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