1 /*
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  */
16 package com.android.car;
17 
18 import android.annotation.Nullable;
19 import android.annotation.UserIdInt;
20 import android.app.ActivityManager;
21 import android.car.Car;
22 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
23 import android.car.hardware.power.ICarPower;
24 import android.car.hardware.power.ICarPowerStateListener;
25 import android.car.userlib.CarUserManagerHelper;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.pm.UserInfo;
30 import android.content.res.Resources;
31 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
32 import android.os.Build;
33 import android.os.Handler;
34 import android.os.HandlerThread;
35 import android.os.IBinder;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.PowerManager;
39 import android.os.RemoteCallbackList;
40 import android.os.RemoteException;
41 import android.os.SystemClock;
42 import android.os.SystemProperties;
43 import android.os.UserHandle;
44 import android.os.UserManager;
45 import android.util.Log;
46 
47 import com.android.car.am.ContinuousBlankActivity;
48 import com.android.car.hal.PowerHalService;
49 import com.android.car.hal.PowerHalService.PowerState;
50 import com.android.car.systeminterface.SystemInterface;
51 import com.android.car.user.CarUserNoticeService;
52 import com.android.internal.annotations.GuardedBy;
53 import com.android.internal.annotations.VisibleForTesting;
54 
55 import java.io.PrintWriter;
56 import java.util.HashSet;
57 import java.util.LinkedList;
58 import java.util.List;
59 import java.util.Set;
60 import java.util.Timer;
61 import java.util.TimerTask;
62 
63 /**
64  * Power Management service class for cars. Controls the power states and interacts with other
65  * parts of the system to ensure its own state.
66  */
67 public class CarPowerManagementService extends ICarPower.Stub implements
68         CarServiceBase, PowerHalService.PowerEventListener {
69 
70     private final Object mLock = new Object();
71     private final Object mSimulationWaitObject = new Object();
72 
73     private final Context mContext;
74     private final PowerHalService mHal;
75     private final SystemInterface mSystemInterface;
76     // The listeners that complete simply by returning from onStateChanged()
77     private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList();
78     // The listeners that must indicate asynchronous completion by calling finished().
79     private final PowerManagerCallbackList mPowerManagerListenersWithCompletion =
80                           new PowerManagerCallbackList();
81 
82     @GuardedBy("mSimulationWaitObject")
83     private boolean mWakeFromSimulatedSleep;
84     @GuardedBy("mSimulationWaitObject")
85     private boolean mInSimulatedDeepSleepMode;
86 
87     @GuardedBy("mLock")
88     private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>();
89     @GuardedBy("mLock")
90     private CpmsState mCurrentState;
91     @GuardedBy("mLock")
92     private Timer mTimer;
93     @GuardedBy("mLock")
94     private long mProcessingStartTime;
95     @GuardedBy("mLock")
96     private long mLastSleepEntryTime;
97     @GuardedBy("mLock")
98     private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>();
99     @GuardedBy("mLock")
100     private HandlerThread mHandlerThread;
101     @GuardedBy("mLock")
102     private PowerHandler mHandler;
103     @GuardedBy("mLock")
104     private boolean mTimerActive;
105     @GuardedBy("mLock")
106     private int mNextWakeupSec;
107     @GuardedBy("mLock")
108     private boolean mShutdownOnFinish;
109     @GuardedBy("mLock")
110     private boolean mShutdownOnNextSuspend;
111     @GuardedBy("mLock")
112     private boolean mIsBooting = true;
113     @GuardedBy("mLock")
114     private boolean mIsResuming;
115     @GuardedBy("mLock")
116     private boolean mRebootAfterGarageMode;
117     private final boolean mDisableUserSwitchDuringResume;
118     private final CarUserManagerHelper mCarUserManagerHelper;
119     private final UserManager mUserManager;    // CarUserManagerHelper is deprecated...
120     private final String mNewGuestName;
121 
122     // TODO:  Make this OEM configurable.
123     private static final int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
124     private static final int SHUTDOWN_EXTEND_MAX_MS = 5000;
125 
126     // maxGarageModeRunningDurationInSecs should be equal or greater than this. 15 min for now.
127     private static final int MIN_MAX_GARAGE_MODE_DURATION_MS = 15 * 60 * 1000;
128 
129     private static int sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
130 
131     // in secs
132     private static final String PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE =
133             "android.car.garagemodeduration";
134 
135     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
onCallbackDied(ICarPowerStateListener listener)141         public void onCallbackDied(ICarPowerStateListener listener) {
142             Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder());
143             CarPowerManagementService.this.doUnregisterListener(listener);
144         }
145     }
146 
CarPowerManagementService(Context context, PowerHalService powerHal, SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper)147     public CarPowerManagementService(Context context, PowerHalService powerHal,
148             SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper) {
149         this(context, context.getResources(), powerHal, systemInterface, carUserManagerHelper,
150                 UserManager.get(context), context.getString(R.string.default_guest_name));
151     }
152 
153     @VisibleForTesting
CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal, SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper, UserManager userManager, String newGuestName)154     CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal,
155             SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper,
156             UserManager userManager, String newGuestName) {
157         mContext = context;
158         mHal = powerHal;
159         mSystemInterface = systemInterface;
160         mCarUserManagerHelper = carUserManagerHelper;
161         mUserManager = userManager;
162         mDisableUserSwitchDuringResume = resources
163                 .getBoolean(R.bool.config_disableUserSwitchDuringResume);
164         sShutdownPrepareTimeMs = resources.getInteger(
165                 R.integer.maxGarageModeRunningDurationInSecs) * 1000;
166         if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) {
167             Log.w(CarLog.TAG_POWER,
168                     "maxGarageModeRunningDurationInSecs smaller than minimum required, resource:"
169                     + sShutdownPrepareTimeMs + "(ms) while should exceed:"
170                     +  MIN_MAX_GARAGE_MODE_DURATION_MS + "(ms), Ignore resource.");
171             sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
172         }
173         mNewGuestName = newGuestName;
174     }
175 
176     @VisibleForTesting
setShutdownPrepareTimeout(int timeoutMs)177     protected static void setShutdownPrepareTimeout(int timeoutMs) {
178         // Override the timeout to keep testing time short
179         if (timeoutMs < SHUTDOWN_EXTEND_MAX_MS) {
180             sShutdownPrepareTimeMs = SHUTDOWN_EXTEND_MAX_MS;
181         } else {
182             sShutdownPrepareTimeMs = timeoutMs;
183         }
184     }
185 
186     @VisibleForTesting
getHandlerThread()187     protected HandlerThread getHandlerThread() {
188         synchronized (mLock) {
189             return mHandlerThread;
190         }
191     }
192 
193     @Override
init()194     public void init() {
195         synchronized (mLock) {
196             mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
197             mHandlerThread.start();
198             mHandler = new PowerHandler(mHandlerThread.getLooper());
199         }
200 
201         mHal.setListener(this);
202         if (mHal.isPowerStateSupported()) {
203             // Initialize CPMS in WAIT_FOR_VHAL state
204             onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, CarPowerStateListener.WAIT_FOR_VHAL);
205         } else {
206             Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
207             onApPowerStateChange(CpmsState.ON, CarPowerStateListener.ON);
208         }
209         mSystemInterface.startDisplayStateMonitoring(this);
210     }
211 
212     @Override
release()213     public void release() {
214         HandlerThread handlerThread;
215         synchronized (mLock) {
216             releaseTimerLocked();
217             mCurrentState = null;
218             mHandler.cancelAll();
219             handlerThread = mHandlerThread;
220             mListenersWeAreWaitingFor.clear();
221         }
222         handlerThread.quitSafely();
223         try {
224             handlerThread.join(1000);
225         } catch (InterruptedException e) {
226             Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
227         }
228         mSystemInterface.stopDisplayStateMonitoring();
229         mPowerManagerListeners.kill();
230         mSystemInterface.releaseAllWakeLocks();
231     }
232 
233     @Override
dump(PrintWriter writer)234     public void dump(PrintWriter writer) {
235         writer.println("*PowerManagementService*");
236         writer.print("mCurrentState:" + mCurrentState);
237         writer.print(",mProcessingStartTime:" + mProcessingStartTime);
238         writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime);
239         writer.print(",mNextWakeupSec:" + mNextWakeupSec);
240         writer.print(",mShutdownOnNextSuspend:" + mShutdownOnNextSuspend);
241         writer.print(",mShutdownOnFinish:" + mShutdownOnFinish);
242         writer.print(",sShutdownPrepareTimeMs:" + sShutdownPrepareTimeMs);
243         writer.print(",mDisableUserSwitchDuringResume:" + mDisableUserSwitchDuringResume);
244         writer.println(",mRebootAfterGarageMode:" + mRebootAfterGarageMode);
245         writer.print("mNewGuestName: "); writer.println(mNewGuestName);
246     }
247 
248     @Override
onApPowerStateChange(PowerState state)249     public void onApPowerStateChange(PowerState state) {
250         PowerHandler handler;
251         synchronized (mLock) {
252             mPendingPowerStates.addFirst(new CpmsState(state));
253             handler = mHandler;
254         }
255         handler.handlePowerStateChange();
256     }
257 
258     @VisibleForTesting
setStateForTesting(boolean isBooting, boolean isResuming)259     void setStateForTesting(boolean isBooting, boolean isResuming) {
260         synchronized (mLock) {
261             Log.d(CarLog.TAG_POWER, "setStateForTesting():"
262                     + " booting(" + mIsBooting + ">" + isBooting + ")"
263                     + " resuming(" + mIsResuming + ">" + isResuming + ")");
264             mIsBooting = isBooting;
265             mIsResuming = isResuming;
266         }
267     }
268 
269     /**
270      * Initiate state change from CPMS directly.
271      */
onApPowerStateChange(int apState, int carPowerStateListenerState)272     private void onApPowerStateChange(int apState, int carPowerStateListenerState) {
273         CpmsState newState = new CpmsState(apState, carPowerStateListenerState);
274         PowerHandler handler;
275         synchronized (mLock) {
276             mPendingPowerStates.addFirst(newState);
277             handler = mHandler;
278         }
279         handler.handlePowerStateChange();
280     }
281 
doHandlePowerStateChange()282     private void doHandlePowerStateChange() {
283         CpmsState state;
284         PowerHandler handler;
285         synchronized (mLock) {
286             state = mPendingPowerStates.peekFirst();
287             mPendingPowerStates.clear();
288             if (state == null) {
289                 return;
290             }
291             Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.name());
292             if (!needPowerStateChangeLocked(state)) {
293                 Log.d(CarLog.TAG_POWER, "doHandlePowerStateChange no change needed");
294                 return;
295             }
296             // now real power change happens. Whatever was queued before should be all cancelled.
297             releaseTimerLocked();
298             handler = mHandler;
299         }
300         handler.cancelProcessingComplete();
301         Log.i(CarLog.TAG_POWER, "setCurrentState " + state.toString());
302         CarStatsLog.logPowerState(state.mState);
303         mCurrentState = state;
304         switch (state.mState) {
305             case CpmsState.WAIT_FOR_VHAL:
306                 handleWaitForVhal(state);
307                 break;
308             case CpmsState.ON:
309                 handleOn();
310                 break;
311             case CpmsState.SHUTDOWN_PREPARE:
312                 handleShutdownPrepare(state);
313                 break;
314             case CpmsState.SIMULATE_SLEEP:
315                 simulateShutdownPrepare();
316                 break;
317             case CpmsState.WAIT_FOR_FINISH:
318                 handleWaitForFinish(state);
319                 break;
320             case CpmsState.SUSPEND:
321                 // Received FINISH from VHAL
322                 handleFinish();
323                 break;
324             default:
325                 // Illegal state
326                 // TODO:  Throw exception?
327                 break;
328         }
329     }
330 
handleWaitForVhal(CpmsState state)331     private void handleWaitForVhal(CpmsState state) {
332         int carPowerStateListenerState = state.mCarPowerStateListenerState;
333         sendPowerManagerEvent(carPowerStateListenerState);
334         // Inspect CarPowerStateListenerState to decide which message to send via VHAL
335         switch (carPowerStateListenerState) {
336             case CarPowerStateListener.WAIT_FOR_VHAL:
337                 mHal.sendWaitForVhal();
338                 break;
339             case CarPowerStateListener.SHUTDOWN_CANCELLED:
340                 mShutdownOnNextSuspend = false; // This cancels the "NextSuspend"
341                 mHal.sendShutdownCancel();
342                 break;
343             case CarPowerStateListener.SUSPEND_EXIT:
344                 mHal.sendSleepExit();
345                 break;
346         }
347     }
348 
updateCarUserNoticeServiceIfNecessary()349     private void updateCarUserNoticeServiceIfNecessary() {
350         try {
351             int currentUserId = ActivityManager.getCurrentUser();
352             UserInfo currentUserInfo = mUserManager.getUserInfo(currentUserId);
353             CarUserNoticeService carUserNoticeService =
354                     CarLocalServices.getService(CarUserNoticeService.class);
355             if (currentUserInfo != null && currentUserInfo.isGuest()
356                     && carUserNoticeService != null) {
357                 Log.i(CarLog.TAG_POWER,
358                         "Car user notice service will ignore all messages before user switch.");
359                 Intent intent = new Intent();
360                 intent.setComponent(new ComponentName(mContext.getPackageName(),
361                         ContinuousBlankActivity.class.getName()));
362                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
363                 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
364                 carUserNoticeService.ignoreUserNotice(currentUserId);
365             }
366         } catch (Exception e) {
367             Log.w(CarLog.TAG_POWER, "Cannot ignore user notice for current user", e);
368         }
369     }
370 
handleOn()371     private void handleOn() {
372         // If current user is a Guest User, we want to inform CarUserNoticeService not to show
373         // notice for current user, and show user notice only for the target user.
374         updateCarUserNoticeServiceIfNecessary();
375 
376         // Some OEMs have their own user-switching logic, which may not be coordinated with this
377         // code. To avoid contention, we don't switch users when we coming alive. The OEM's code
378         // should do the switch.
379         boolean allowUserSwitch = true;
380         synchronized (mLock) {
381             if (mIsBooting) {
382                 // The system is booting, so don't switch users
383                 allowUserSwitch = false;
384                 mIsBooting = false;
385                 mIsResuming = false;
386                 Log.i(CarLog.TAG_POWER, "User switch disallowed while booting");
387             } else {
388                 // The system is resuming after a suspension. Optionally disable user switching.
389                 allowUserSwitch = !mDisableUserSwitchDuringResume;
390                 mIsBooting = false;
391                 mIsResuming = false;
392                 if (!allowUserSwitch) {
393                     Log.i(CarLog.TAG_POWER, "User switch disallowed while resuming");
394                 }
395             }
396         }
397 
398         mSystemInterface.setDisplayState(true);
399         sendPowerManagerEvent(CarPowerStateListener.ON);
400         mHal.sendOn();
401 
402         try {
403             switchUserOnResumeIfNecessary(allowUserSwitch);
404         } catch (Exception e) {
405             Log.e(CarLog.TAG_POWER, "Could not switch user on resume: " + e);
406         }
407     }
408 
switchUserOnResumeIfNecessary(boolean allowSwitching)409     private void switchUserOnResumeIfNecessary(boolean allowSwitching) {
410         int targetUserId = mCarUserManagerHelper.getInitialUser();
411         if (targetUserId == UserHandle.USER_SYSTEM) {
412             // API explicitly say it doesn't return USER_SYSTEM
413             Log.wtf(CarLog.TAG_POWER, "getInitialUser() returned system user");
414             return;
415         }
416         int currentUserId = ActivityManager.getCurrentUser();
417         UserInfo targetUserInfo = mUserManager.getUserInfo(targetUserId);
418         boolean isTargetPersistent = !targetUserInfo.isEphemeral();
419         boolean isTargetGuest = targetUserInfo.isGuest();
420         Log.d(CarLog.TAG_POWER, "getTargetUserId(): current=" + currentUserId
421                 + ", target=" + targetUserInfo.toFullString()
422                 + ", isTargetPersistent=" + isTargetPersistent + ", isTargetGuest=" + isTargetGuest
423                 + ", allowSwitching: " + allowSwitching);
424 
425         if (isTargetPersistent && !isTargetGuest) {
426             if (!allowSwitching) {
427                 Log.d(CarLog.TAG_POWER, "Not switching to " + targetUserId
428                         + " because it's not allowed");
429                 return;
430             }
431             if (currentUserId == targetUserId) {
432                 Log.v(CarLog.TAG_POWER, "no need to switch to (same user) " + currentUserId);
433                 return;
434             }
435             // All good - switch to the requested user
436             switchToUser(currentUserId, targetUserId, /* reason= */ null);
437             return;
438         }
439 
440         if (!isTargetGuest) {
441             // Shouldn't happen (unless OEM is explicitly creating ephemeral users, which
442             // doesn't make much sense), but it doesn't hurt to log...
443             Log.w(CarLog.TAG_POWER, "target user is ephemeral but not a guest: "
444                     + targetUserInfo.toFullString());
445             if (allowSwitching) {
446                 switchToUser(currentUserId, targetUserId, /* reason= */ null);
447             }
448             return;
449         } else if (isTargetPersistent) {
450             // TODO(b/146380030): decide whether we should delete it or not
451             // Shouldn't happen neither, but it's not a big deal (guest will be replaced below
452             // anyway), but it's worth logging as well...
453             Log.w(CarLog.TAG_POWER, "target user is a non-ephemeral guest: "
454                     + targetUserInfo.toFullString());
455         }
456 
457         // At this point, target user is a guest - we cannot resume into an ephemeral guest for
458         // privacy reasons, so we need to create a new guest and switch to it (even if the OEM
459         // doesn't allow switching)
460 
461 
462         boolean marked = mUserManager.markGuestForDeletion(targetUserId);
463         if (!marked) {
464             Log.w(CarLog.TAG_POWER, "Could not mark guest user " + targetUserId + " for deletion");
465             return;
466         }
467 
468         UserInfo newGuest = mUserManager.createGuest(mContext, mNewGuestName);
469 
470         if (newGuest != null) {
471             switchToUser(currentUserId, newGuest.id, "Created new guest");
472             Log.d(CarLog.TAG_POWER, "Removing previous guest " + targetUserId);
473             mUserManager.removeUser(targetUserId);
474         } else {
475             Log.wtf(CarLog.TAG_POWER, "Could not create new guest");
476             // TODO(b/146380030): decide whether we should switch to SYSTEM
477         }
478     }
479 
switchToUser(@serIdInt int fromUser, @UserIdInt int toUser, @Nullable String reason)480     private void switchToUser(@UserIdInt int fromUser, @UserIdInt int toUser,
481             @Nullable String reason) {
482         StringBuilder message = new StringBuilder();
483         if (reason == null) {
484             message.append("Desired user changed");
485         } else {
486             message.append(reason);
487         }
488         message.append(", switching from ").append(fromUser).append(" to ").append(toUser);
489         Log.i(CarLog.TAG_POWER, message.toString());
490         mCarUserManagerHelper.switchToUserId(toUser);
491     }
492 
getFirstSwitchableUser()493     private int getFirstSwitchableUser() {
494         List<UserInfo> allUsers = mUserManager.getUsers();
495         for (UserInfo user : allUsers) {
496             if (user.id != UserHandle.USER_SYSTEM) {
497                 return user.id;
498             }
499         }
500         Log.wtf(CarLog.TAG_POWER, "no switchable user: " + allUsers);
501         return UserHandle.USER_NULL;
502     }
503 
handleShutdownPrepare(CpmsState newState)504     private void handleShutdownPrepare(CpmsState newState) {
505         mSystemInterface.setDisplayState(false);
506         // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
507         synchronized (mLock) {
508             mShutdownOnFinish = mShutdownOnNextSuspend
509                     || !mHal.isDeepSleepAllowed()
510                     || !mSystemInterface.isSystemSupportingDeepSleep()
511                     || !newState.mCanSleep;
512         }
513         if (newState.mCanPostpone) {
514             Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
515             sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
516             mHal.sendShutdownPrepare();
517             doHandlePreprocessing();
518         } else {
519             Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
520             synchronized (mLock) {
521                 releaseTimerLocked();
522             }
523             // Notify hal that we are shutting down and since it is immediate, don't schedule next
524             // wake up
525             mHal.sendShutdownStart(0);
526             // shutdown HU
527             mSystemInterface.shutdown();
528         }
529     }
530 
531     // Simulate system shutdown to Deep Sleep
simulateShutdownPrepare()532     private void simulateShutdownPrepare() {
533         mSystemInterface.setDisplayState(false);
534         Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
535         sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
536         mHal.sendShutdownPrepare();
537         doHandlePreprocessing();
538     }
539 
handleWaitForFinish(CpmsState state)540     private void handleWaitForFinish(CpmsState state) {
541         sendPowerManagerEvent(state.mCarPowerStateListenerState);
542         int wakeupSec;
543         synchronized (mLock) {
544             wakeupSec = mNextWakeupSec;
545         }
546         switch (state.mCarPowerStateListenerState) {
547             case CarPowerStateListener.SUSPEND_ENTER:
548                 mHal.sendSleepEntry(wakeupSec);
549                 break;
550             case CarPowerStateListener.SHUTDOWN_ENTER:
551                 mHal.sendShutdownStart(wakeupSec);
552                 break;
553         }
554     }
555 
handleFinish()556     private void handleFinish() {
557         boolean simulatedMode;
558         synchronized (mSimulationWaitObject) {
559             simulatedMode = mInSimulatedDeepSleepMode;
560         }
561         boolean mustShutDown;
562         boolean forceReboot;
563         synchronized (mLock) {
564             mustShutDown = mShutdownOnFinish && !simulatedMode;
565             forceReboot = mRebootAfterGarageMode;
566             mRebootAfterGarageMode = false;
567         }
568         if (forceReboot) {
569             PowerManager powerManager = mContext.getSystemService(PowerManager.class);
570             if (powerManager == null) {
571                 Log.wtf(CarLog.TAG_POWER, "No PowerManager. Cannot reboot.");
572             } else {
573                 Log.i(CarLog.TAG_POWER, "GarageMode has completed. Forcing reboot.");
574                 powerManager.reboot("GarageModeReboot");
575                 throw new AssertionError("Should not return from PowerManager.reboot()");
576             }
577         }
578         if (mustShutDown) {
579             // shutdown HU
580             mSystemInterface.shutdown();
581         } else {
582             doHandleDeepSleep(simulatedMode);
583         }
584         mShutdownOnNextSuspend = false;
585     }
586 
587     @GuardedBy("mLock")
releaseTimerLocked()588     private void releaseTimerLocked() {
589         if (mTimer != null) {
590             mTimer.cancel();
591         }
592         mTimer = null;
593         mTimerActive = false;
594     }
595 
doHandlePreprocessing()596     private void doHandlePreprocessing() {
597         int pollingCount = (sShutdownPrepareTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
598         if (Build.IS_USERDEBUG || Build.IS_ENG) {
599             int shutdownPrepareTimeOverrideInSecs =
600                     SystemProperties.getInt(PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE, -1);
601             if (shutdownPrepareTimeOverrideInSecs >= 0) {
602                 pollingCount =
603                         (shutdownPrepareTimeOverrideInSecs * 1000 / SHUTDOWN_POLLING_INTERVAL_MS)
604                                 + 1;
605                 Log.i(CarLog.TAG_POWER,
606                         "Garage mode duration overridden secs:"
607                                 + shutdownPrepareTimeOverrideInSecs);
608             }
609         }
610         Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: "
611                 + sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
612         synchronized (mLock) {
613             mProcessingStartTime = SystemClock.elapsedRealtime();
614             releaseTimerLocked();
615             mTimer = new Timer();
616             mTimerActive = true;
617             mTimer.scheduleAtFixedRate(
618                     new ShutdownProcessingTimerTask(pollingCount),
619                     0 /*delay*/,
620                     SHUTDOWN_POLLING_INTERVAL_MS);
621         }
622     }
623 
sendPowerManagerEvent(int newState)624     private void sendPowerManagerEvent(int newState) {
625         // Broadcast to the listeners that do not signal completion
626         notifyListeners(mPowerManagerListeners, newState);
627 
628         // SHUTDOWN_PREPARE is the only state where we need
629         // to maintain callbacks from listener components.
630         boolean allowCompletion = (newState == CarPowerStateListener.SHUTDOWN_PREPARE);
631 
632         // Fully populate mListenersWeAreWaitingFor before calling any onStateChanged()
633         // for the listeners that signal completion.
634         // Otherwise, if the first listener calls finish() synchronously, we will
635         // see the list go empty and we will think that we are done.
636         boolean haveSomeCompleters = false;
637         PowerManagerCallbackList completingListeners = new PowerManagerCallbackList();
638         synchronized (mLock) {
639             mListenersWeAreWaitingFor.clear();
640             int idx = mPowerManagerListenersWithCompletion.beginBroadcast();
641             while (idx-- > 0) {
642                 ICarPowerStateListener listener =
643                         mPowerManagerListenersWithCompletion.getBroadcastItem(idx);
644                 completingListeners.register(listener);
645                 if (allowCompletion) {
646                     mListenersWeAreWaitingFor.add(listener.asBinder());
647                     haveSomeCompleters = true;
648                 }
649             }
650             mPowerManagerListenersWithCompletion.finishBroadcast();
651         }
652         // Broadcast to the listeners that DO signal completion
653         notifyListeners(completingListeners, newState);
654 
655         if (allowCompletion && !haveSomeCompleters) {
656             // No jobs need to signal completion. So we are now complete.
657             signalComplete();
658         }
659     }
660 
notifyListeners(PowerManagerCallbackList listenerList, int newState)661     private void notifyListeners(PowerManagerCallbackList listenerList, int newState) {
662         int idx = listenerList.beginBroadcast();
663         while (idx-- > 0) {
664             ICarPowerStateListener listener = listenerList.getBroadcastItem(idx);
665             try {
666                 listener.onStateChanged(newState);
667             } catch (RemoteException e) {
668                 // It's likely the connection snapped. Let binder death handle the situation.
669                 Log.e(CarLog.TAG_POWER, "onStateChanged() call failed", e);
670             }
671         }
672         listenerList.finishBroadcast();
673     }
674 
doHandleDeepSleep(boolean simulatedMode)675     private void doHandleDeepSleep(boolean simulatedMode) {
676         // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
677         // enterDeepSleep should force sleep entry even if wake lock is kept.
678         mSystemInterface.switchToPartialWakeLock();
679         PowerHandler handler;
680         synchronized (mLock) {
681             handler = mHandler;
682         }
683         handler.cancelProcessingComplete();
684         synchronized (mLock) {
685             mLastSleepEntryTime = SystemClock.elapsedRealtime();
686         }
687         int nextListenerState;
688         if (simulatedMode) {
689             simulateSleepByWaiting();
690             nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
691         } else {
692             boolean sleepSucceeded = mSystemInterface.enterDeepSleep();
693             if (!sleepSucceeded) {
694                 // Suspend failed! VHAL should transition CPMS to shutdown.
695                 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down.");
696                 mSystemInterface.shutdown();
697                 return;
698             }
699             nextListenerState = CarPowerStateListener.SUSPEND_EXIT;
700         }
701         // On resume, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
702         synchronized (mLock) {
703             mIsResuming = true;
704             mNextWakeupSec = 0;
705         }
706         Log.i(CarLog.TAG_POWER, "Resuming after suspending");
707         mSystemInterface.refreshDisplayBrightness();
708         onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState);
709     }
710 
needPowerStateChangeLocked(CpmsState newState)711     private boolean needPowerStateChangeLocked(CpmsState newState) {
712         if (newState == null) {
713             return false;
714         } else if (mCurrentState == null) {
715             return true;
716         } else if (mCurrentState.equals(newState)) {
717             return false;
718         }
719 
720         // The following switch/case enforces the allowed state transitions.
721         switch (mCurrentState.mState) {
722             case CpmsState.WAIT_FOR_VHAL:
723                 return (newState.mState == CpmsState.ON)
724                     || (newState.mState == CpmsState.SHUTDOWN_PREPARE);
725             case CpmsState.SUSPEND:
726                 return newState.mState == CpmsState.WAIT_FOR_VHAL;
727             case CpmsState.ON:
728                 return (newState.mState == CpmsState.SHUTDOWN_PREPARE)
729                     || (newState.mState == CpmsState.SIMULATE_SLEEP);
730             case CpmsState.SHUTDOWN_PREPARE:
731                 // If VHAL sends SHUTDOWN_IMMEDIATELY while in SHUTDOWN_PREPARE state, do it.
732                 return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone)
733                     || (newState.mState == CpmsState.WAIT_FOR_FINISH)
734                     || (newState.mState == CpmsState.WAIT_FOR_VHAL);
735             case CpmsState.SIMULATE_SLEEP:
736                 return true;
737             case CpmsState.WAIT_FOR_FINISH:
738                 return newState.mState == CpmsState.SUSPEND;
739             default:
740                 Log.e(CarLog.TAG_POWER, "Unhandled state transition:  currentState="
741                         + mCurrentState.name() + ", newState=" + newState.name());
742                 return false;
743         }
744     }
745 
doHandleProcessingComplete()746     private void doHandleProcessingComplete() {
747         int listenerState;
748         synchronized (mLock) {
749             releaseTimerLocked();
750             if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) {
751                 // entered sleep after processing start. So this could be duplicate request.
752                 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
753                 return;
754             }
755             listenerState = mShutdownOnFinish
756                     ? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER;
757         }
758         onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState);
759     }
760 
761     @Override
onDisplayBrightnessChange(int brightness)762     public void onDisplayBrightnessChange(int brightness) {
763         PowerHandler handler;
764         synchronized (mLock) {
765             handler = mHandler;
766         }
767         handler.handleDisplayBrightnessChange(brightness);
768     }
769 
doHandleDisplayBrightnessChange(int brightness)770     private void doHandleDisplayBrightnessChange(int brightness) {
771         mSystemInterface.setDisplayBrightness(brightness);
772     }
773 
doHandleMainDisplayStateChange(boolean on)774     private void doHandleMainDisplayStateChange(boolean on) {
775         Log.w(CarLog.TAG_POWER, "Unimplemented:  doHandleMainDisplayStateChange() - on = " + on);
776     }
777 
handleMainDisplayChanged(boolean on)778     public void handleMainDisplayChanged(boolean on) {
779         PowerHandler handler;
780         synchronized (mLock) {
781             handler = mHandler;
782         }
783         handler.handleMainDisplayStateChange(on);
784     }
785 
786     /**
787      * Send display brightness to VHAL.
788      * @param brightness value 0-100%
789      */
sendDisplayBrightness(int brightness)790     public void sendDisplayBrightness(int brightness) {
791         mHal.sendDisplayBrightness(brightness);
792     }
793 
794     /**
795      * Get the PowerHandler that we use to change power states
796      */
getHandler()797     public Handler getHandler() {
798         synchronized (mLock) {
799             return mHandler;
800         }
801     }
802 
803     // Binder interface for general use.
804     // The listener is not required (or allowed) to call finished().
805     @Override
registerListener(ICarPowerStateListener listener)806     public void registerListener(ICarPowerStateListener listener) {
807         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
808         mPowerManagerListeners.register(listener);
809     }
810 
811     // Binder interface for Car services only.
812     // After the listener completes its processing, it must call finished().
813     @Override
registerListenerWithCompletion(ICarPowerStateListener listener)814     public void registerListenerWithCompletion(ICarPowerStateListener listener) {
815         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
816         ICarImpl.assertCallingFromSystemProcessOrSelf();
817 
818         mPowerManagerListenersWithCompletion.register(listener);
819         // TODO: Need to send current state to newly registered listener? If so, need to handle
820         //       completion for SHUTDOWN_PREPARE state
821     }
822 
823     @Override
unregisterListener(ICarPowerStateListener listener)824     public void unregisterListener(ICarPowerStateListener listener) {
825         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
826         doUnregisterListener(listener);
827     }
828 
doUnregisterListener(ICarPowerStateListener listener)829     private void doUnregisterListener(ICarPowerStateListener listener) {
830         mPowerManagerListeners.unregister(listener);
831         boolean found = mPowerManagerListenersWithCompletion.unregister(listener);
832         if (found) {
833             // Remove this from the completion list (if it's there)
834             finishedImpl(listener.asBinder());
835         }
836     }
837 
838     @Override
requestShutdownOnNextSuspend()839     public void requestShutdownOnNextSuspend() {
840         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
841         synchronized (mLock) {
842             mShutdownOnNextSuspend = true;
843         }
844     }
845 
846     @Override
finished(ICarPowerStateListener listener)847     public void finished(ICarPowerStateListener listener) {
848         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
849         ICarImpl.assertCallingFromSystemProcessOrSelf();
850         finishedImpl(listener.asBinder());
851     }
852 
853     @Override
scheduleNextWakeupTime(int seconds)854     public void scheduleNextWakeupTime(int seconds) {
855         if (seconds < 0) {
856             Log.w(CarLog.TAG_POWER, "Next wake up time is negative. Ignoring!");
857             return;
858         }
859         boolean timedWakeupAllowed = mHal.isTimedWakeupAllowed();
860         synchronized (mLock) {
861             if (!timedWakeupAllowed) {
862                 Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping");
863                 mNextWakeupSec = 0;
864                 return;
865             }
866             if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) {
867                 // The new value is sooner than the old value. Take the new value.
868                 mNextWakeupSec = seconds;
869             } else {
870                 Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
871                         + "scheduled time");
872             }
873         }
874     }
875 
finishedImpl(IBinder binder)876     private void finishedImpl(IBinder binder) {
877         boolean allAreComplete = false;
878         synchronized (mLock) {
879             boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder);
880             allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty();
881         }
882         if (allAreComplete) {
883             signalComplete();
884         }
885     }
886 
signalComplete()887     private void signalComplete() {
888         if (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE
889                 || mCurrentState.mState == CpmsState.SIMULATE_SLEEP) {
890             PowerHandler powerHandler;
891             // All apps are ready to shutdown/suspend.
892             synchronized (mLock) {
893                 if (!mShutdownOnFinish) {
894                     if (mLastSleepEntryTime > mProcessingStartTime
895                             && mLastSleepEntryTime < SystemClock.elapsedRealtime()) {
896                         Log.i(CarLog.TAG_POWER, "signalComplete: Already slept!");
897                         return;
898                     }
899                 }
900                 powerHandler = mHandler;
901             }
902             Log.i(CarLog.TAG_POWER, "Apps are finished, call handleProcessingComplete()");
903             powerHandler.handleProcessingComplete();
904         }
905     }
906 
907     private class PowerHandler extends Handler {
908         private final int MSG_POWER_STATE_CHANGE = 0;
909         private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
910         private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
911         private final int MSG_PROCESSING_COMPLETE = 3;
912 
913         // Do not handle this immediately but with some delay as there can be a race between
914         // display off due to rear view camera and delivery to here.
915         private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
916 
PowerHandler(Looper looper)917         private PowerHandler(Looper looper) {
918             super(looper);
919         }
920 
handlePowerStateChange()921         private void handlePowerStateChange() {
922             Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
923             sendMessage(msg);
924         }
925 
handleDisplayBrightnessChange(int brightness)926         private void handleDisplayBrightnessChange(int brightness) {
927             Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
928             sendMessage(msg);
929         }
930 
handleMainDisplayStateChange(boolean on)931         private void handleMainDisplayStateChange(boolean on) {
932             removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
933             Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
934             sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
935         }
936 
handleProcessingComplete()937         private void handleProcessingComplete() {
938             removeMessages(MSG_PROCESSING_COMPLETE);
939             Message msg = obtainMessage(MSG_PROCESSING_COMPLETE);
940             sendMessage(msg);
941         }
942 
cancelProcessingComplete()943         private void cancelProcessingComplete() {
944             removeMessages(MSG_PROCESSING_COMPLETE);
945         }
946 
cancelAll()947         private void cancelAll() {
948             removeMessages(MSG_POWER_STATE_CHANGE);
949             removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
950             removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
951             removeMessages(MSG_PROCESSING_COMPLETE);
952         }
953 
954         @Override
handleMessage(Message msg)955         public void handleMessage(Message msg) {
956             switch (msg.what) {
957                 case MSG_POWER_STATE_CHANGE:
958                     doHandlePowerStateChange();
959                     break;
960                 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
961                     doHandleDisplayBrightnessChange(msg.arg1);
962                     break;
963                 case MSG_MAIN_DISPLAY_STATE_CHANGE:
964                     doHandleMainDisplayStateChange((Boolean) msg.obj);
965                     break;
966                 case MSG_PROCESSING_COMPLETE:
967                     doHandleProcessingComplete();
968                     break;
969             }
970         }
971     }
972 
973     private class ShutdownProcessingTimerTask extends TimerTask {
974         private final int mExpirationCount;
975         private int mCurrentCount;
976 
ShutdownProcessingTimerTask(int expirationCount)977         private ShutdownProcessingTimerTask(int expirationCount) {
978             mExpirationCount = expirationCount;
979             mCurrentCount = 0;
980         }
981 
982         @Override
run()983         public void run() {
984             synchronized (mLock) {
985                 if (!mTimerActive) {
986                     // Ignore timer expiration since we got cancelled
987                     return;
988                 }
989                 mCurrentCount++;
990                 if (mCurrentCount > mExpirationCount) {
991                     PowerHandler handler;
992                     releaseTimerLocked();
993                     handler = mHandler;
994                     handler.handleProcessingComplete();
995                 } else {
996                     mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
997                 }
998             }
999         }
1000     }
1001 
1002     private static class CpmsState {
1003         // NOTE: When modifying states below, make sure to update CarPowerStateChanged.State in
1004         //   frameworks/base/cmds/statsd/src/atoms.proto also.
1005         public static final int WAIT_FOR_VHAL = 0;
1006         public static final int ON = 1;
1007         public static final int SHUTDOWN_PREPARE = 2;
1008         public static final int WAIT_FOR_FINISH = 3;
1009         public static final int SUSPEND = 4;
1010         public static final int SIMULATE_SLEEP = 5;
1011 
1012         /* Config values from AP_POWER_STATE_REQ */
1013         public final boolean mCanPostpone;
1014         public final boolean mCanSleep;
1015         /* Message sent to CarPowerStateListener in response to this state */
1016         public final int mCarPowerStateListenerState;
1017         /* One of the above state variables */
1018         public final int mState;
1019 
1020         /**
1021           * This constructor takes a PowerHalService.PowerState object and creates the corresponding
1022           * CPMS state from it.
1023           */
CpmsState(PowerState halPowerState)1024         CpmsState(PowerState halPowerState) {
1025             switch (halPowerState.mState) {
1026                 case VehicleApPowerStateReq.ON:
1027                     this.mCanPostpone = false;
1028                     this.mCanSleep = false;
1029                     this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(ON);
1030                     this.mState = ON;
1031                     break;
1032                 case VehicleApPowerStateReq.SHUTDOWN_PREPARE:
1033                     this.mCanPostpone = halPowerState.canPostponeShutdown();
1034                     this.mCanSleep = halPowerState.canEnterDeepSleep();
1035                     this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(
1036                             SHUTDOWN_PREPARE);
1037                     this.mState = SHUTDOWN_PREPARE;
1038                     break;
1039                 case VehicleApPowerStateReq.CANCEL_SHUTDOWN:
1040                     this.mCanPostpone = false;
1041                     this.mCanSleep = false;
1042                     this.mCarPowerStateListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
1043                     this.mState = WAIT_FOR_VHAL;
1044                     break;
1045                 case VehicleApPowerStateReq.FINISHED:
1046                     this.mCanPostpone = false;
1047                     this.mCanSleep = false;
1048                     this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(SUSPEND);
1049                     this.mState = SUSPEND;
1050                     break;
1051                 default:
1052                     // Illegal state from PowerState.  Throw an exception?
1053                     this.mCanPostpone = false;
1054                     this.mCanSleep = false;
1055                     this.mCarPowerStateListenerState = 0;
1056                     this.mState = 0;
1057                     break;
1058             }
1059         }
1060 
CpmsState(int state)1061         CpmsState(int state) {
1062             this(state, cpmsStateToPowerStateListenerState(state));
1063         }
1064 
CpmsState(int state, int carPowerStateListenerState)1065         CpmsState(int state, int carPowerStateListenerState) {
1066             this.mCanPostpone = (state == SIMULATE_SLEEP);
1067             this.mCanSleep = (state == SIMULATE_SLEEP);
1068             this.mCarPowerStateListenerState = carPowerStateListenerState;
1069             this.mState = state;
1070         }
1071 
name()1072         public String name() {
1073             String baseName;
1074             switch(mState) {
1075                 case WAIT_FOR_VHAL:     baseName = "WAIT_FOR_VHAL";    break;
1076                 case ON:                baseName = "ON";               break;
1077                 case SHUTDOWN_PREPARE:  baseName = "SHUTDOWN_PREPARE"; break;
1078                 case WAIT_FOR_FINISH:   baseName = "WAIT_FOR_FINISH";  break;
1079                 case SUSPEND:           baseName = "SUSPEND";          break;
1080                 case SIMULATE_SLEEP:    baseName = "SIMULATE_SLEEP";   break;
1081                 default:                baseName = "<unknown>";        break;
1082             }
1083             return baseName + "(" + mState + ")";
1084         }
1085 
cpmsStateToPowerStateListenerState(int state)1086         private static int cpmsStateToPowerStateListenerState(int state) {
1087             int powerStateListenerState = 0;
1088 
1089             // Set the CarPowerStateListenerState based on current state
1090             switch (state) {
1091                 case ON:
1092                     powerStateListenerState = CarPowerStateListener.ON;
1093                     break;
1094                 case SHUTDOWN_PREPARE:
1095                     powerStateListenerState = CarPowerStateListener.SHUTDOWN_PREPARE;
1096                     break;
1097                 case SUSPEND:
1098                     powerStateListenerState = CarPowerStateListener.SUSPEND_ENTER;
1099                     break;
1100                 case WAIT_FOR_VHAL:
1101                 case WAIT_FOR_FINISH:
1102                 default:
1103                     // Illegal state for this constructor.  Throw an exception?
1104                     break;
1105             }
1106             return powerStateListenerState;
1107         }
1108 
1109         @Override
equals(Object o)1110         public boolean equals(Object o) {
1111             if (this == o) {
1112                 return true;
1113             }
1114             if (!(o instanceof CpmsState)) {
1115                 return false;
1116             }
1117             CpmsState that = (CpmsState) o;
1118             return this.mState == that.mState
1119                     && this.mCanSleep == that.mCanSleep
1120                     && this.mCanPostpone == that.mCanPostpone
1121                     && this.mCarPowerStateListenerState == that.mCarPowerStateListenerState;
1122         }
1123 
1124         @Override
toString()1125         public String toString() {
1126             return "CpmsState canSleep:" + mCanSleep + ", canPostpone=" + mCanPostpone
1127                     + ", carPowerStateListenerState=" + mCarPowerStateListenerState
1128                     + ", CpmsState=" + this.name();
1129         }
1130     }
1131 
1132     /**
1133      * Resume after a manually-invoked suspend.
1134      * Invoked using "adb shell dumpsys activity service com.android.car resume".
1135      */
forceSimulatedResume()1136     public void forceSimulatedResume() {
1137         PowerHandler handler;
1138         synchronized (this) {
1139             // Cancel Garage Mode in case it's running
1140             mPendingPowerStates.addFirst(new CpmsState(CpmsState.WAIT_FOR_VHAL,
1141                                                        CarPowerStateListener.SHUTDOWN_CANCELLED));
1142             handler = mHandler;
1143         }
1144         handler.handlePowerStateChange();
1145 
1146         synchronized (mSimulationWaitObject) {
1147             mWakeFromSimulatedSleep = true;
1148             mSimulationWaitObject.notify();
1149         }
1150     }
1151 
1152     /**
1153      * Manually enter simulated suspend (Deep Sleep) mode, trigging Garage mode.
1154      * If the parameter is 'true', reboot the system when Garage Mode completes.
1155      *
1156      * Invoked using "adb shell dumpsys activity service com.android.car suspend" or
1157      * "adb shell dumpsys activity service com.android.car garage-mode reboot".
1158      * This is similar to 'onApPowerStateChange()' except that it needs to create a CpmsState
1159      * that is not directly derived from a VehicleApPowerStateReq.
1160      */
1161     @VisibleForTesting
forceSuspendAndMaybeReboot(boolean shouldReboot)1162     void forceSuspendAndMaybeReboot(boolean shouldReboot) {
1163         synchronized (mSimulationWaitObject) {
1164             mInSimulatedDeepSleepMode = true;
1165             mWakeFromSimulatedSleep = false;
1166         }
1167         PowerHandler handler;
1168         synchronized (mLock) {
1169             mRebootAfterGarageMode = shouldReboot;
1170             mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP,
1171                                                        CarPowerStateListener.SHUTDOWN_PREPARE));
1172             handler = mHandler;
1173         }
1174         handler.handlePowerStateChange();
1175     }
1176 
1177     // In a real Deep Sleep, the hardware removes power from the CPU (but retains power
1178     // on the RAM). This puts the processor to sleep. Upon some external signal, power
1179     // is re-applied to the CPU, and processing resumes right where it left off.
1180     // We simulate this behavior by calling wait().
1181     // We continue from wait() when forceSimulatedResume() is called.
simulateSleepByWaiting()1182     private void simulateSleepByWaiting() {
1183         Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by waiting");
1184         synchronized (mSimulationWaitObject) {
1185             while (!mWakeFromSimulatedSleep) {
1186                 try {
1187                     mSimulationWaitObject.wait();
1188                 } catch (InterruptedException ignored) {
1189                     Thread.currentThread().interrupt(); // Restore interrupted status
1190                 }
1191             }
1192             mInSimulatedDeepSleepMode = false;
1193         }
1194         Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation");
1195     }
1196 }
1197