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.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 20 21 import android.annotation.Nullable; 22 import android.car.builtin.util.Slogf; 23 import android.car.hardware.power.CarPowerManager; 24 import android.car.hardware.power.ICarPowerStateListener; 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 import android.util.Log; 31 32 import com.android.car.CarLocalServices; 33 import com.android.car.CarLog; 34 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 35 import com.android.car.internal.util.IndentingPrintWriter; 36 import com.android.car.power.CarPowerManagementService; 37 import com.android.car.systeminterface.SystemInterface; 38 import com.android.internal.annotations.VisibleForTesting; 39 40 /** 41 * Main controller for GarageMode. It controls all the flows of GarageMode and defines the logic. 42 */ 43 public class GarageModeController extends ICarPowerStateListener.Stub { 44 45 private static final String TAG = CarLog.tagFor(GarageMode.class) + "_" 46 + GarageModeController.class.getSimpleName(); 47 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 48 49 private final GarageMode mGarageMode; 50 private final Handler mHandler; 51 private CarPowerManagementService mCarPowerService; 52 GarageModeController(Context context, Looper looper)53 public GarageModeController(Context context, Looper looper) { 54 this(context, looper, /* handler= */ null, /* garageMode= */ null); 55 } 56 GarageModeController(Context context, Looper looper, Handler handler, GarageMode garageMode)57 public GarageModeController(Context context, Looper looper, Handler handler, 58 GarageMode garageMode) { 59 mHandler = (handler == null) ? new Handler(looper) : handler; 60 mGarageMode = (garageMode == null) ? new GarageMode(context, this) : garageMode; 61 } 62 63 /** init */ init()64 public void init() { 65 mCarPowerService = CarLocalServices.getService(CarPowerManagementService.class); 66 mCarPowerService.registerInternalListener(GarageModeController.this); 67 mGarageMode.init(); 68 Slogf.e("GarageMode", "init"); 69 } 70 71 /** release */ release()72 public void release() { 73 mCarPowerService.unregisterInternalListener(GarageModeController.this); 74 mGarageMode.release(); 75 } 76 77 // This function runs in the CarPowerManagementService handler thread, which is a different 78 // thread than mHandler is using. 79 @Override onStateChanged(int state, long expirationTimeMs)80 public void onStateChanged(int state, long expirationTimeMs) { 81 if (DBG) { 82 Slogf.d(TAG, "CPM state changed to %s", 83 CarPowerManagementService.powerStateToString(state)); 84 } 85 switch (state) { 86 case CarPowerManager.STATE_SHUTDOWN_CANCELLED: 87 resetGarageMode(null); 88 break; 89 case CarPowerManager.STATE_SHUTDOWN_ENTER: 90 case CarPowerManager.STATE_SUSPEND_ENTER: 91 case CarPowerManager.STATE_HIBERNATION_ENTER: 92 resetGarageMode(() -> { 93 mCarPowerService.completeHandlingPowerStateChange(state, 94 GarageModeController.this); 95 }); 96 break; 97 case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE: 98 case CarPowerManager.STATE_POST_SHUTDOWN_ENTER: 99 case CarPowerManager.STATE_POST_SUSPEND_ENTER: 100 case CarPowerManager.STATE_POST_HIBERNATION_ENTER: 101 mCarPowerService.completeHandlingPowerStateChange(state, GarageModeController.this); 102 break; 103 case CarPowerManager.STATE_SHUTDOWN_PREPARE: 104 initiateGarageMode( 105 () -> mCarPowerService.completeHandlingPowerStateChange(state, 106 GarageModeController.this)); 107 break; 108 default: 109 break; 110 } 111 } 112 113 /** 114 * @return boolean whether any jobs are currently in running that GarageMode cares about 115 */ isGarageModeActive()116 boolean isGarageModeActive() { 117 return mGarageMode.isGarageModeActive(); 118 } 119 120 /** 121 * Prints Garage Mode's status, including what jobs it is waiting for 122 */ 123 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)124 void dump(IndentingPrintWriter writer) { 125 mGarageMode.dump(writer); 126 } 127 128 /** 129 * Wrapper method to send a broadcast 130 * 131 * @param i intent that contains broadcast data 132 */ sendBroadcast(Intent i)133 void sendBroadcast(Intent i) { 134 SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class); 135 if (DBG) { 136 Slogf.d(TAG, "Sending broadcast with action: %s", i.getAction()); 137 } 138 systemInterface.sendBroadcastAsUser(i, UserHandle.ALL); 139 } 140 141 /** 142 * @return Handler instance used by controller 143 */ getHandler()144 Handler getHandler() { 145 return mHandler; 146 } 147 148 /** 149 * Initiates GarageMode flow which will set the system idleness to true and will start 150 * monitoring jobs which has idleness constraint enabled. 151 */ initiateGarageMode(Runnable completor)152 void initiateGarageMode(Runnable completor) { 153 mHandler.post(() -> mGarageMode.enterGarageMode(completor)); 154 } 155 156 /** 157 * Resets GarageMode. 158 */ resetGarageMode(@ullable Runnable completor)159 void resetGarageMode(@Nullable Runnable completor) { 160 mHandler.post(() -> mGarageMode.cancel(completor)); 161 } 162 163 @VisibleForTesting finishGarageMode()164 void finishGarageMode() { 165 mHandler.post(() -> mGarageMode.finish()); 166 } 167 } 168