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