1 /* 2 * Copyright (C) 2021 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.server.devicestate; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.hardware.devicestate.DeviceState; 22 import android.hardware.devicestate.DeviceStateRequest; 23 import android.os.IBinder; 24 import android.util.Slog; 25 26 import java.io.PrintWriter; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 30 /** 31 * Manages the lifecycle of override requests. 32 * <p> 33 * New requests are added with {@link #addRequest(OverrideRequest)} and are kept active until 34 * either: 35 * <ul> 36 * <li>A new request is added with {@link #addRequest(OverrideRequest)}, in which case the 37 * request will become suspended.</li> 38 * <li>The request is cancelled with {@link #cancelRequest} or as a side effect 39 * of other methods calls, such as {@link #handleProcessDied(int)}.</li> 40 * </ul> 41 */ 42 final class OverrideRequestController { 43 private static final String TAG = "OverrideRequestController"; 44 45 static final int STATUS_UNKNOWN = 0; 46 /** 47 * The request is the top-most request. 48 */ 49 static final int STATUS_ACTIVE = 1; 50 /** 51 * The request is not longer valid. 52 */ 53 static final int STATUS_CANCELED = 2; 54 55 @IntDef(prefix = {"STATUS_"}, value = { 56 STATUS_UNKNOWN, 57 STATUS_ACTIVE, 58 STATUS_CANCELED 59 }) 60 @Retention(RetentionPolicy.SOURCE) 61 @interface RequestStatus {} 62 63 /** 64 * A flag indicating that the status change was triggered by thermal critical status. 65 */ 66 static final int FLAG_THERMAL_CRITICAL = 1 << 0; 67 68 /** 69 * A flag indicating that the status change was triggered by power save mode. 70 */ 71 static final int FLAG_POWER_SAVE_ENABLED = 1 << 1; 72 73 @IntDef(flag = true, prefix = {"FLAG_"}, value = { 74 FLAG_THERMAL_CRITICAL, 75 FLAG_POWER_SAVE_ENABLED 76 }) 77 @Retention(RetentionPolicy.SOURCE) 78 @interface StatusChangedFlag {} 79 statusToString(@equestStatus int status)80 static String statusToString(@RequestStatus int status) { 81 switch (status) { 82 case STATUS_ACTIVE: 83 return "ACTIVE"; 84 case STATUS_CANCELED: 85 return "CANCELED"; 86 case STATUS_UNKNOWN: 87 return "UNKNOWN"; 88 } 89 throw new IllegalArgumentException("Unknown status: " + status); 90 } 91 92 private final StatusChangeListener mListener; 93 94 // Handle to the current override request, null if none. 95 private OverrideRequest mRequest; 96 // Handle to the current base state override request, null if none. 97 private OverrideRequest mBaseStateRequest; 98 99 private boolean mStickyRequestsAllowed; 100 // The current request has outlived their process. 101 private boolean mStickyRequest; 102 OverrideRequestController(@onNull StatusChangeListener listener)103 OverrideRequestController(@NonNull StatusChangeListener listener) { 104 mListener = listener; 105 } 106 107 /** 108 * Sets sticky requests as either allowed or disallowed. When sticky requests are allowed a call 109 * to {@link #handleProcessDied(int)} will not result in the request being cancelled 110 * immediately. Instead, the request will be marked sticky and must be cancelled with a call 111 * to {@link #cancelStickyRequest()}. 112 */ setStickyRequestsAllowed(boolean stickyRequestsAllowed)113 void setStickyRequestsAllowed(boolean stickyRequestsAllowed) { 114 mStickyRequestsAllowed = stickyRequestsAllowed; 115 if (!mStickyRequestsAllowed) { 116 cancelStickyRequest(); 117 } 118 } 119 120 /** 121 * Sets the new request as active and cancels the previous override request, notifies the 122 * listener of all changes to request status as a result of this operation. 123 */ addRequest(@onNull OverrideRequest request)124 void addRequest(@NonNull OverrideRequest request) { 125 OverrideRequest previousRequest = mRequest; 126 mRequest = request; 127 mListener.onStatusChanged(request, STATUS_ACTIVE, 0 /* flags */); 128 129 if (previousRequest != null) { 130 cancelRequestLocked(previousRequest); 131 } 132 } 133 addBaseStateRequest(@onNull OverrideRequest request)134 void addBaseStateRequest(@NonNull OverrideRequest request) { 135 OverrideRequest previousRequest = mBaseStateRequest; 136 mBaseStateRequest = request; 137 mListener.onStatusChanged(request, STATUS_ACTIVE, 0 /* flags */); 138 139 if (previousRequest != null) { 140 cancelRequestLocked(previousRequest); 141 } 142 } 143 144 /** 145 * Cancels the request with the specified {@code token} and notifies the listener of all changes 146 * to request status as a result of this operation. 147 */ cancelRequest(@onNull OverrideRequest request)148 void cancelRequest(@NonNull OverrideRequest request) { 149 // Either don't have a current request or attempting to cancel an already cancelled request 150 if (!hasRequest(request.getToken(), request.getRequestType())) { 151 return; 152 } 153 cancelCurrentRequestLocked(); 154 } 155 156 /** 157 * Cancels a request that is currently marked sticky and notifies the listener of all 158 * changes to request status as a result of this operation. 159 * 160 * @see #setStickyRequestsAllowed(boolean) 161 */ cancelStickyRequest()162 void cancelStickyRequest() { 163 if (mStickyRequest) { 164 cancelCurrentRequestLocked(); 165 } 166 } 167 168 /** 169 * Cancels the current override request, this could be due to the device being put 170 * into a hardware state that declares the flag "FLAG_CANCEL_OVERRIDE_REQUESTS" 171 */ cancelOverrideRequest()172 void cancelOverrideRequest() { 173 cancelCurrentRequestLocked(); 174 } 175 176 /** 177 * Cancels the current base state override request, this could be due to the physical 178 * configuration of the device changing. 179 */ cancelBaseStateOverrideRequest()180 void cancelBaseStateOverrideRequest() { 181 cancelCurrentBaseStateRequestLocked(); 182 } 183 184 /** 185 * Returns {@code true} if this controller is current managing a request with the specified 186 * {@code token}, {@code false} otherwise. 187 */ hasRequest(@onNull IBinder token, @OverrideRequest.OverrideRequestType int requestType)188 boolean hasRequest(@NonNull IBinder token, 189 @OverrideRequest.OverrideRequestType int requestType) { 190 if (requestType == OverrideRequest.OVERRIDE_REQUEST_TYPE_BASE_STATE) { 191 return mBaseStateRequest != null && token == mBaseStateRequest.getToken(); 192 } else { 193 return mRequest != null && token == mRequest.getToken(); 194 } 195 } 196 197 /** 198 * Notifies the controller that the process with the specified {@code pid} has died. The 199 * controller will notify the listener of all changes to request status as a result of this 200 * operation. 201 */ handleProcessDied(int pid)202 void handleProcessDied(int pid) { 203 if (mBaseStateRequest != null && mBaseStateRequest.getPid() == pid) { 204 cancelCurrentBaseStateRequestLocked(); 205 } 206 207 if (mRequest != null && mRequest.getPid() == pid) { 208 if (mRequest.getRequestedDeviceState().hasProperty( 209 DeviceState.PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP)) { 210 cancelCurrentRequestLocked(); 211 return; 212 } 213 214 if (mStickyRequestsAllowed) { 215 // Do not cancel the requests now because sticky requests are allowed. These 216 // requests will be cancelled on a call to cancelStickyRequests(). 217 mStickyRequest = true; 218 return; 219 } 220 cancelCurrentRequestLocked(); 221 } 222 } 223 224 /** 225 * Notifies the controller that the base state has changed. The controller will notify the 226 * listener of all changes to request status as a result of this change. 227 */ handleBaseStateChanged(int state)228 void handleBaseStateChanged(int state) { 229 if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedStateIdentifier()) { 230 cancelBaseStateOverrideRequest(); 231 } 232 if (mRequest == null) { 233 return; 234 } 235 236 if ((mRequest.getFlags() 237 & DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES) != 0) { 238 cancelCurrentRequestLocked(); 239 } 240 } 241 242 /** 243 * Notifies the controller that the set of supported states has changed. The controller will 244 * notify the listener of all changes to request status as a result of this change. 245 */ handleNewSupportedStates(int[] newSupportedStates, @DeviceStateProvider.SupportedStatesUpdatedReason int reason)246 void handleNewSupportedStates(int[] newSupportedStates, 247 @DeviceStateProvider.SupportedStatesUpdatedReason int reason) { 248 boolean isThermalCritical = 249 reason == DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL; 250 boolean isPowerSaveEnabled = 251 reason == DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED; 252 @StatusChangedFlag int flags = 0; 253 flags |= isThermalCritical ? FLAG_THERMAL_CRITICAL : 0; 254 flags |= isPowerSaveEnabled ? FLAG_POWER_SAVE_ENABLED : 0; 255 if (mBaseStateRequest != null && !contains(newSupportedStates, 256 mBaseStateRequest.getRequestedStateIdentifier())) { 257 cancelCurrentBaseStateRequestLocked(flags); 258 } 259 260 if (mRequest != null && !contains(newSupportedStates, 261 mRequest.getRequestedStateIdentifier())) { 262 cancelCurrentRequestLocked(flags); 263 } 264 } 265 dumpInternal(PrintWriter pw)266 void dumpInternal(PrintWriter pw) { 267 OverrideRequest overrideRequest = mRequest; 268 final boolean requestActive = overrideRequest != null; 269 pw.println(); 270 pw.println("Override Request active: " + requestActive); 271 if (requestActive) { 272 pw.println("Request: mPid=" + overrideRequest.getPid() 273 + ", mRequestedState=" + overrideRequest.getRequestedStateIdentifier() 274 + ", mFlags=" + overrideRequest.getFlags() 275 + ", mStatus=" + statusToString(STATUS_ACTIVE)); 276 } 277 } 278 cancelRequestLocked(@onNull OverrideRequest requestToCancel)279 private void cancelRequestLocked(@NonNull OverrideRequest requestToCancel) { 280 cancelRequestLocked(requestToCancel, 0 /* flags */); 281 } 282 cancelRequestLocked(@onNull OverrideRequest requestToCancel, @StatusChangedFlag int flags)283 private void cancelRequestLocked(@NonNull OverrideRequest requestToCancel, 284 @StatusChangedFlag int flags) { 285 mListener.onStatusChanged(requestToCancel, STATUS_CANCELED, flags); 286 } 287 288 /** 289 * Handles cancelling {@code mRequest}. 290 * Notifies the listener of the canceled status as well. 291 */ cancelCurrentRequestLocked()292 private void cancelCurrentRequestLocked() { 293 cancelCurrentRequestLocked(0 /* flags */); 294 } 295 cancelCurrentRequestLocked(@tatusChangedFlag int flags)296 private void cancelCurrentRequestLocked(@StatusChangedFlag int flags) { 297 if (mRequest == null) { 298 Slog.w(TAG, "Attempted to cancel a null OverrideRequest"); 299 return; 300 } 301 mStickyRequest = false; 302 cancelRequestLocked(mRequest, flags); 303 mRequest = null; 304 } 305 306 /** 307 * Handles cancelling {@code mBaseStateRequest}. 308 * Notifies the listener of the canceled status as well. 309 */ cancelCurrentBaseStateRequestLocked()310 private void cancelCurrentBaseStateRequestLocked() { 311 cancelCurrentBaseStateRequestLocked(0 /* flags */); 312 } 313 cancelCurrentBaseStateRequestLocked(@tatusChangedFlag int flags)314 private void cancelCurrentBaseStateRequestLocked(@StatusChangedFlag int flags) { 315 if (mBaseStateRequest == null) { 316 Slog.w(TAG, "Attempted to cancel a null OverrideRequest"); 317 return; 318 } 319 cancelRequestLocked(mBaseStateRequest, flags); 320 mBaseStateRequest = null; 321 } 322 contains(int[] array, int value)323 private static boolean contains(int[] array, int value) { 324 for (int i = 0; i < array.length; i++) { 325 if (array[i] == value) { 326 return true; 327 } 328 } 329 return false; 330 } 331 332 public interface StatusChangeListener { 333 334 /** 335 * Notifies the listener of a change in request status. If a change within the controller 336 * causes one request to become active and one to become either suspended or cancelled, this 337 * method is guaranteed to be called with the active request first before the suspended or 338 * cancelled request. 339 */ onStatusChanged(@onNull OverrideRequest request, @RequestStatus int newStatus, @StatusChangedFlag int flags)340 void onStatusChanged(@NonNull OverrideRequest request, @RequestStatus int newStatus, 341 @StatusChangedFlag int flags); 342 } 343 } 344