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