1 /* 2 * Copyright (C) 2018 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 17 package com.android.car.garagemode; 18 19 import static com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 20 21 import android.app.job.JobScheduler; 22 import android.car.hardware.power.CarPowerManager; 23 import android.car.hardware.power.CarPowerManager.CarPowerStateListener; 24 import android.car.hardware.power.CarPowerManager.CarPowerStateListenerWithCompletion; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.os.Handler; 28 import android.os.Looper; 29 import android.os.UserHandle; 30 31 import com.android.car.CarLocalServices; 32 import com.android.car.CarLog; 33 import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport; 34 import com.android.car.systeminterface.SystemInterface; 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.server.utils.Slogf; 37 38 import java.io.PrintWriter; 39 import java.util.concurrent.CompletableFuture; 40 41 /** 42 * Main controller for GarageMode. It controls all the flows of GarageMode and defines the logic. 43 */ 44 public class Controller implements CarPowerStateListenerWithCompletion { 45 46 private static final String TAG = CarLog.tagFor(GarageMode.class) + "_" 47 + Controller.class.getSimpleName(); 48 49 @VisibleForTesting final WakeupPolicy mWakeupPolicy; 50 private final GarageMode mGarageMode; 51 private final Handler mHandler; 52 private final Context mContext; 53 private CarPowerManager mCarPowerManager; 54 Controller(Context context, Looper looper)55 public Controller(Context context, Looper looper) { 56 this(context, looper, null, null, null); 57 } 58 Controller( Context context, Looper looper, WakeupPolicy wakeupPolicy, Handler handler, GarageMode garageMode)59 public Controller( 60 Context context, 61 Looper looper, 62 WakeupPolicy wakeupPolicy, 63 Handler handler, 64 GarageMode garageMode) { 65 mContext = context; 66 mHandler = (handler == null ? new Handler(looper) : handler); 67 mWakeupPolicy = 68 (wakeupPolicy == null ? WakeupPolicy.initFromResources(context) : wakeupPolicy); 69 mGarageMode = (garageMode == null ? new GarageMode(this) : garageMode); 70 } 71 72 /** init */ init()73 public void init() { 74 mCarPowerManager = CarLocalServices.createCarPowerManager(mContext); 75 mCarPowerManager.setListenerWithCompletion(Controller.this); 76 mGarageMode.init(); 77 } 78 79 /** release */ release()80 public void release() { 81 mCarPowerManager.clearListener(); 82 mGarageMode.release(); 83 } 84 85 @Override onStateChanged(int state, CompletableFuture<Void> future)86 public void onStateChanged(int state, CompletableFuture<Void> future) { 87 switch (state) { 88 case CarPowerStateListener.SHUTDOWN_CANCELLED: 89 Slogf.d(TAG, "CPM state changed to SHUTDOWN_CANCELLED"); 90 handleShutdownCancelled(); 91 break; 92 case CarPowerStateListener.SHUTDOWN_ENTER: 93 Slogf.d(TAG, "CPM state changed to SHUTDOWN_ENTER"); 94 handleShutdownEnter(); 95 break; 96 case CarPowerStateListener.SHUTDOWN_PREPARE: 97 Slogf.d(TAG, "CPM state changed to SHUTDOWN_PREPARE"); 98 handleShutdownPrepare(future); 99 break; 100 case CarPowerStateListener.SUSPEND_ENTER: 101 Slogf.d(TAG, "CPM state changed to SUSPEND_ENTER"); 102 handleSuspendEnter(); 103 break; 104 case CarPowerStateListener.SUSPEND_EXIT: 105 Slogf.d(TAG, "CPM state changed to SUSPEND_EXIT"); 106 handleSuspendExit(); 107 break; 108 default: 109 } 110 } 111 112 /** 113 * @return boolean whether any jobs are currently in running that GarageMode cares about 114 */ isGarageModeActive()115 boolean isGarageModeActive() { 116 return mGarageMode.isGarageModeActive(); 117 } 118 119 /** 120 * Prints Garage Mode's status, including what jobs it is waiting for 121 */ 122 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(PrintWriter writer)123 void dump(PrintWriter writer) { 124 mGarageMode.dump(writer); 125 } 126 127 /** 128 * Wrapper method to send a broadcast 129 * 130 * @param i intent that contains broadcast data 131 */ sendBroadcast(Intent i)132 void sendBroadcast(Intent i) { 133 SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class); 134 Slogf.d(TAG, "Sending broadcast with action: %s", i.getAction()); 135 systemInterface.sendBroadcastAsUser(i, UserHandle.ALL); 136 } 137 138 /** 139 * @return JobSchedulerService instance 140 */ getJobSchedulerService()141 JobScheduler getJobSchedulerService() { 142 return (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); 143 } 144 145 /** 146 * @return Handler instance used by controller 147 */ getHandler()148 Handler getHandler() { 149 return mHandler; 150 } 151 152 /** 153 * Initiates GarageMode flow which will set the system idleness to true and will start 154 * monitoring jobs which has idleness constraint enabled. 155 */ initiateGarageMode(CompletableFuture<Void> future)156 void initiateGarageMode(CompletableFuture<Void> future) { 157 mWakeupPolicy.incrementCounter(); 158 mGarageMode.enterGarageMode(future); 159 } 160 161 /** 162 * Resets GarageMode. 163 */ resetGarageMode()164 void resetGarageMode() { 165 mGarageMode.cancel(); 166 mWakeupPolicy.resetCounter(); 167 } 168 169 @VisibleForTesting finishGarageMode()170 void finishGarageMode() { 171 mGarageMode.finish(); 172 } 173 174 @VisibleForTesting setCarPowerManager(CarPowerManager cpm)175 void setCarPowerManager(CarPowerManager cpm) { 176 mCarPowerManager = cpm; 177 } 178 scheduleNextWakeup()179 void scheduleNextWakeup() { 180 if (mWakeupPolicy.getNextWakeUpInterval() <= 0) { 181 // Either there is no policy or nothing left to schedule 182 return; 183 } 184 int seconds = mWakeupPolicy.getNextWakeUpInterval(); 185 mCarPowerManager.scheduleNextWakeupTime(seconds); 186 } 187 handleSuspendExit()188 private void handleSuspendExit() { 189 resetGarageMode(); 190 } 191 handleSuspendEnter()192 private void handleSuspendEnter() { 193 resetGarageMode(); 194 } 195 handleShutdownEnter()196 private void handleShutdownEnter() { 197 resetGarageMode(); 198 } 199 handleShutdownPrepare(CompletableFuture<Void> future)200 private void handleShutdownPrepare(CompletableFuture<Void> future) { 201 initiateGarageMode(future); 202 } 203 handleShutdownCancelled()204 private void handleShutdownCancelled() { 205 resetGarageMode(); 206 } 207 } 208