1 /* 2 * Copyright (C) 2020 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 static android.Manifest.permission.CONTROL_DEVICE_STATE; 20 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 21 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; 22 import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE; 23 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE; 24 25 import static com.android.server.devicestate.DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS; 26 import static com.android.server.devicestate.OverrideRequest.OVERRIDE_REQUEST_TYPE_BASE_STATE; 27 import static com.android.server.devicestate.OverrideRequest.OVERRIDE_REQUEST_TYPE_EMULATED_STATE; 28 import static com.android.server.devicestate.OverrideRequestController.STATUS_ACTIVE; 29 import static com.android.server.devicestate.OverrideRequestController.STATUS_CANCELED; 30 import static com.android.server.devicestate.OverrideRequestController.STATUS_UNKNOWN; 31 32 import android.annotation.IntDef; 33 import android.annotation.IntRange; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.content.Context; 37 import android.hardware.devicestate.DeviceStateInfo; 38 import android.hardware.devicestate.DeviceStateManager; 39 import android.hardware.devicestate.DeviceStateManagerInternal; 40 import android.hardware.devicestate.IDeviceStateManager; 41 import android.hardware.devicestate.IDeviceStateManagerCallback; 42 import android.os.Binder; 43 import android.os.Handler; 44 import android.os.IBinder; 45 import android.os.RemoteException; 46 import android.os.ResultReceiver; 47 import android.os.ShellCallback; 48 import android.os.SystemProperties; 49 import android.os.Trace; 50 import android.util.Slog; 51 import android.util.SparseArray; 52 53 import com.android.internal.R; 54 import com.android.internal.annotations.GuardedBy; 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.internal.util.DumpUtils; 57 import com.android.internal.util.FrameworkStatsLog; 58 import com.android.server.DisplayThread; 59 import com.android.server.LocalServices; 60 import com.android.server.SystemService; 61 import com.android.server.statusbar.StatusBarManagerInternal; 62 import com.android.server.wm.ActivityTaskManagerInternal; 63 import com.android.server.wm.WindowProcessController; 64 65 import java.io.FileDescriptor; 66 import java.io.PrintWriter; 67 import java.lang.annotation.Retention; 68 import java.lang.annotation.RetentionPolicy; 69 import java.util.ArrayList; 70 import java.util.Arrays; 71 import java.util.HashSet; 72 import java.util.Optional; 73 import java.util.Set; 74 import java.util.WeakHashMap; 75 76 /** 77 * A system service that manages the state of a device with user-configurable hardware like a 78 * foldable phone. 79 * <p> 80 * Device state is an abstract concept that allows mapping the current state of the device to the 81 * state of the system. For example, system services (like 82 * {@link com.android.server.display.DisplayManagerService display manager} and 83 * {@link com.android.server.wm.WindowManagerService window manager}) and system UI may have 84 * different behaviors depending on the physical state of the device. This is useful for 85 * variable-state devices, like foldable or rollable devices, that can be configured by users into 86 * differing hardware states, which each may have a different expected use case. 87 * </p> 88 * <p> 89 * The {@link DeviceStateManagerService} is responsible for receiving state change requests from 90 * the {@link DeviceStateProvider} to modify the current device state and communicating with the 91 * {@link DeviceStatePolicy policy} to ensure the system is configured to match the requested state. 92 * </p> 93 * The service also provides the {@link DeviceStateManager} API allowing clients to listen for 94 * changes in device state and submit requests to override the device state provided by the 95 * {@link DeviceStateProvider}. 96 * 97 * @see DeviceStatePolicy 98 * @see DeviceStateManager 99 */ 100 public final class DeviceStateManagerService extends SystemService { 101 private static final String TAG = "DeviceStateManagerService"; 102 private static final boolean DEBUG = false; 103 104 private final Object mLock = new Object(); 105 // Handler on the {@link DisplayThread} used to dispatch calls to the policy and to registered 106 // callbacks though its handler (mHandler). Provides a guarantee of callback order when 107 // leveraging mHandler and also enables posting messages with the service lock held. 108 private final Handler mHandler; 109 @NonNull 110 private final DeviceStatePolicy mDeviceStatePolicy; 111 @NonNull 112 private final BinderService mBinderService; 113 @NonNull 114 private final OverrideRequestController mOverrideRequestController; 115 @NonNull 116 private final DeviceStateProviderListener mDeviceStateProviderListener; 117 @VisibleForTesting 118 @NonNull 119 public ActivityTaskManagerInternal mActivityTaskManagerInternal; 120 121 // All supported device states keyed by identifier. 122 @GuardedBy("mLock") 123 private SparseArray<DeviceState> mDeviceStates = new SparseArray<>(); 124 125 // The current committed device state. Will be empty until the first device state provided by 126 // the DeviceStateProvider is committed. 127 @GuardedBy("mLock") 128 @NonNull 129 private Optional<DeviceState> mCommittedState = Optional.empty(); 130 // The device state that is currently awaiting callback from the policy to be committed. 131 @GuardedBy("mLock") 132 @NonNull 133 private Optional<DeviceState> mPendingState = Optional.empty(); 134 // Whether or not the policy is currently waiting to be notified of the current pending state. 135 @GuardedBy("mLock") 136 private boolean mIsPolicyWaitingForState = false; 137 138 // The device state that is set by the DeviceStateProvider. Will be empty until the first 139 // callback from the provider and then will always contain the most recent value. 140 @GuardedBy("mLock") 141 @NonNull 142 private Optional<DeviceState> mBaseState = Optional.empty(); 143 144 // The current active override request. When set the device state specified here will take 145 // precedence over mBaseState. 146 @GuardedBy("mLock") 147 @NonNull 148 private Optional<OverrideRequest> mActiveOverride = Optional.empty(); 149 150 // The current active base state override request. When set the device state specified here will 151 // replace the value in mBaseState. 152 @GuardedBy("mLock") 153 @NonNull 154 private Optional<OverrideRequest> mActiveBaseStateOverride = Optional.empty(); 155 156 // List of processes registered to receive notifications about changes to device state and 157 // request status indexed by process id. 158 @GuardedBy("mLock") 159 private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>(); 160 161 private Set<Integer> mDeviceStatesAvailableForAppRequests; 162 163 private Set<Integer> mFoldedDeviceStates; 164 165 @Nullable 166 private DeviceState mRearDisplayState; 167 168 // TODO(259328837) Generalize for all pending feature requests in the future 169 @Nullable 170 private OverrideRequest mRearDisplayPendingOverrideRequest; 171 172 @VisibleForTesting 173 interface SystemPropertySetter { setDebugTracingDeviceStateProperty(String value)174 void setDebugTracingDeviceStateProperty(String value); 175 } 176 @NonNull 177 private final SystemPropertySetter mSystemPropertySetter; 178 DeviceStateManagerService(@onNull Context context)179 public DeviceStateManagerService(@NonNull Context context) { 180 this(context, DeviceStatePolicy.Provider 181 .fromResources(context.getResources()) 182 .instantiate(context)); 183 } 184 DeviceStateManagerService(@onNull Context context, @NonNull DeviceStatePolicy policy)185 private DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) { 186 this(context, policy, (value) -> { 187 SystemProperties.set("debug.tracing.device_state", value); 188 }); 189 } 190 191 @VisibleForTesting DeviceStateManagerService(@onNull Context context, @NonNull DeviceStatePolicy policy, @NonNull SystemPropertySetter systemPropertySetter)192 DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy, 193 @NonNull SystemPropertySetter systemPropertySetter) { 194 super(context); 195 mSystemPropertySetter = systemPropertySetter; 196 // We use the DisplayThread because this service indirectly drives 197 // display (on/off) and window (position) events through its callbacks. 198 DisplayThread displayThread = DisplayThread.get(); 199 mHandler = new Handler(displayThread.getLooper()); 200 mOverrideRequestController = new OverrideRequestController( 201 this::onOverrideRequestStatusChangedLocked); 202 mDeviceStatePolicy = policy; 203 mDeviceStateProviderListener = new DeviceStateProviderListener(); 204 mDeviceStatePolicy.getDeviceStateProvider().setListener(mDeviceStateProviderListener); 205 mBinderService = new BinderService(); 206 mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); 207 } 208 209 @Override onStart()210 public void onStart() { 211 publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService); 212 publishLocalService(DeviceStateManagerInternal.class, new LocalService()); 213 214 synchronized (mLock) { 215 readStatesAvailableForRequestFromApps(); 216 mFoldedDeviceStates = readFoldedStates(); 217 } 218 } 219 220 @VisibleForTesting getHandler()221 Handler getHandler() { 222 return mHandler; 223 } 224 225 /** 226 * Returns the current state the system is in. Note that the system may be in the process of 227 * configuring a different state. 228 * <p> 229 * Note: This method will return {@link Optional#empty()} if called before the first state has 230 * been committed, otherwise it will return the last committed state. 231 * 232 * @see #getPendingState() 233 */ 234 @NonNull getCommittedState()235 Optional<DeviceState> getCommittedState() { 236 synchronized (mLock) { 237 return mCommittedState; 238 } 239 } 240 241 /** 242 * Returns the state the system is currently configuring, or {@link Optional#empty()} if the 243 * system is not in the process of configuring a state. 244 */ 245 @VisibleForTesting 246 @NonNull getPendingState()247 Optional<DeviceState> getPendingState() { 248 synchronized (mLock) { 249 return mPendingState; 250 } 251 } 252 253 /** 254 * Returns the base state. The service will configure the device to match the base state when 255 * there is no active request to override the base state. 256 * <p> 257 * Note: This method will return {@link Optional#empty()} if called before a base state is 258 * provided to the service by the {@link DeviceStateProvider}, otherwise it will return the 259 * most recent provided value. 260 * 261 * @see #getOverrideState() 262 */ 263 @NonNull getBaseState()264 Optional<DeviceState> getBaseState() { 265 synchronized (mLock) { 266 return mBaseState; 267 } 268 } 269 270 /** 271 * Returns the current override state, or {@link Optional#empty()} if no override state is 272 * requested. If an override states is present, the returned state will take precedence over 273 * the base state returned from {@link #getBaseState()}. 274 */ 275 @NonNull getOverrideState()276 Optional<DeviceState> getOverrideState() { 277 synchronized (mLock) { 278 if (mActiveOverride.isPresent()) { 279 return getStateLocked(mActiveOverride.get().getRequestedState()); 280 } 281 return Optional.empty(); 282 } 283 } 284 285 /** 286 * Returns the current override base state, or {@link Optional#empty()} if no override state is 287 * requested. If an override base state is present, the returned state will be the same as 288 * the base state returned from {@link #getBaseState()}. 289 */ 290 @NonNull getOverrideBaseState()291 Optional<DeviceState> getOverrideBaseState() { 292 synchronized (mLock) { 293 if (mActiveBaseStateOverride.isPresent()) { 294 return getStateLocked(mActiveBaseStateOverride.get().getRequestedState()); 295 } 296 return Optional.empty(); 297 } 298 } 299 300 /** Returns the list of currently supported device states. */ getSupportedStates()301 DeviceState[] getSupportedStates() { 302 synchronized (mLock) { 303 DeviceState[] supportedStates = new DeviceState[mDeviceStates.size()]; 304 for (int i = 0; i < supportedStates.length; i++) { 305 supportedStates[i] = mDeviceStates.valueAt(i); 306 } 307 return supportedStates; 308 } 309 } 310 311 /** Returns the list of currently supported device state identifiers. */ getSupportedStateIdentifiersLocked()312 private int[] getSupportedStateIdentifiersLocked() { 313 int[] supportedStates = new int[mDeviceStates.size()]; 314 for (int i = 0; i < supportedStates.length; i++) { 315 supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier(); 316 } 317 return supportedStates; 318 } 319 320 @NonNull getDeviceStateInfoLocked()321 private DeviceStateInfo getDeviceStateInfoLocked() { 322 if (!mBaseState.isPresent() || !mCommittedState.isPresent()) { 323 throw new IllegalStateException("Trying to get the current DeviceStateInfo before the" 324 + " initial state has been committed."); 325 } 326 327 final int[] supportedStates = getSupportedStateIdentifiersLocked(); 328 final int baseState = mBaseState.get().getIdentifier(); 329 final int currentState = mCommittedState.get().getIdentifier(); 330 331 return new DeviceStateInfo(supportedStates, baseState, currentState); 332 } 333 334 @VisibleForTesting getBinderService()335 IDeviceStateManager getBinderService() { 336 return mBinderService; 337 } 338 updateSupportedStates(DeviceState[] supportedDeviceStates)339 private void updateSupportedStates(DeviceState[] supportedDeviceStates) { 340 synchronized (mLock) { 341 final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked(); 342 343 // Whether or not at least one device state has the flag FLAG_CANCEL_OVERRIDE_REQUESTS 344 // set. If set to true, the OverrideRequestController will be configured to allow sticky 345 // requests. 346 boolean hasTerminalDeviceState = false; 347 mDeviceStates.clear(); 348 for (int i = 0; i < supportedDeviceStates.length; i++) { 349 DeviceState state = supportedDeviceStates[i]; 350 if (state.hasFlag(FLAG_CANCEL_OVERRIDE_REQUESTS)) { 351 hasTerminalDeviceState = true; 352 } 353 mDeviceStates.put(state.getIdentifier(), state); 354 } 355 356 mOverrideRequestController.setStickyRequestsAllowed(hasTerminalDeviceState); 357 358 final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked(); 359 if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) { 360 return; 361 } 362 363 mOverrideRequestController.handleNewSupportedStates(newStateIdentifiers); 364 updatePendingStateLocked(); 365 366 setRearDisplayStateLocked(); 367 368 if (!mPendingState.isPresent()) { 369 // If the change in the supported states didn't result in a change of the pending 370 // state commitPendingState() will never be called and the callbacks will never be 371 // notified of the change. 372 notifyDeviceStateInfoChangedAsync(); 373 } 374 375 mHandler.post(this::notifyPolicyIfNeeded); 376 } 377 } 378 379 @GuardedBy("mLock") setRearDisplayStateLocked()380 private void setRearDisplayStateLocked() { 381 int rearDisplayIdentifier = getContext().getResources().getInteger( 382 R.integer.config_deviceStateRearDisplay); 383 if (rearDisplayIdentifier != INVALID_DEVICE_STATE) { 384 mRearDisplayState = mDeviceStates.get(rearDisplayIdentifier); 385 } 386 } 387 388 /** 389 * Returns {@code true} if the provided state is supported. Requires that 390 * {@link #mDeviceStates} is sorted prior to calling. 391 */ isSupportedStateLocked(int identifier)392 private boolean isSupportedStateLocked(int identifier) { 393 return mDeviceStates.contains(identifier); 394 } 395 396 /** 397 * Returns the {@link DeviceState} with the supplied {@code identifier}, or {@code null} if 398 * there is no device state with the identifier. 399 */ 400 @Nullable getStateLocked(int identifier)401 private Optional<DeviceState> getStateLocked(int identifier) { 402 return Optional.ofNullable(mDeviceStates.get(identifier)); 403 } 404 405 /** 406 * Sets the base state. 407 * 408 * @throws IllegalArgumentException if the {@code identifier} is not a supported state. 409 * 410 * @see #isSupportedStateLocked(int) 411 */ setBaseState(int identifier)412 private void setBaseState(int identifier) { 413 synchronized (mLock) { 414 final Optional<DeviceState> baseStateOptional = getStateLocked(identifier); 415 if (!baseStateOptional.isPresent()) { 416 throw new IllegalArgumentException("Base state is not supported"); 417 } 418 419 final DeviceState baseState = baseStateOptional.get(); 420 421 if (mBaseState.isPresent() && mBaseState.get().equals(baseState)) { 422 // Base state hasn't changed. Nothing to do. 423 return; 424 } 425 // There is a pending rear display request, so we check if the overlay should be closed 426 if (mRearDisplayPendingOverrideRequest != null) { 427 handleRearDisplayBaseStateChangedLocked(identifier); 428 } 429 mBaseState = Optional.of(baseState); 430 431 if (baseState.hasFlag(FLAG_CANCEL_OVERRIDE_REQUESTS)) { 432 mOverrideRequestController.cancelOverrideRequest(); 433 } 434 mOverrideRequestController.handleBaseStateChanged(identifier); 435 updatePendingStateLocked(); 436 437 if (!mPendingState.isPresent()) { 438 // If the change in base state didn't result in a change of the pending state 439 // commitPendingState() will never be called and the callbacks will never be 440 // notified of the change. 441 notifyDeviceStateInfoChangedAsync(); 442 } 443 444 mHandler.post(this::notifyPolicyIfNeeded); 445 } 446 } 447 448 /** 449 * Tries to update the current pending state with the current requested state. Must call 450 * {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being 451 * changed. 452 * 453 * @return {@code true} if the pending state has changed as a result of this call, {@code false} 454 * otherwise. 455 */ updatePendingStateLocked()456 private boolean updatePendingStateLocked() { 457 if (mPendingState.isPresent()) { 458 // Have pending state, can not configure a new state until the state is committed. 459 return false; 460 } 461 462 final DeviceState stateToConfigure; 463 if (mActiveOverride.isPresent()) { 464 stateToConfigure = getStateLocked(mActiveOverride.get().getRequestedState()).get(); 465 } else if (mBaseState.isPresent() 466 && isSupportedStateLocked(mBaseState.get().getIdentifier())) { 467 // Base state could have recently become unsupported after a change in supported states. 468 stateToConfigure = mBaseState.get(); 469 } else { 470 stateToConfigure = null; 471 } 472 473 if (stateToConfigure == null) { 474 // No currently requested state. 475 return false; 476 } 477 478 if (mCommittedState.isPresent() && stateToConfigure.equals(mCommittedState.get())) { 479 // The state requesting to be committed already matches the current committed state. 480 return false; 481 } 482 483 mPendingState = Optional.of(stateToConfigure); 484 mIsPolicyWaitingForState = true; 485 return true; 486 } 487 488 /** 489 * Notifies the policy to configure the supplied state. Should not be called with {@link #mLock} 490 * held. 491 */ notifyPolicyIfNeeded()492 private void notifyPolicyIfNeeded() { 493 if (Thread.holdsLock(mLock)) { 494 Throwable error = new Throwable("Attempting to notify DeviceStatePolicy with service" 495 + " lock held"); 496 error.fillInStackTrace(); 497 Slog.w(TAG, error); 498 } 499 int state; 500 synchronized (mLock) { 501 if (!mIsPolicyWaitingForState) { 502 return; 503 } 504 mIsPolicyWaitingForState = false; 505 state = mPendingState.get().getIdentifier(); 506 } 507 508 if (DEBUG) { 509 Slog.d(TAG, "Notifying policy to configure state: " + state); 510 } 511 mDeviceStatePolicy.configureDeviceForState(state, this::commitPendingState); 512 } 513 514 /** 515 * Commits the current pending state after a callback from the {@link DeviceStatePolicy}. 516 * 517 * <pre> 518 * ------------- ----------- ------------- 519 * Provider -> | Requested | -> | Pending | -> Policy -> | Committed | 520 * ------------- ----------- ------------- 521 * </pre> 522 * <p> 523 * When a new state is requested it immediately enters the requested state. Once the policy is 524 * available to accept a new state, which could also be immediately if there is no current 525 * pending state at the point of request, the policy is notified and a callback is provided to 526 * trigger the state to be committed. 527 * </p> 528 */ commitPendingState()529 private void commitPendingState() { 530 synchronized (mLock) { 531 final DeviceState newState = mPendingState.get(); 532 if (DEBUG) { 533 Slog.d(TAG, "Committing state: " + newState); 534 } 535 536 FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_STATE_CHANGED, 537 newState.getIdentifier(), !mCommittedState.isPresent()); 538 String traceString = newState.getIdentifier() + ":" + newState.getName(); 539 Trace.instantForTrack( 540 Trace.TRACE_TAG_SYSTEM_SERVER, "DeviceStateChanged", traceString); 541 mSystemPropertySetter.setDebugTracingDeviceStateProperty(traceString); 542 543 mCommittedState = Optional.of(newState); 544 mPendingState = Optional.empty(); 545 updatePendingStateLocked(); 546 547 // Notify callbacks of a change. 548 notifyDeviceStateInfoChangedAsync(); 549 550 // The top request could have come in while the service was awaiting callback 551 // from the policy. In that case we only set it to active if it matches the 552 // current committed state, otherwise it will be set to active when its 553 // requested state is committed. 554 OverrideRequest activeRequest = mActiveOverride.orElse(null); 555 if (activeRequest != null 556 && activeRequest.getRequestedState() == newState.getIdentifier()) { 557 ProcessRecord processRecord = mProcessRecords.get(activeRequest.getPid()); 558 if (processRecord != null) { 559 processRecord.notifyRequestActiveAsync(activeRequest.getToken()); 560 } 561 } 562 563 // Try to configure the next state if needed. 564 mHandler.post(this::notifyPolicyIfNeeded); 565 } 566 } 567 notifyDeviceStateInfoChangedAsync()568 private void notifyDeviceStateInfoChangedAsync() { 569 synchronized (mLock) { 570 if (mProcessRecords.size() == 0) { 571 return; 572 } 573 574 ArrayList<ProcessRecord> registeredProcesses = new ArrayList<>(); 575 for (int i = 0; i < mProcessRecords.size(); i++) { 576 registeredProcesses.add(mProcessRecords.valueAt(i)); 577 } 578 579 DeviceStateInfo info = getDeviceStateInfoLocked(); 580 581 for (int i = 0; i < registeredProcesses.size(); i++) { 582 registeredProcesses.get(i).notifyDeviceStateInfoAsync(info); 583 } 584 } 585 } 586 587 @GuardedBy("mLock") onOverrideRequestStatusChangedLocked(@onNull OverrideRequest request, @OverrideRequestController.RequestStatus int status)588 private void onOverrideRequestStatusChangedLocked(@NonNull OverrideRequest request, 589 @OverrideRequestController.RequestStatus int status) { 590 if (request.getRequestType() == OVERRIDE_REQUEST_TYPE_BASE_STATE) { 591 switch (status) { 592 case STATUS_ACTIVE: 593 enableBaseStateRequestLocked(request); 594 return; 595 case STATUS_CANCELED: 596 if (mActiveBaseStateOverride.isPresent() 597 && mActiveBaseStateOverride.get() == request) { 598 mActiveBaseStateOverride = Optional.empty(); 599 } 600 break; 601 case STATUS_UNKNOWN: // same as default 602 default: 603 throw new IllegalArgumentException("Unknown request status: " + status); 604 } 605 } else if (request.getRequestType() == OVERRIDE_REQUEST_TYPE_EMULATED_STATE) { 606 switch (status) { 607 case STATUS_ACTIVE: 608 mActiveOverride = Optional.of(request); 609 break; 610 case STATUS_CANCELED: 611 if (mActiveOverride.isPresent() && mActiveOverride.get() == request) { 612 mActiveOverride = Optional.empty(); 613 } 614 break; 615 case STATUS_UNKNOWN: // same as default 616 default: 617 throw new IllegalArgumentException("Unknown request status: " + status); 618 } 619 } else { 620 throw new IllegalArgumentException( 621 "Unknown OverrideRest type: " + request.getRequestType()); 622 } 623 624 boolean updatedPendingState = updatePendingStateLocked(); 625 626 ProcessRecord processRecord = mProcessRecords.get(request.getPid()); 627 if (processRecord == null) { 628 // If the process is no longer registered with the service, for example if it has died, 629 // there is no need to notify it of a change in request status. 630 mHandler.post(this::notifyPolicyIfNeeded); 631 return; 632 } 633 634 if (status == STATUS_ACTIVE) { 635 if (!updatedPendingState && !mPendingState.isPresent()) { 636 // If the pending state was not updated and there is not currently a pending state 637 // then this newly active request will never be notified of a change in state. 638 // Schedule the notification now. 639 processRecord.notifyRequestActiveAsync(request.getToken()); 640 } 641 } else { 642 processRecord.notifyRequestCanceledAsync(request.getToken()); 643 } 644 645 mHandler.post(this::notifyPolicyIfNeeded); 646 } 647 648 /** 649 * Sets the new base state of the device and notifies the process that made the base state 650 * override request that the request is now active. 651 */ 652 @GuardedBy("mLock") enableBaseStateRequestLocked(OverrideRequest request)653 private void enableBaseStateRequestLocked(OverrideRequest request) { 654 setBaseState(request.getRequestedState()); 655 mActiveBaseStateOverride = Optional.of(request); 656 ProcessRecord processRecord = mProcessRecords.get(request.getPid()); 657 processRecord.notifyRequestActiveAsync(request.getToken()); 658 } 659 registerProcess(int pid, IDeviceStateManagerCallback callback)660 private void registerProcess(int pid, IDeviceStateManagerCallback callback) { 661 synchronized (mLock) { 662 if (mProcessRecords.contains(pid)) { 663 throw new SecurityException("The calling process has already registered an" 664 + " IDeviceStateManagerCallback."); 665 } 666 667 ProcessRecord record = new ProcessRecord(callback, pid, this::handleProcessDied, 668 mHandler); 669 try { 670 callback.asBinder().linkToDeath(record, 0); 671 } catch (RemoteException ex) { 672 throw new RuntimeException(ex); 673 } 674 mProcessRecords.put(pid, record); 675 676 DeviceStateInfo currentInfo = mCommittedState.isPresent() 677 ? getDeviceStateInfoLocked() : null; 678 if (currentInfo != null) { 679 // If there is not a committed state we'll wait to notify the process of the initial 680 // value. 681 record.notifyDeviceStateInfoAsync(currentInfo); 682 } 683 } 684 } 685 handleProcessDied(ProcessRecord processRecord)686 private void handleProcessDied(ProcessRecord processRecord) { 687 synchronized (mLock) { 688 mProcessRecords.remove(processRecord.mPid); 689 mOverrideRequestController.handleProcessDied(processRecord.mPid); 690 } 691 } 692 requestStateInternal(int state, int flags, int callingPid, @NonNull IBinder token, boolean hasControlDeviceStatePermission)693 private void requestStateInternal(int state, int flags, int callingPid, 694 @NonNull IBinder token, boolean hasControlDeviceStatePermission) { 695 synchronized (mLock) { 696 final ProcessRecord processRecord = mProcessRecords.get(callingPid); 697 if (processRecord == null) { 698 throw new IllegalStateException("Process " + callingPid 699 + " has no registered callback."); 700 } 701 702 if (mOverrideRequestController.hasRequest(token, 703 OVERRIDE_REQUEST_TYPE_EMULATED_STATE)) { 704 throw new IllegalStateException("Request has already been made for the supplied" 705 + " token: " + token); 706 } 707 708 final Optional<DeviceState> deviceState = getStateLocked(state); 709 if (!deviceState.isPresent()) { 710 throw new IllegalArgumentException("Requested state: " + state 711 + " is not supported."); 712 } 713 714 OverrideRequest request = new OverrideRequest(token, callingPid, state, flags, 715 OVERRIDE_REQUEST_TYPE_EMULATED_STATE); 716 717 // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay 718 if (!hasControlDeviceStatePermission && mRearDisplayState != null 719 && state == mRearDisplayState.getIdentifier()) { 720 showRearDisplayEducationalOverlayLocked(request); 721 } else { 722 mOverrideRequestController.addRequest(request); 723 } 724 } 725 } 726 727 /** 728 * If we get a request to enter rear display mode, we need to display an educational 729 * overlay to let the user know what will happen. This calls into the 730 * {@link StatusBarManagerInternal} to notify SystemUI to display the educational dialog. 731 */ 732 @GuardedBy("mLock") showRearDisplayEducationalOverlayLocked(OverrideRequest request)733 private void showRearDisplayEducationalOverlayLocked(OverrideRequest request) { 734 mRearDisplayPendingOverrideRequest = request; 735 736 StatusBarManagerInternal statusBar = 737 LocalServices.getService(StatusBarManagerInternal.class); 738 if (statusBar != null) { 739 statusBar.showRearDisplayDialog(mBaseState.get().getIdentifier()); 740 } 741 } 742 cancelStateRequestInternal(int callingPid)743 private void cancelStateRequestInternal(int callingPid) { 744 synchronized (mLock) { 745 final ProcessRecord processRecord = mProcessRecords.get(callingPid); 746 if (processRecord == null) { 747 throw new IllegalStateException("Process " + callingPid 748 + " has no registered callback."); 749 } 750 mActiveOverride.ifPresent(mOverrideRequestController::cancelRequest); 751 } 752 } 753 requestBaseStateOverrideInternal(int state, int flags, int callingPid, @NonNull IBinder token)754 private void requestBaseStateOverrideInternal(int state, int flags, int callingPid, 755 @NonNull IBinder token) { 756 synchronized (mLock) { 757 final Optional<DeviceState> deviceState = getStateLocked(state); 758 if (!deviceState.isPresent()) { 759 throw new IllegalArgumentException("Requested state: " + state 760 + " is not supported."); 761 } 762 763 final ProcessRecord processRecord = mProcessRecords.get(callingPid); 764 if (processRecord == null) { 765 throw new IllegalStateException("Process " + callingPid 766 + " has no registered callback."); 767 } 768 769 if (mOverrideRequestController.hasRequest(token, 770 OVERRIDE_REQUEST_TYPE_BASE_STATE)) { 771 throw new IllegalStateException("Request has already been made for the supplied" 772 + " token: " + token); 773 } 774 775 OverrideRequest request = new OverrideRequest(token, callingPid, state, flags, 776 OVERRIDE_REQUEST_TYPE_BASE_STATE); 777 mOverrideRequestController.addBaseStateRequest(request); 778 } 779 } 780 cancelBaseStateOverrideInternal(int callingPid)781 private void cancelBaseStateOverrideInternal(int callingPid) { 782 synchronized (mLock) { 783 final ProcessRecord processRecord = mProcessRecords.get(callingPid); 784 if (processRecord == null) { 785 throw new IllegalStateException("Process " + callingPid 786 + " has no registered callback."); 787 } 788 setBaseState(mDeviceStateProviderListener.mCurrentBaseState); 789 } 790 } 791 792 /** 793 * Adds the rear display state request to the {@link OverrideRequestController} if the 794 * educational overlay was closed in a way that should enable the feature, and cancels the 795 * request if it was dismissed in a way that should cancel the feature. 796 */ onStateRequestOverlayDismissedInternal(boolean shouldCancelRequest)797 private void onStateRequestOverlayDismissedInternal(boolean shouldCancelRequest) { 798 if (mRearDisplayPendingOverrideRequest != null) { 799 synchronized (mLock) { 800 if (shouldCancelRequest) { 801 ProcessRecord processRecord = mProcessRecords.get( 802 mRearDisplayPendingOverrideRequest.getPid()); 803 processRecord.notifyRequestCanceledAsync( 804 mRearDisplayPendingOverrideRequest.getToken()); 805 } else { 806 mOverrideRequestController.addRequest(mRearDisplayPendingOverrideRequest); 807 } 808 mRearDisplayPendingOverrideRequest = null; 809 } 810 } 811 } 812 dumpInternal(PrintWriter pw)813 private void dumpInternal(PrintWriter pw) { 814 pw.println("DEVICE STATE MANAGER (dumpsys device_state)"); 815 816 synchronized (mLock) { 817 pw.println(" mCommittedState=" + mCommittedState); 818 pw.println(" mPendingState=" + mPendingState); 819 pw.println(" mBaseState=" + mBaseState); 820 pw.println(" mOverrideState=" + getOverrideState()); 821 822 final int processCount = mProcessRecords.size(); 823 pw.println(); 824 pw.println("Registered processes: size=" + processCount); 825 for (int i = 0; i < processCount; i++) { 826 ProcessRecord processRecord = mProcessRecords.valueAt(i); 827 pw.println(" " + i + ": mPid=" + processRecord.mPid); 828 } 829 830 mOverrideRequestController.dumpInternal(pw); 831 } 832 } 833 834 /** 835 * Allow top processes to request or cancel a device state change. If the calling process ID is 836 * not the top app, then check if this process holds the 837 * {@link android.Manifest.permission.CONTROL_DEVICE_STATE} permission. If the calling process 838 * is the top app, check to verify they are requesting a state we've deemed to be able to be 839 * available for an app process to request. States that can be requested are based around 840 * features that we've created that require specific device state overrides. 841 * @param callingPid Process ID that is requesting this state change 842 * @param state state that is being requested. 843 */ assertCanRequestDeviceState(int callingPid, int state)844 private void assertCanRequestDeviceState(int callingPid, int state) { 845 final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp(); 846 if (topApp == null || topApp.getPid() != callingPid 847 || !isStateAvailableForAppRequests(state)) { 848 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 849 "Permission required to request device state, " 850 + "or the call must come from the top app " 851 + "and be a device state that is available for apps to request."); 852 } 853 } 854 855 /** 856 * Checks if the process can control the device state. If the calling process ID is 857 * not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission. 858 * 859 * @param callingPid Process ID that is requesting this state change 860 */ assertCanControlDeviceState(int callingPid)861 private void assertCanControlDeviceState(int callingPid) { 862 final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp(); 863 if (topApp == null || topApp.getPid() != callingPid) { 864 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 865 "Permission required to request device state, " 866 + "or the call must come from the top app."); 867 } 868 } 869 isStateAvailableForAppRequests(int state)870 private boolean isStateAvailableForAppRequests(int state) { 871 synchronized (mLock) { 872 return mDeviceStatesAvailableForAppRequests.contains(state); 873 } 874 } 875 876 /** 877 * Adds device state values that are available to be requested by the top level app. 878 */ 879 @GuardedBy("mLock") readStatesAvailableForRequestFromApps()880 private void readStatesAvailableForRequestFromApps() { 881 mDeviceStatesAvailableForAppRequests = new HashSet<>(); 882 String[] availableAppStatesConfigIdentifiers = getContext().getResources() 883 .getStringArray(R.array.config_deviceStatesAvailableForAppRequests); 884 for (int i = 0; i < availableAppStatesConfigIdentifiers.length; i++) { 885 String identifierToFetch = availableAppStatesConfigIdentifiers[i]; 886 int configValueIdentifier = getContext().getResources() 887 .getIdentifier(identifierToFetch, "integer", "android"); 888 int state = getContext().getResources().getInteger(configValueIdentifier); 889 if (isValidState(state)) { 890 mDeviceStatesAvailableForAppRequests.add(state); 891 } else { 892 Slog.e(TAG, "Invalid device state was found in the configuration file. State id: " 893 + state); 894 } 895 } 896 } 897 readFoldedStates()898 private Set<Integer> readFoldedStates() { 899 Set<Integer> foldedStates = new HashSet(); 900 int[] mFoldedStatesArray = getContext().getResources().getIntArray( 901 com.android.internal.R.array.config_foldedDeviceStates); 902 for (int i = 0; i < mFoldedStatesArray.length; i++) { 903 foldedStates.add(mFoldedStatesArray[i]); 904 } 905 return foldedStates; 906 } 907 908 @GuardedBy("mLock") isValidState(int state)909 private boolean isValidState(int state) { 910 for (int i = 0; i < mDeviceStates.size(); i++) { 911 if (state == mDeviceStates.valueAt(i).getIdentifier()) { 912 return true; 913 } 914 } 915 return false; 916 } 917 918 /** 919 * If the device is being opened, in response to the rear display educational overlay, we should 920 * dismiss the overlay and enter the mode. 921 */ 922 @GuardedBy("mLock") handleRearDisplayBaseStateChangedLocked(int newBaseState)923 private void handleRearDisplayBaseStateChangedLocked(int newBaseState) { 924 if (isDeviceOpeningLocked(newBaseState)) { 925 onStateRequestOverlayDismissedInternal(false); 926 } 927 } 928 929 /** 930 * Determines if the device is being opened and if we are going from a folded state to a 931 * non-folded state. 932 */ 933 @GuardedBy("mLock") isDeviceOpeningLocked(int newBaseState)934 private boolean isDeviceOpeningLocked(int newBaseState) { 935 return mBaseState.filter( 936 deviceState -> mFoldedDeviceStates.contains(deviceState.getIdentifier()) 937 && !mFoldedDeviceStates.contains(newBaseState)).isPresent(); 938 } 939 940 private final class DeviceStateProviderListener implements DeviceStateProvider.Listener { 941 @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int mCurrentBaseState; 942 943 @Override onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates)944 public void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates) { 945 if (newDeviceStates.length == 0) { 946 throw new IllegalArgumentException("Supported device states must not be empty"); 947 } 948 updateSupportedStates(newDeviceStates); 949 } 950 951 @Override onStateChanged( @ntRangefrom = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier)952 public void onStateChanged( 953 @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier) { 954 if (identifier < MINIMUM_DEVICE_STATE || identifier > MAXIMUM_DEVICE_STATE) { 955 throw new IllegalArgumentException("Invalid identifier: " + identifier); 956 } 957 958 mCurrentBaseState = identifier; 959 setBaseState(identifier); 960 } 961 } 962 963 private static final class ProcessRecord implements IBinder.DeathRecipient { 964 public interface DeathListener { onProcessDied(ProcessRecord record)965 void onProcessDied(ProcessRecord record); 966 } 967 968 private static final int STATUS_ACTIVE = 0; 969 970 private static final int STATUS_SUSPENDED = 1; 971 972 private static final int STATUS_CANCELED = 2; 973 974 @IntDef(prefix = {"STATUS_"}, value = { 975 STATUS_ACTIVE, 976 STATUS_SUSPENDED, 977 STATUS_CANCELED 978 }) 979 @Retention(RetentionPolicy.SOURCE) 980 private @interface RequestStatus {} 981 982 private final IDeviceStateManagerCallback mCallback; 983 private final int mPid; 984 private final DeathListener mDeathListener; 985 private final Handler mHandler; 986 987 private final WeakHashMap<IBinder, Integer> mLastNotifiedStatus = new WeakHashMap<>(); 988 ProcessRecord(IDeviceStateManagerCallback callback, int pid, DeathListener deathListener, Handler handler)989 ProcessRecord(IDeviceStateManagerCallback callback, int pid, DeathListener deathListener, 990 Handler handler) { 991 mCallback = callback; 992 mPid = pid; 993 mDeathListener = deathListener; 994 mHandler = handler; 995 } 996 997 @Override binderDied()998 public void binderDied() { 999 mDeathListener.onProcessDied(this); 1000 } 1001 notifyDeviceStateInfoAsync(@onNull DeviceStateInfo info)1002 public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) { 1003 mHandler.post(() -> { 1004 try { 1005 mCallback.onDeviceStateInfoChanged(info); 1006 } catch (RemoteException ex) { 1007 Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.", 1008 ex); 1009 } 1010 }); 1011 } 1012 notifyRequestActiveAsync(IBinder token)1013 public void notifyRequestActiveAsync(IBinder token) { 1014 @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token); 1015 if (lastStatus != null 1016 && (lastStatus == STATUS_ACTIVE || lastStatus == STATUS_CANCELED)) { 1017 return; 1018 } 1019 1020 mLastNotifiedStatus.put(token, STATUS_ACTIVE); 1021 mHandler.post(() -> { 1022 try { 1023 mCallback.onRequestActive(token); 1024 } catch (RemoteException ex) { 1025 Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.", 1026 ex); 1027 } 1028 }); 1029 } 1030 notifyRequestCanceledAsync(IBinder token)1031 public void notifyRequestCanceledAsync(IBinder token) { 1032 @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token); 1033 if (lastStatus != null && lastStatus == STATUS_CANCELED) { 1034 return; 1035 } 1036 1037 mLastNotifiedStatus.put(token, STATUS_CANCELED); 1038 mHandler.post(() -> { 1039 try { 1040 mCallback.onRequestCanceled(token); 1041 } catch (RemoteException ex) { 1042 Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.", 1043 ex); 1044 } 1045 }); 1046 } 1047 } 1048 1049 /** Implementation of {@link IDeviceStateManager} published as a binder service. */ 1050 private final class BinderService extends IDeviceStateManager.Stub { 1051 @Override // Binder call getDeviceStateInfo()1052 public DeviceStateInfo getDeviceStateInfo() { 1053 synchronized (mLock) { 1054 return getDeviceStateInfoLocked(); 1055 } 1056 } 1057 1058 @Override // Binder call registerCallback(IDeviceStateManagerCallback callback)1059 public void registerCallback(IDeviceStateManagerCallback callback) { 1060 if (callback == null) { 1061 throw new IllegalArgumentException("Device state callback must not be null."); 1062 } 1063 1064 final int callingPid = Binder.getCallingPid(); 1065 final long token = Binder.clearCallingIdentity(); 1066 try { 1067 registerProcess(callingPid, callback); 1068 } finally { 1069 Binder.restoreCallingIdentity(token); 1070 } 1071 } 1072 1073 @Override // Binder call requestState(IBinder token, int state, int flags)1074 public void requestState(IBinder token, int state, int flags) { 1075 final int callingPid = Binder.getCallingPid(); 1076 // Allow top processes to request a device state change 1077 // If the calling process ID is not the top app, then we check if this process 1078 // holds a permission to CONTROL_DEVICE_STATE 1079 assertCanRequestDeviceState(callingPid, state); 1080 1081 if (token == null) { 1082 throw new IllegalArgumentException("Request token must not be null."); 1083 } 1084 1085 boolean hasControlStatePermission = getContext().checkCallingOrSelfPermission( 1086 CONTROL_DEVICE_STATE) == PERMISSION_GRANTED; 1087 1088 final long callingIdentity = Binder.clearCallingIdentity(); 1089 try { 1090 requestStateInternal(state, flags, callingPid, token, hasControlStatePermission); 1091 } finally { 1092 Binder.restoreCallingIdentity(callingIdentity); 1093 } 1094 } 1095 1096 @Override // Binder call cancelStateRequest()1097 public void cancelStateRequest() { 1098 final int callingPid = Binder.getCallingPid(); 1099 // Allow top processes to cancel a device state change 1100 // If the calling process ID is not the top app, then we check if this process 1101 // holds a permission to CONTROL_DEVICE_STATE 1102 assertCanControlDeviceState(callingPid); 1103 1104 final long callingIdentity = Binder.clearCallingIdentity(); 1105 try { 1106 cancelStateRequestInternal(callingPid); 1107 } finally { 1108 Binder.restoreCallingIdentity(callingIdentity); 1109 } 1110 } 1111 1112 @Override // Binder call requestBaseStateOverride(IBinder token, int state, int flags)1113 public void requestBaseStateOverride(IBinder token, int state, int flags) { 1114 final int callingPid = Binder.getCallingPid(); 1115 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 1116 "Permission required to control base state of device."); 1117 1118 if (token == null) { 1119 throw new IllegalArgumentException("Request token must not be null."); 1120 } 1121 1122 final long callingIdentity = Binder.clearCallingIdentity(); 1123 try { 1124 requestBaseStateOverrideInternal(state, flags, callingPid, token); 1125 } finally { 1126 Binder.restoreCallingIdentity(callingIdentity); 1127 } 1128 } 1129 1130 @Override // Binder call cancelBaseStateOverride()1131 public void cancelBaseStateOverride() { 1132 final int callingPid = Binder.getCallingPid(); 1133 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 1134 "Permission required to control base state of device."); 1135 1136 final long callingIdentity = Binder.clearCallingIdentity(); 1137 try { 1138 cancelBaseStateOverrideInternal(callingPid); 1139 } finally { 1140 Binder.restoreCallingIdentity(callingIdentity); 1141 } 1142 } 1143 1144 @Override // Binder call onStateRequestOverlayDismissed(boolean shouldCancelRequest)1145 public void onStateRequestOverlayDismissed(boolean shouldCancelRequest) { 1146 1147 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 1148 "CONTROL_DEVICE_STATE permission required to control the state request " 1149 + "overlay"); 1150 1151 final long callingIdentity = Binder.clearCallingIdentity(); 1152 try { 1153 onStateRequestOverlayDismissedInternal(shouldCancelRequest); 1154 } finally { 1155 Binder.restoreCallingIdentity(callingIdentity); 1156 } 1157 } 1158 1159 @Override // Binder call onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver result)1160 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1161 String[] args, ShellCallback callback, ResultReceiver result) { 1162 new DeviceStateManagerShellCommand(DeviceStateManagerService.this) 1163 .exec(this, in, out, err, args, callback, result); 1164 } 1165 1166 @Override // Binder call dump(FileDescriptor fd, final PrintWriter pw, String[] args)1167 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 1168 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; 1169 1170 final long token = Binder.clearCallingIdentity(); 1171 try { 1172 dumpInternal(pw); 1173 } finally { 1174 Binder.restoreCallingIdentity(token); 1175 } 1176 } 1177 } 1178 1179 /** Implementation of {@link DeviceStateManagerInternal} published as a local service. */ 1180 private final class LocalService extends DeviceStateManagerInternal { 1181 @Override getSupportedStateIdentifiers()1182 public int[] getSupportedStateIdentifiers() { 1183 synchronized (mLock) { 1184 return getSupportedStateIdentifiersLocked(); 1185 } 1186 } 1187 } 1188 } 1189