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.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE; 21 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE; 22 23 import static com.android.server.devicestate.OverrideRequestController.STATUS_ACTIVE; 24 import static com.android.server.devicestate.OverrideRequestController.STATUS_CANCELED; 25 import static com.android.server.devicestate.OverrideRequestController.STATUS_SUSPENDED; 26 27 import android.annotation.IntDef; 28 import android.annotation.IntRange; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.content.Context; 32 import android.hardware.devicestate.DeviceStateInfo; 33 import android.hardware.devicestate.DeviceStateManager; 34 import android.hardware.devicestate.IDeviceStateManager; 35 import android.hardware.devicestate.IDeviceStateManagerCallback; 36 import android.os.Binder; 37 import android.os.Handler; 38 import android.os.IBinder; 39 import android.os.RemoteException; 40 import android.os.ResultReceiver; 41 import android.os.ShellCallback; 42 import android.util.Slog; 43 import android.util.SparseArray; 44 45 import com.android.internal.annotations.GuardedBy; 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.util.DumpUtils; 48 import com.android.internal.util.FrameworkStatsLog; 49 import com.android.server.DisplayThread; 50 import com.android.server.LocalServices; 51 import com.android.server.SystemService; 52 import com.android.server.policy.DeviceStatePolicyImpl; 53 import com.android.server.wm.ActivityTaskManagerInternal; 54 import com.android.server.wm.WindowProcessController; 55 56 import java.io.FileDescriptor; 57 import java.io.PrintWriter; 58 import java.lang.annotation.Retention; 59 import java.lang.annotation.RetentionPolicy; 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.Optional; 63 import java.util.WeakHashMap; 64 65 /** 66 * A system service that manages the state of a device with user-configurable hardware like a 67 * foldable phone. 68 * <p> 69 * Device state is an abstract concept that allows mapping the current state of the device to the 70 * state of the system. For example, system services (like 71 * {@link com.android.server.display.DisplayManagerService display manager} and 72 * {@link com.android.server.wm.WindowManagerService window manager}) and system UI may have 73 * different behaviors depending on the physical state of the device. This is useful for 74 * variable-state devices, like foldable or rollable devices, that can be configured by users into 75 * differing hardware states, which each may have a different expected use case. 76 * </p> 77 * <p> 78 * The {@link DeviceStateManagerService} is responsible for receiving state change requests from 79 * the {@link DeviceStateProvider} to modify the current device state and communicating with the 80 * {@link DeviceStatePolicy policy} to ensure the system is configured to match the requested state. 81 * </p> 82 * The service also provides the {@link DeviceStateManager} API allowing clients to listen for 83 * changes in device state and submit requests to override the device state provided by the 84 * {@link DeviceStateProvider}. 85 * 86 * @see DeviceStatePolicy 87 * @see DeviceStateManager 88 */ 89 public final class DeviceStateManagerService extends SystemService { 90 private static final String TAG = "DeviceStateManagerService"; 91 private static final boolean DEBUG = false; 92 93 private final Object mLock = new Object(); 94 // Handler on the {@link DisplayThread} used to dispatch calls to the policy and to registered 95 // callbacks though its handler (mHandler). Provides a guarantee of callback order when 96 // leveraging mHandler and also enables posting messages with the service lock held. 97 private final Handler mHandler; 98 @NonNull 99 private final DeviceStatePolicy mDeviceStatePolicy; 100 @NonNull 101 private final BinderService mBinderService; 102 @NonNull 103 private final OverrideRequestController mOverrideRequestController; 104 @VisibleForTesting 105 @NonNull 106 public ActivityTaskManagerInternal mActivityTaskManagerInternal; 107 108 // All supported device states keyed by identifier. 109 @GuardedBy("mLock") 110 private SparseArray<DeviceState> mDeviceStates = new SparseArray<>(); 111 112 // The current committed device state. Will be empty until the first device state provided by 113 // the DeviceStateProvider is committed. 114 @GuardedBy("mLock") 115 @NonNull 116 private Optional<DeviceState> mCommittedState = Optional.empty(); 117 // The device state that is currently awaiting callback from the policy to be committed. 118 @GuardedBy("mLock") 119 @NonNull 120 private Optional<DeviceState> mPendingState = Optional.empty(); 121 // Whether or not the policy is currently waiting to be notified of the current pending state. 122 @GuardedBy("mLock") 123 private boolean mIsPolicyWaitingForState = false; 124 125 // The device state that is set by the DeviceStateProvider. Will be empty until the first 126 // callback from the provider and then will always contain the most recent value. 127 @GuardedBy("mLock") 128 @NonNull 129 private Optional<DeviceState> mBaseState = Optional.empty(); 130 131 // The current active override request. When set the device state specified here will take 132 // precedence over mBaseState. 133 @GuardedBy("mLock") 134 @NonNull 135 private Optional<OverrideRequest> mActiveOverride = Optional.empty(); 136 137 // List of processes registered to receive notifications about changes to device state and 138 // request status indexed by process id. 139 @GuardedBy("mLock") 140 private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>(); 141 DeviceStateManagerService(@onNull Context context)142 public DeviceStateManagerService(@NonNull Context context) { 143 this(context, new DeviceStatePolicyImpl(context)); 144 } 145 146 @VisibleForTesting DeviceStateManagerService(@onNull Context context, @NonNull DeviceStatePolicy policy)147 DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) { 148 super(context); 149 // We use the DisplayThread because this service indirectly drives 150 // display (on/off) and window (position) events through its callbacks. 151 DisplayThread displayThread = DisplayThread.get(); 152 mHandler = new Handler(displayThread.getLooper()); 153 mOverrideRequestController = new OverrideRequestController( 154 this::onOverrideRequestStatusChangedLocked); 155 mDeviceStatePolicy = policy; 156 mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener()); 157 mBinderService = new BinderService(); 158 mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); 159 } 160 161 @Override onStart()162 public void onStart() { 163 publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService); 164 } 165 166 @VisibleForTesting getHandler()167 Handler getHandler() { 168 return mHandler; 169 } 170 171 /** 172 * Returns the current state the system is in. Note that the system may be in the process of 173 * configuring a different state. 174 * <p> 175 * Note: This method will return {@link Optional#empty()} if called before the first state has 176 * been committed, otherwise it will return the last committed state. 177 * 178 * @see #getPendingState() 179 */ 180 @NonNull getCommittedState()181 Optional<DeviceState> getCommittedState() { 182 synchronized (mLock) { 183 return mCommittedState; 184 } 185 } 186 187 /** 188 * Returns the state the system is currently configuring, or {@link Optional#empty()} if the 189 * system is not in the process of configuring a state. 190 */ 191 @VisibleForTesting 192 @NonNull getPendingState()193 Optional<DeviceState> getPendingState() { 194 synchronized (mLock) { 195 return mPendingState; 196 } 197 } 198 199 /** 200 * Returns the base state. The service will configure the device to match the base state when 201 * there is no active request to override the base state. 202 * <p> 203 * Note: This method will return {@link Optional#empty()} if called before a base state is 204 * provided to the service by the {@link DeviceStateProvider}, otherwise it will return the 205 * most recent provided value. 206 * 207 * @see #getOverrideState() 208 */ 209 @NonNull getBaseState()210 Optional<DeviceState> getBaseState() { 211 synchronized (mLock) { 212 return mBaseState; 213 } 214 } 215 216 /** 217 * Returns the current override state, or {@link Optional#empty()} if no override state is 218 * requested. If an override states is present, the returned state will take precedence over 219 * the base state returned from {@link #getBaseState()}. 220 */ 221 @NonNull getOverrideState()222 Optional<DeviceState> getOverrideState() { 223 synchronized (mLock) { 224 if (mActiveOverride.isPresent()) { 225 return getStateLocked(mActiveOverride.get().getRequestedState()); 226 } 227 return Optional.empty(); 228 } 229 } 230 231 /** Returns the list of currently supported device states. */ getSupportedStates()232 DeviceState[] getSupportedStates() { 233 synchronized (mLock) { 234 DeviceState[] supportedStates = new DeviceState[mDeviceStates.size()]; 235 for (int i = 0; i < supportedStates.length; i++) { 236 supportedStates[i] = mDeviceStates.valueAt(i); 237 } 238 return supportedStates; 239 } 240 } 241 242 /** Returns the list of currently supported device state identifiers. */ getSupportedStateIdentifiers()243 private int[] getSupportedStateIdentifiers() { 244 synchronized (mLock) { 245 return getSupportedStateIdentifiersLocked(); 246 } 247 } 248 249 /** Returns the list of currently supported device state identifiers. */ getSupportedStateIdentifiersLocked()250 private int[] getSupportedStateIdentifiersLocked() { 251 int[] supportedStates = new int[mDeviceStates.size()]; 252 for (int i = 0; i < supportedStates.length; i++) { 253 supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier(); 254 } 255 return supportedStates; 256 } 257 258 @NonNull getDeviceStateInfoLocked()259 private DeviceStateInfo getDeviceStateInfoLocked() { 260 if (!mBaseState.isPresent() || !mCommittedState.isPresent()) { 261 throw new IllegalStateException("Trying to get the current DeviceStateInfo before the" 262 + " initial state has been committed."); 263 } 264 265 final int[] supportedStates = getSupportedStateIdentifiersLocked(); 266 final int baseState = mBaseState.get().getIdentifier(); 267 final int currentState = mCommittedState.get().getIdentifier(); 268 269 return new DeviceStateInfo(supportedStates, baseState, currentState); 270 } 271 272 @VisibleForTesting getBinderService()273 IDeviceStateManager getBinderService() { 274 return mBinderService; 275 } 276 updateSupportedStates(DeviceState[] supportedDeviceStates)277 private void updateSupportedStates(DeviceState[] supportedDeviceStates) { 278 synchronized (mLock) { 279 final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked(); 280 281 // Whether or not at least one device state has the flag FLAG_CANCEL_STICKY_REQUESTS 282 // set. If set to true, the OverrideRequestController will be configured to allow sticky 283 // requests. 284 boolean hasTerminalDeviceState = false; 285 mDeviceStates.clear(); 286 for (int i = 0; i < supportedDeviceStates.length; i++) { 287 DeviceState state = supportedDeviceStates[i]; 288 if ((state.getFlags() & DeviceState.FLAG_CANCEL_STICKY_REQUESTS) != 0) { 289 hasTerminalDeviceState = true; 290 } 291 mDeviceStates.put(state.getIdentifier(), state); 292 } 293 294 mOverrideRequestController.setStickyRequestsAllowed(hasTerminalDeviceState); 295 296 final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked(); 297 if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) { 298 return; 299 } 300 301 mOverrideRequestController.handleNewSupportedStates(newStateIdentifiers); 302 updatePendingStateLocked(); 303 304 if (!mPendingState.isPresent()) { 305 // If the change in the supported states didn't result in a change of the pending 306 // state commitPendingState() will never be called and the callbacks will never be 307 // notified of the change. 308 notifyDeviceStateInfoChangedAsync(); 309 } 310 311 mHandler.post(this::notifyPolicyIfNeeded); 312 } 313 } 314 315 /** 316 * Returns {@code true} if the provided state is supported. Requires that 317 * {@link #mDeviceStates} is sorted prior to calling. 318 */ isSupportedStateLocked(int identifier)319 private boolean isSupportedStateLocked(int identifier) { 320 return mDeviceStates.contains(identifier); 321 } 322 323 /** 324 * Returns the {@link DeviceState} with the supplied {@code identifier}, or {@code null} if 325 * there is no device state with the identifier. 326 */ 327 @Nullable getStateLocked(int identifier)328 private Optional<DeviceState> getStateLocked(int identifier) { 329 return Optional.ofNullable(mDeviceStates.get(identifier)); 330 } 331 332 /** 333 * Sets the base state. 334 * 335 * @throws IllegalArgumentException if the {@code identifier} is not a supported state. 336 * 337 * @see #isSupportedStateLocked(int) 338 */ setBaseState(int identifier)339 private void setBaseState(int identifier) { 340 synchronized (mLock) { 341 final Optional<DeviceState> baseStateOptional = getStateLocked(identifier); 342 if (!baseStateOptional.isPresent()) { 343 throw new IllegalArgumentException("Base state is not supported"); 344 } 345 346 final DeviceState baseState = baseStateOptional.get(); 347 if (mBaseState.isPresent() && mBaseState.get().equals(baseState)) { 348 // Base state hasn't changed. Nothing to do. 349 return; 350 } 351 mBaseState = Optional.of(baseState); 352 353 if ((baseState.getFlags() & DeviceState.FLAG_CANCEL_STICKY_REQUESTS) != 0) { 354 mOverrideRequestController.cancelStickyRequests(); 355 } 356 mOverrideRequestController.handleBaseStateChanged(); 357 updatePendingStateLocked(); 358 359 if (!mPendingState.isPresent()) { 360 // If the change in base state didn't result in a change of the pending state 361 // commitPendingState() will never be called and the callbacks will never be 362 // notified of the change. 363 notifyDeviceStateInfoChangedAsync(); 364 } 365 366 mHandler.post(this::notifyPolicyIfNeeded); 367 } 368 } 369 370 /** 371 * Tries to update the current pending state with the current requested state. Must call 372 * {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being 373 * changed. 374 * 375 * @return {@code true} if the pending state has changed as a result of this call, {@code false} 376 * otherwise. 377 */ updatePendingStateLocked()378 private boolean updatePendingStateLocked() { 379 if (mPendingState.isPresent()) { 380 // Have pending state, can not configure a new state until the state is committed. 381 return false; 382 } 383 384 final DeviceState stateToConfigure; 385 if (mActiveOverride.isPresent()) { 386 stateToConfigure = getStateLocked(mActiveOverride.get().getRequestedState()).get(); 387 } else if (mBaseState.isPresent() 388 && isSupportedStateLocked(mBaseState.get().getIdentifier())) { 389 // Base state could have recently become unsupported after a change in supported states. 390 stateToConfigure = mBaseState.get(); 391 } else { 392 stateToConfigure = null; 393 } 394 395 if (stateToConfigure == null) { 396 // No currently requested state. 397 return false; 398 } 399 400 if (mCommittedState.isPresent() && stateToConfigure.equals(mCommittedState.get())) { 401 // The state requesting to be committed already matches the current committed state. 402 return false; 403 } 404 405 mPendingState = Optional.of(stateToConfigure); 406 mIsPolicyWaitingForState = true; 407 return true; 408 } 409 410 /** 411 * Notifies the policy to configure the supplied state. Should not be called with {@link #mLock} 412 * held. 413 */ notifyPolicyIfNeeded()414 private void notifyPolicyIfNeeded() { 415 if (Thread.holdsLock(mLock)) { 416 Throwable error = new Throwable("Attempting to notify DeviceStatePolicy with service" 417 + " lock held"); 418 error.fillInStackTrace(); 419 Slog.w(TAG, error); 420 } 421 int state; 422 synchronized (mLock) { 423 if (!mIsPolicyWaitingForState) { 424 return; 425 } 426 mIsPolicyWaitingForState = false; 427 state = mPendingState.get().getIdentifier(); 428 } 429 430 if (DEBUG) { 431 Slog.d(TAG, "Notifying policy to configure state: " + state); 432 } 433 mDeviceStatePolicy.configureDeviceForState(state, this::commitPendingState); 434 } 435 436 /** 437 * Commits the current pending state after a callback from the {@link DeviceStatePolicy}. 438 * 439 * <pre> 440 * ------------- ----------- ------------- 441 * Provider -> | Requested | -> | Pending | -> Policy -> | Committed | 442 * ------------- ----------- ------------- 443 * </pre> 444 * <p> 445 * When a new state is requested it immediately enters the requested state. Once the policy is 446 * available to accept a new state, which could also be immediately if there is no current 447 * pending state at the point of request, the policy is notified and a callback is provided to 448 * trigger the state to be committed. 449 * </p> 450 */ commitPendingState()451 private void commitPendingState() { 452 synchronized (mLock) { 453 final DeviceState newState = mPendingState.get(); 454 if (DEBUG) { 455 Slog.d(TAG, "Committing state: " + newState); 456 } 457 458 FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_STATE_CHANGED, 459 newState.getIdentifier(), !mCommittedState.isPresent()); 460 461 mCommittedState = Optional.of(newState); 462 mPendingState = Optional.empty(); 463 updatePendingStateLocked(); 464 465 // Notify callbacks of a change. 466 notifyDeviceStateInfoChangedAsync(); 467 468 // The top request could have come in while the service was awaiting callback 469 // from the policy. In that case we only set it to active if it matches the 470 // current committed state, otherwise it will be set to active when its 471 // requested state is committed. 472 OverrideRequest activeRequest = mActiveOverride.orElse(null); 473 if (activeRequest != null 474 && activeRequest.getRequestedState() == newState.getIdentifier()) { 475 ProcessRecord processRecord = mProcessRecords.get(activeRequest.getPid()); 476 if (processRecord != null) { 477 processRecord.notifyRequestActiveAsync(activeRequest.getToken()); 478 } 479 } 480 481 // Try to configure the next state if needed. 482 mHandler.post(this::notifyPolicyIfNeeded); 483 } 484 } 485 notifyDeviceStateInfoChangedAsync()486 private void notifyDeviceStateInfoChangedAsync() { 487 synchronized (mLock) { 488 if (mProcessRecords.size() == 0) { 489 return; 490 } 491 492 ArrayList<ProcessRecord> registeredProcesses = new ArrayList<>(); 493 for (int i = 0; i < mProcessRecords.size(); i++) { 494 registeredProcesses.add(mProcessRecords.valueAt(i)); 495 } 496 497 DeviceStateInfo info = getDeviceStateInfoLocked(); 498 499 for (int i = 0; i < registeredProcesses.size(); i++) { 500 registeredProcesses.get(i).notifyDeviceStateInfoAsync(info); 501 } 502 } 503 } 504 onOverrideRequestStatusChangedLocked(@onNull OverrideRequest request, @OverrideRequestController.RequestStatus int status)505 private void onOverrideRequestStatusChangedLocked(@NonNull OverrideRequest request, 506 @OverrideRequestController.RequestStatus int status) { 507 if (status == STATUS_ACTIVE) { 508 mActiveOverride = Optional.of(request); 509 } else if (status == STATUS_SUSPENDED || status == STATUS_CANCELED) { 510 if (mActiveOverride.isPresent() && mActiveOverride.get() == request) { 511 mActiveOverride = Optional.empty(); 512 } 513 } else { 514 throw new IllegalArgumentException("Unknown request status: " + status); 515 } 516 517 boolean updatedPendingState = updatePendingStateLocked(); 518 519 ProcessRecord processRecord = mProcessRecords.get(request.getPid()); 520 if (processRecord == null) { 521 // If the process is no longer registered with the service, for example if it has died, 522 // there is no need to notify it of a change in request status. 523 mHandler.post(this::notifyPolicyIfNeeded); 524 return; 525 } 526 527 if (status == STATUS_ACTIVE) { 528 if (!updatedPendingState && !mPendingState.isPresent()) { 529 // If the pending state was not updated and there is not currently a pending state 530 // then this newly active request will never be notified of a change in state. 531 // Schedule the notification now. 532 processRecord.notifyRequestActiveAsync(request.getToken()); 533 } 534 } else if (status == STATUS_SUSPENDED) { 535 processRecord.notifyRequestSuspendedAsync(request.getToken()); 536 } else { 537 processRecord.notifyRequestCanceledAsync(request.getToken()); 538 } 539 540 mHandler.post(this::notifyPolicyIfNeeded); 541 } 542 registerProcess(int pid, IDeviceStateManagerCallback callback)543 private void registerProcess(int pid, IDeviceStateManagerCallback callback) { 544 synchronized (mLock) { 545 if (mProcessRecords.contains(pid)) { 546 throw new SecurityException("The calling process has already registered an" 547 + " IDeviceStateManagerCallback."); 548 } 549 550 ProcessRecord record = new ProcessRecord(callback, pid, this::handleProcessDied, 551 mHandler); 552 try { 553 callback.asBinder().linkToDeath(record, 0); 554 } catch (RemoteException ex) { 555 throw new RuntimeException(ex); 556 } 557 mProcessRecords.put(pid, record); 558 559 DeviceStateInfo currentInfo = mCommittedState.isPresent() 560 ? getDeviceStateInfoLocked() : null; 561 if (currentInfo != null) { 562 // If there is not a committed state we'll wait to notify the process of the initial 563 // value. 564 record.notifyDeviceStateInfoAsync(currentInfo); 565 } 566 } 567 } 568 handleProcessDied(ProcessRecord processRecord)569 private void handleProcessDied(ProcessRecord processRecord) { 570 synchronized (mLock) { 571 mProcessRecords.remove(processRecord.mPid); 572 mOverrideRequestController.handleProcessDied(processRecord.mPid); 573 } 574 } 575 requestStateInternal(int state, int flags, int callingPid, @NonNull IBinder token)576 private void requestStateInternal(int state, int flags, int callingPid, 577 @NonNull IBinder token) { 578 synchronized (mLock) { 579 final ProcessRecord processRecord = mProcessRecords.get(callingPid); 580 if (processRecord == null) { 581 throw new IllegalStateException("Process " + callingPid 582 + " has no registered callback."); 583 } 584 585 if (mOverrideRequestController.hasRequest(token)) { 586 throw new IllegalStateException("Request has already been made for the supplied" 587 + " token: " + token); 588 } 589 590 final Optional<DeviceState> deviceState = getStateLocked(state); 591 if (!deviceState.isPresent()) { 592 throw new IllegalArgumentException("Requested state: " + state 593 + " is not supported."); 594 } 595 596 OverrideRequest request = new OverrideRequest(token, callingPid, state, flags); 597 mOverrideRequestController.addRequest(request); 598 } 599 } 600 cancelRequestInternal(int callingPid, @NonNull IBinder token)601 private void cancelRequestInternal(int callingPid, @NonNull IBinder token) { 602 synchronized (mLock) { 603 final ProcessRecord processRecord = mProcessRecords.get(callingPid); 604 if (processRecord == null) { 605 throw new IllegalStateException("Process " + callingPid 606 + " has no registered callback."); 607 } 608 609 mOverrideRequestController.cancelRequest(token); 610 } 611 } 612 dumpInternal(PrintWriter pw)613 private void dumpInternal(PrintWriter pw) { 614 pw.println("DEVICE STATE MANAGER (dumpsys device_state)"); 615 616 synchronized (mLock) { 617 pw.println(" mCommittedState=" + mCommittedState); 618 pw.println(" mPendingState=" + mPendingState); 619 pw.println(" mBaseState=" + mBaseState); 620 pw.println(" mOverrideState=" + getOverrideState()); 621 622 final int processCount = mProcessRecords.size(); 623 pw.println(); 624 pw.println("Registered processes: size=" + processCount); 625 for (int i = 0; i < processCount; i++) { 626 ProcessRecord processRecord = mProcessRecords.valueAt(i); 627 pw.println(" " + i + ": mPid=" + processRecord.mPid); 628 } 629 630 mOverrideRequestController.dumpInternal(pw); 631 } 632 } 633 634 private final class DeviceStateProviderListener implements DeviceStateProvider.Listener { 635 @Override onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates)636 public void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates) { 637 if (newDeviceStates.length == 0) { 638 throw new IllegalArgumentException("Supported device states must not be empty"); 639 } 640 updateSupportedStates(newDeviceStates); 641 } 642 643 @Override onStateChanged( @ntRangefrom = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier)644 public void onStateChanged( 645 @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier) { 646 if (identifier < MINIMUM_DEVICE_STATE || identifier > MAXIMUM_DEVICE_STATE) { 647 throw new IllegalArgumentException("Invalid identifier: " + identifier); 648 } 649 650 setBaseState(identifier); 651 } 652 } 653 654 private static final class ProcessRecord implements IBinder.DeathRecipient { 655 public interface DeathListener { onProcessDied(ProcessRecord record)656 void onProcessDied(ProcessRecord record); 657 } 658 659 private static final int STATUS_ACTIVE = 0; 660 661 private static final int STATUS_SUSPENDED = 1; 662 663 private static final int STATUS_CANCELED = 2; 664 665 @IntDef(prefix = {"STATUS_"}, value = { 666 STATUS_ACTIVE, 667 STATUS_SUSPENDED, 668 STATUS_CANCELED 669 }) 670 @Retention(RetentionPolicy.SOURCE) 671 private @interface RequestStatus {} 672 673 private final IDeviceStateManagerCallback mCallback; 674 private final int mPid; 675 private final DeathListener mDeathListener; 676 private final Handler mHandler; 677 678 private final WeakHashMap<IBinder, Integer> mLastNotifiedStatus = new WeakHashMap<>(); 679 ProcessRecord(IDeviceStateManagerCallback callback, int pid, DeathListener deathListener, Handler handler)680 ProcessRecord(IDeviceStateManagerCallback callback, int pid, DeathListener deathListener, 681 Handler handler) { 682 mCallback = callback; 683 mPid = pid; 684 mDeathListener = deathListener; 685 mHandler = handler; 686 } 687 688 @Override binderDied()689 public void binderDied() { 690 mDeathListener.onProcessDied(this); 691 } 692 notifyDeviceStateInfoAsync(@onNull DeviceStateInfo info)693 public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) { 694 mHandler.post(() -> { 695 try { 696 mCallback.onDeviceStateInfoChanged(info); 697 } catch (RemoteException ex) { 698 Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.", 699 ex); 700 } 701 }); 702 } 703 notifyRequestActiveAsync(IBinder token)704 public void notifyRequestActiveAsync(IBinder token) { 705 @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token); 706 if (lastStatus != null 707 && (lastStatus == STATUS_ACTIVE || lastStatus == STATUS_CANCELED)) { 708 return; 709 } 710 711 mLastNotifiedStatus.put(token, STATUS_ACTIVE); 712 mHandler.post(() -> { 713 try { 714 mCallback.onRequestActive(token); 715 } catch (RemoteException ex) { 716 Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.", 717 ex); 718 } 719 }); 720 } 721 notifyRequestSuspendedAsync(IBinder token)722 public void notifyRequestSuspendedAsync(IBinder token) { 723 @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token); 724 if (lastStatus != null 725 && (lastStatus == STATUS_SUSPENDED || lastStatus == STATUS_CANCELED)) { 726 return; 727 } 728 729 mLastNotifiedStatus.put(token, STATUS_SUSPENDED); 730 mHandler.post(() -> { 731 try { 732 mCallback.onRequestSuspended(token); 733 } catch (RemoteException ex) { 734 Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.", 735 ex); 736 } 737 }); 738 } 739 notifyRequestCanceledAsync(IBinder token)740 public void notifyRequestCanceledAsync(IBinder token) { 741 @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token); 742 if (lastStatus != null && lastStatus == STATUS_CANCELED) { 743 return; 744 } 745 746 mLastNotifiedStatus.put(token, STATUS_CANCELED); 747 mHandler.post(() -> { 748 try { 749 mCallback.onRequestCanceled(token); 750 } catch (RemoteException ex) { 751 Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.", 752 ex); 753 } 754 }); 755 } 756 } 757 758 /** Implementation of {@link IDeviceStateManager} published as a binder service. */ 759 private final class BinderService extends IDeviceStateManager.Stub { 760 @Override // Binder call getDeviceStateInfo()761 public DeviceStateInfo getDeviceStateInfo() { 762 synchronized (mLock) { 763 return getDeviceStateInfoLocked(); 764 } 765 } 766 767 @Override // Binder call registerCallback(IDeviceStateManagerCallback callback)768 public void registerCallback(IDeviceStateManagerCallback callback) { 769 if (callback == null) { 770 throw new IllegalArgumentException("Device state callback must not be null."); 771 } 772 773 final int callingPid = Binder.getCallingPid(); 774 final long token = Binder.clearCallingIdentity(); 775 try { 776 registerProcess(callingPid, callback); 777 } finally { 778 Binder.restoreCallingIdentity(token); 779 } 780 } 781 782 @Override // Binder call requestState(IBinder token, int state, int flags)783 public void requestState(IBinder token, int state, int flags) { 784 final int callingPid = Binder.getCallingPid(); 785 // Allow top processes to request a device state change 786 // If the calling process ID is not the top app, then we check if this process 787 // holds a permission to CONTROL_DEVICE_STATE 788 final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp(); 789 if (topApp.getPid() != callingPid) { 790 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 791 "Permission required to request device state, " 792 + "or the call must come from the top focused app."); 793 } 794 795 if (token == null) { 796 throw new IllegalArgumentException("Request token must not be null."); 797 } 798 799 final long callingIdentity = Binder.clearCallingIdentity(); 800 try { 801 requestStateInternal(state, flags, callingPid, token); 802 } finally { 803 Binder.restoreCallingIdentity(callingIdentity); 804 } 805 } 806 807 @Override // Binder call cancelRequest(IBinder token)808 public void cancelRequest(IBinder token) { 809 final int callingPid = Binder.getCallingPid(); 810 // Allow top processes to cancel a device state change 811 // If the calling process ID is not the top app, then we check if this process 812 // holds a permission to CONTROL_DEVICE_STATE 813 final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp(); 814 if (topApp.getPid() != callingPid) { 815 getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, 816 "Permission required to cancel device state, " 817 + "or the call must come from the top focused app."); 818 } 819 820 if (token == null) { 821 throw new IllegalArgumentException("Request token must not be null."); 822 } 823 824 final long callingIdentity = Binder.clearCallingIdentity(); 825 try { 826 cancelRequestInternal(callingPid, token); 827 } finally { 828 Binder.restoreCallingIdentity(callingIdentity); 829 } 830 } 831 832 @Override // Binder call onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver result)833 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 834 String[] args, ShellCallback callback, ResultReceiver result) { 835 new DeviceStateManagerShellCommand(DeviceStateManagerService.this) 836 .exec(this, in, out, err, args, callback, result); 837 } 838 839 @Override // Binder call dump(FileDescriptor fd, final PrintWriter pw, String[] args)840 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 841 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; 842 843 final long token = Binder.clearCallingIdentity(); 844 try { 845 dumpInternal(pw); 846 } finally { 847 Binder.restoreCallingIdentity(token); 848 } 849 } 850 } 851 } 852