1 /*
2  * Copyright (C) 2023 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.companion.virtual;
18 
19 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_ENABLED;
20 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY;
21 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY;
22 import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED;
23 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
24 import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
25 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
26 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
27 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
28 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD;
29 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
30 import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
31 import static android.companion.virtualdevice.flags.Flags.virtualCameraServiceDiscovery;
32 import static android.companion.virtualdevice.flags.Flags.intentInterceptionActionMatchingFix;
33 
34 import android.annotation.EnforcePermission;
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.annotation.RequiresPermission;
38 import android.annotation.StringRes;
39 import android.annotation.UserIdInt;
40 import android.app.Activity;
41 import android.app.ActivityOptions;
42 import android.app.PendingIntent;
43 import android.app.admin.DevicePolicyManager;
44 import android.companion.AssociationInfo;
45 import android.companion.virtual.IVirtualDevice;
46 import android.companion.virtual.IVirtualDeviceActivityListener;
47 import android.companion.virtual.IVirtualDeviceIntentInterceptor;
48 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
49 import android.companion.virtual.VirtualDevice;
50 import android.companion.virtual.VirtualDeviceManager;
51 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
52 import android.companion.virtual.VirtualDeviceParams;
53 import android.companion.virtual.audio.IAudioConfigChangedCallback;
54 import android.companion.virtual.audio.IAudioRoutingCallback;
55 import android.companion.virtual.camera.VirtualCameraConfig;
56 import android.companion.virtual.flags.Flags;
57 import android.companion.virtual.sensor.VirtualSensor;
58 import android.companion.virtual.sensor.VirtualSensorEvent;
59 import android.content.AttributionSource;
60 import android.content.ComponentName;
61 import android.content.Context;
62 import android.content.Intent;
63 import android.content.IntentFilter;
64 import android.content.pm.ActivityInfo;
65 import android.content.pm.PackageManager;
66 import android.graphics.PointF;
67 import android.hardware.display.DisplayManager;
68 import android.hardware.display.DisplayManagerGlobal;
69 import android.hardware.display.DisplayManagerInternal;
70 import android.hardware.display.IVirtualDisplayCallback;
71 import android.hardware.display.VirtualDisplayConfig;
72 import android.hardware.input.VirtualDpadConfig;
73 import android.hardware.input.VirtualKeyEvent;
74 import android.hardware.input.VirtualKeyboardConfig;
75 import android.hardware.input.VirtualMouseButtonEvent;
76 import android.hardware.input.VirtualMouseConfig;
77 import android.hardware.input.VirtualMouseRelativeEvent;
78 import android.hardware.input.VirtualMouseScrollEvent;
79 import android.hardware.input.VirtualNavigationTouchpadConfig;
80 import android.hardware.input.VirtualStylusButtonEvent;
81 import android.hardware.input.VirtualStylusConfig;
82 import android.hardware.input.VirtualStylusMotionEvent;
83 import android.hardware.input.VirtualTouchEvent;
84 import android.hardware.input.VirtualTouchscreenConfig;
85 import android.media.AudioManager;
86 import android.media.audiopolicy.AudioMix;
87 import android.os.Binder;
88 import android.os.IBinder;
89 import android.os.LocaleList;
90 import android.os.Looper;
91 import android.os.PermissionEnforcer;
92 import android.os.PowerManager;
93 import android.os.RemoteException;
94 import android.os.ResultReceiver;
95 import android.os.UserHandle;
96 import android.os.UserManager;
97 import android.util.ArrayMap;
98 import android.util.ArraySet;
99 import android.util.IntArray;
100 import android.util.Slog;
101 import android.util.SparseArray;
102 import android.util.SparseIntArray;
103 import android.view.Display;
104 import android.view.WindowManager;
105 import android.widget.Toast;
106 
107 import com.android.internal.annotations.GuardedBy;
108 import com.android.internal.annotations.VisibleForTesting;
109 import com.android.internal.app.BlockedAppStreamingActivity;
110 import com.android.modules.expresslog.Counter;
111 import com.android.server.LocalServices;
112 import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
113 import com.android.server.companion.virtual.audio.VirtualAudioController;
114 import com.android.server.companion.virtual.camera.VirtualCameraController;
115 import com.android.server.inputmethod.InputMethodManagerInternal;
116 
117 import dalvik.annotation.optimization.FastNative;
118 
119 import java.io.FileDescriptor;
120 import java.io.PrintWriter;
121 import java.util.List;
122 import java.util.Map;
123 import java.util.Objects;
124 import java.util.Set;
125 import java.util.function.Consumer;
126 
127 final class VirtualDeviceImpl extends IVirtualDevice.Stub
128         implements IBinder.DeathRecipient, RunningAppsChangedListener {
129 
130     private static final String TAG = "VirtualDeviceImpl";
131 
132     private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
133             DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED
134                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
135                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
136                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
137 
138     private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS_PRE_VIC =
139             DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
140                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
141                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
142 
143     private static final String PERSISTENT_ID_PREFIX_CDM_ASSOCIATION = "companion:";
144 
145     /**
146      * Timeout until {@link #launchPendingIntent} stops waiting for an activity to be launched.
147      */
148     private static final long PENDING_TRAMPOLINE_TIMEOUT_MS = 5000;
149 
150     private final Object mVirtualDeviceLock = new Object();
151 
152     private final int mBaseVirtualDisplayFlags;
153 
154     private final Context mContext;
155     private final AssociationInfo mAssociationInfo;
156     private final VirtualDeviceManagerService mService;
157     private final PendingTrampolineCallback mPendingTrampolineCallback;
158     private final int mOwnerUid;
159     private final VirtualDeviceLog mVirtualDeviceLog;
160     private final String mOwnerPackageName;
161     @NonNull
162     private final AttributionSource mAttributionSource;
163     private final int mDeviceId;
164     @Nullable
165     private final String mPersistentDeviceId;
166     // Thou shall not hold the mVirtualDeviceLock over the mInputController calls.
167     // Holding the lock can lead to lock inversion with GlobalWindowManagerLock.
168     // 1. After display is created the window manager calls into VDM during construction
169     //   of display specific context to fetch device id corresponding to the display.
170     //   mVirtualDeviceLock will be held while this is done.
171     // 2. InputController interactions result in calls to DisplayManager (to set IME,
172     //    possibly more indirect calls), and those attempt to lock GlobalWindowManagerLock which
173     //    creates lock inversion.
174     private final InputController mInputController;
175     private final SensorController mSensorController;
176     private final CameraAccessController mCameraAccessController;
177     @Nullable // Null if virtual camera flag is off.
178     private final VirtualCameraController mVirtualCameraController;
179     private VirtualAudioController mVirtualAudioController;
180     private final IBinder mAppToken;
181     private final VirtualDeviceParams mParams;
182     @GuardedBy("mVirtualDeviceLock")
183     private final SparseIntArray mDevicePolicies;
184     @GuardedBy("mVirtualDeviceLock")
185     private final SparseArray<VirtualDisplayWrapper> mVirtualDisplays = new SparseArray<>();
186     private final IVirtualDeviceActivityListener mActivityListener;
187     private final IVirtualDeviceSoundEffectListener mSoundEffectListener;
188     private final DisplayManagerGlobal mDisplayManager;
189     private final DisplayManagerInternal mDisplayManagerInternal;
190     @GuardedBy("mVirtualDeviceLock")
191     private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>();
192     @NonNull
193     private final Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
194     // The default setting for showing the pointer on new displays.
195     @GuardedBy("mVirtualDeviceLock")
196     private boolean mDefaultShowPointerIcon = true;
197     @GuardedBy("mVirtualDeviceLock")
198     @Nullable
199     private LocaleList mLocaleList = null;
200 
201     @NonNull
202     private final VirtualDevice mPublicVirtualDeviceObject;
203 
204     @GuardedBy("mVirtualDeviceLock")
205     @NonNull
206     private final Set<ComponentName> mActivityPolicyExemptions;
207     private final ComponentName mPermissionDialogComponent;
208 
createListenerAdapter()209     private ActivityListener createListenerAdapter() {
210         return new ActivityListener() {
211 
212             @Override
213             public void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity) {
214                 try {
215                     mActivityListener.onTopActivityChanged(displayId, topActivity,
216                             UserHandle.USER_NULL);
217                 } catch (RemoteException e) {
218                     Slog.w(TAG, "Unable to call mActivityListener for display: " + displayId, e);
219                 }
220             }
221 
222             @Override
223             public void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity,
224                     @UserIdInt int userId) {
225                 try {
226                     mActivityListener.onTopActivityChanged(displayId, topActivity, userId);
227                 } catch (RemoteException e) {
228                     Slog.w(TAG, "Unable to call mActivityListener for display: " + displayId, e);
229                 }
230             }
231 
232             @Override
233             public void onDisplayEmpty(int displayId) {
234                 try {
235                     mActivityListener.onDisplayEmpty(displayId);
236                 } catch (RemoteException e) {
237                     Slog.w(TAG, "Unable to call mActivityListener for display: " + displayId, e);
238                 }
239             }
240         };
241     }
242 
243     VirtualDeviceImpl(
244             Context context,
245             AssociationInfo associationInfo,
246             VirtualDeviceManagerService service,
247             VirtualDeviceLog virtualDeviceLog,
248             IBinder token,
249             AttributionSource attributionSource,
250             int deviceId,
251             CameraAccessController cameraAccessController,
252             PendingTrampolineCallback pendingTrampolineCallback,
253             IVirtualDeviceActivityListener activityListener,
254             IVirtualDeviceSoundEffectListener soundEffectListener,
255             Consumer<ArraySet<Integer>> runningAppsChangedCallback,
256             VirtualDeviceParams params) {
257         this(
258                 context,
259                 associationInfo,
260                 service,
261                 virtualDeviceLog,
262                 token,
263                 attributionSource,
264                 deviceId,
265                 /* inputController= */ null,
266                 cameraAccessController,
267                 pendingTrampolineCallback,
268                 activityListener,
269                 soundEffectListener,
270                 runningAppsChangedCallback,
271                 params,
272                 DisplayManagerGlobal.getInstance(),
273                 isVirtualCameraEnabled()
274                         ? new VirtualCameraController(
275                                 params.getDevicePolicy(POLICY_TYPE_CAMERA), deviceId)
276                         : null);
277     }
278 
279     @VisibleForTesting
280     VirtualDeviceImpl(
281             Context context,
282             AssociationInfo associationInfo,
283             VirtualDeviceManagerService service,
284             VirtualDeviceLog virtualDeviceLog,
285             IBinder token,
286             AttributionSource attributionSource,
287             int deviceId,
288             InputController inputController,
289             CameraAccessController cameraAccessController,
290             PendingTrampolineCallback pendingTrampolineCallback,
291             IVirtualDeviceActivityListener activityListener,
292             IVirtualDeviceSoundEffectListener soundEffectListener,
293             Consumer<ArraySet<Integer>> runningAppsChangedCallback,
294             VirtualDeviceParams params,
295             DisplayManagerGlobal displayManager,
296             VirtualCameraController virtualCameraController) {
297         super(PermissionEnforcer.fromContext(context));
298         mVirtualDeviceLog = virtualDeviceLog;
299         mOwnerPackageName = attributionSource.getPackageName();
300         mAttributionSource = attributionSource;
301         UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(attributionSource.getUid());
302         mContext = context.createContextAsUser(ownerUserHandle, 0);
303         mAssociationInfo = associationInfo;
304         mPersistentDeviceId = createPersistentDeviceId(associationInfo.getId());
305         mService = service;
306         mPendingTrampolineCallback = pendingTrampolineCallback;
307         mActivityListener = activityListener;
308         mSoundEffectListener = soundEffectListener;
309         mRunningAppsChangedCallback = runningAppsChangedCallback;
310         mOwnerUid = attributionSource.getUid();
311         mDeviceId = deviceId;
312         mAppToken = token;
313         mParams = params;
314         mDevicePolicies = params.getDevicePolicies();
315         mDisplayManager = displayManager;
316         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
317         if (inputController == null) {
318             mInputController = new InputController(
319                     context.getMainThreadHandler(),
320                     context.getSystemService(WindowManager.class), mAttributionSource);
321         } else {
322             mInputController = inputController;
323         }
324         mSensorController = new SensorController(this, mDeviceId, mAttributionSource,
325                 mParams.getVirtualSensorCallback(), mParams.getVirtualSensorConfigs());
326         mCameraAccessController = cameraAccessController;
327         if (mCameraAccessController != null) {
328             mCameraAccessController.startObservingIfNeeded();
329         }
330         if (!Flags.streamPermissions()) {
331             mPermissionDialogComponent = getPermissionDialogComponent();
332         } else {
333             mPermissionDialogComponent = null;
334         }
335         mVirtualCameraController = virtualCameraController;
336         try {
337             token.linkToDeath(this, 0);
338         } catch (RemoteException e) {
339             throw e.rethrowFromSystemServer();
340         }
341         mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);
342 
343         if (Flags.vdmPublicApis()) {
344             mPublicVirtualDeviceObject = new VirtualDevice(
345                     this, getDeviceId(), getPersistentDeviceId(), mParams.getName(),
346                     getDisplayName());
347         } else {
348             mPublicVirtualDeviceObject = new VirtualDevice(
349                     this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
350         }
351 
352         if (Flags.dynamicPolicy()) {
353             mActivityPolicyExemptions = new ArraySet<>(
354                     mParams.getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
355                             ? mParams.getBlockedActivities()
356                             : mParams.getAllowedActivities());
357         } else {
358             mActivityPolicyExemptions =
359                     mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED
360                             ? mParams.getBlockedActivities()
361                             : mParams.getAllowedActivities();
362         }
363 
364         int flags = DEFAULT_VIRTUAL_DISPLAY_FLAGS;
365         if (!Flags.consistentDisplayFlags()) {
366             flags |= DEFAULT_VIRTUAL_DISPLAY_FLAGS_PRE_VIC;
367         }
368         if (mParams.getLockState() == VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED) {
369             flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
370         }
371         mBaseVirtualDisplayFlags = flags;
372 
373         if (Flags.vdmCustomIme() && mParams.getInputMethodComponent() != null) {
374             final String imeId = mParams.getInputMethodComponent().flattenToShortString();
375             Slog.d(TAG, "Setting custom input method " + imeId + " as default for virtual device "
376                     + deviceId);
377             InputMethodManagerInternal.get().setVirtualDeviceInputMethodForAllUsers(
378                     mDeviceId, imeId);
379         }
380     }
381 
382     @VisibleForTesting
383     SensorController getSensorControllerForTest() {
384         return mSensorController;
385     }
386 
387     static String createPersistentDeviceId(int associationId) {
388         return PERSISTENT_ID_PREFIX_CDM_ASSOCIATION + associationId;
389     }
390 
391     /**
392      * Returns the flags that should be added to any virtual displays created on this virtual
393      * device.
394      */
395     int getBaseVirtualDisplayFlags() {
396         return mBaseVirtualDisplayFlags;
397     }
398 
399     /** Returns the camera access controller of this device. */
400     CameraAccessController getCameraAccessController() {
401         return mCameraAccessController;
402     }
403 
404     /** Returns the device display name. */
405     CharSequence getDisplayName() {
406         return mAssociationInfo.getDisplayName();
407     }
408 
409     /** Returns the public representation of the device. */
410     VirtualDevice getPublicVirtualDeviceObject() {
411         return mPublicVirtualDeviceObject;
412     }
413 
414     /** Returns the locale of the device. */
415     LocaleList getDeviceLocaleList() {
416         synchronized (mVirtualDeviceLock) {
417             return mLocaleList;
418         }
419     }
420 
421     @Override  // Binder call
422     public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
423             @VirtualDeviceParams.PolicyType int policyType) {
424         if (Flags.dynamicPolicy()) {
425             synchronized (mVirtualDeviceLock) {
426                 return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
427             }
428         } else {
429             return mParams.getDevicePolicy(policyType);
430         }
431     }
432 
433     /** Returns device-specific audio session id for playback. */
434     public int getAudioPlaybackSessionId() {
435         return mParams.getAudioPlaybackSessionId();
436     }
437 
438     /** Returns device-specific audio session id for recording. */
439     public int getAudioRecordingSessionId() {
440         return mParams.getAudioRecordingSessionId();
441     }
442 
443     /** Returns the unique device ID of this device. */
444     @Override // Binder call
445     public int getDeviceId() {
446         return mDeviceId;
447     }
448 
449     /** Returns the unique device ID of this device. */
450     @Override // Binder call
451     public @Nullable String getPersistentDeviceId() {
452         return mPersistentDeviceId;
453     }
454 
455     @Override // Binder call
456     public int getAssociationId() {
457         return mAssociationInfo.getId();
458     }
459 
460     @Override // Binder call
461     public void launchPendingIntent(int displayId, PendingIntent pendingIntent,
462             ResultReceiver resultReceiver) {
463         Objects.requireNonNull(pendingIntent);
464         synchronized (mVirtualDeviceLock) {
465             if (!mVirtualDisplays.contains(displayId)) {
466                 throw new SecurityException("Display ID " + displayId
467                         + " not found for this virtual device");
468             }
469         }
470         if (pendingIntent.isActivity()) {
471             try {
472                 sendPendingIntent(displayId, pendingIntent);
473                 resultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
474             } catch (PendingIntent.CanceledException e) {
475                 Slog.w(TAG, "Pending intent canceled", e);
476                 resultReceiver.send(
477                         VirtualDeviceManager.LAUNCH_FAILURE_PENDING_INTENT_CANCELED, null);
478             }
479         } else {
480             PendingTrampoline pendingTrampoline = new PendingTrampoline(pendingIntent,
481                     resultReceiver, displayId);
482             mPendingTrampolineCallback.startWaitingForPendingTrampoline(pendingTrampoline);
483             mContext.getMainThreadHandler().postDelayed(() -> {
484                 pendingTrampoline.mResultReceiver.send(
485                         VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
486                 mPendingTrampolineCallback.stopWaitingForPendingTrampoline(pendingTrampoline);
487             }, PENDING_TRAMPOLINE_TIMEOUT_MS);
488             try {
489                 sendPendingIntent(displayId, pendingIntent);
490             } catch (PendingIntent.CanceledException e) {
491                 Slog.w(TAG, "Pending intent canceled", e);
492                 resultReceiver.send(
493                         VirtualDeviceManager.LAUNCH_FAILURE_PENDING_INTENT_CANCELED, null);
494                 mPendingTrampolineCallback.stopWaitingForPendingTrampoline(pendingTrampoline);
495             }
496         }
497     }
498 
499     @Override // Binder call
500     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
501     public void addActivityPolicyExemption(@NonNull ComponentName componentName) {
502         super.addActivityPolicyExemption_enforcePermission();
503         synchronized (mVirtualDeviceLock) {
504             if (mActivityPolicyExemptions.add(componentName)) {
505                 for (int i = 0; i < mVirtualDisplays.size(); i++) {
506                     mVirtualDisplays.valueAt(i).getWindowPolicyController()
507                             .addActivityPolicyExemption(componentName);
508                 }
509             }
510         }
511     }
512 
513     @Override // Binder call
514     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
515     public void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
516         super.removeActivityPolicyExemption_enforcePermission();
517         synchronized (mVirtualDeviceLock) {
518             if (mActivityPolicyExemptions.remove(componentName)) {
519                 for (int i = 0; i < mVirtualDisplays.size(); i++) {
520                     mVirtualDisplays.valueAt(i).getWindowPolicyController()
521                             .removeActivityPolicyExemption(componentName);
522                 }
523             }
524         }
525     }
526 
527     private void sendPendingIntent(int displayId, PendingIntent pendingIntent)
528             throws PendingIntent.CanceledException {
529         final ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId);
530         options.setPendingIntentBackgroundActivityLaunchAllowed(true);
531         options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
532         pendingIntent.send(
533                 mContext,
534                 /* code= */ 0,
535                 /* intent= */ null,
536                 /* onFinished= */ null,
537                 /* handler= */ null,
538                 /* requiredPermission= */ null,
539                 options.toBundle());
540     }
541 
542     @Override // Binder call
543     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
544     public void close() {
545         super.close_enforcePermission();
546         // Remove about-to-be-closed virtual device from the service before butchering it.
547         if (!mService.removeVirtualDevice(mDeviceId)) {
548             // Device is already closed.
549             return;
550         }
551 
552         mVirtualDeviceLog.logClosed(mDeviceId, mOwnerUid);
553 
554         final long ident = Binder.clearCallingIdentity();
555         try {
556             VirtualDisplayWrapper[] virtualDisplaysToBeReleased;
557             synchronized (mVirtualDeviceLock) {
558                 if (mVirtualAudioController != null) {
559                     mVirtualAudioController.stopListening();
560                     mVirtualAudioController = null;
561                 }
562                 mLocaleList = null;
563                 virtualDisplaysToBeReleased = new VirtualDisplayWrapper[mVirtualDisplays.size()];
564                 for (int i = 0; i < mVirtualDisplays.size(); i++) {
565                     virtualDisplaysToBeReleased[i] = mVirtualDisplays.valueAt(i);
566                 }
567                 mVirtualDisplays.clear();
568             }
569             // Destroy the display outside locked section.
570             for (VirtualDisplayWrapper virtualDisplayWrapper : virtualDisplaysToBeReleased) {
571                 mDisplayManager.releaseVirtualDisplay(virtualDisplayWrapper.getToken());
572                 // The releaseVirtualDisplay call above won't trigger
573                 // VirtualDeviceImpl.onVirtualDisplayRemoved callback because we already removed the
574                 // virtual device from the service - we release the other display-tied resources
575                 // here with the guarantee it will be done exactly once.
576                 releaseOwnedVirtualDisplayResources(virtualDisplayWrapper);
577             }
578 
579             mAppToken.unlinkToDeath(this, 0);
580             if (mCameraAccessController != null) {
581                 mCameraAccessController.stopObservingIfNeeded();
582             }
583 
584             // Clear any previously set custom IME components.
585             if (Flags.vdmCustomIme() && mParams.getInputMethodComponent() != null) {
586                 InputMethodManagerInternal.get().setVirtualDeviceInputMethodForAllUsers(
587                         mDeviceId, null);
588             }
589 
590             mInputController.close();
591             mSensorController.close();
592         } finally {
593             Binder.restoreCallingIdentity(ident);
594         }
595         if (mVirtualCameraController != null) {
596             mVirtualCameraController.close();
597         }
598     }
599 
600     @Override
601     public void binderDied() {
602         close();
603     }
604 
605     @Override
606     @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
607     public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
608         if (mCameraAccessController != null) {
609             mCameraAccessController.blockCameraAccessIfNeeded(runningUids);
610         }
611         mRunningAppsChangedCallback.accept(runningUids);
612     }
613 
614     @VisibleForTesting
615     VirtualAudioController getVirtualAudioControllerForTesting() {
616         return mVirtualAudioController;
617     }
618 
619     @Override // Binder call
620     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
621     public void onAudioSessionStarting(int displayId,
622             @NonNull IAudioRoutingCallback routingCallback,
623             @Nullable IAudioConfigChangedCallback configChangedCallback) {
624         super.onAudioSessionStarting_enforcePermission();
625         synchronized (mVirtualDeviceLock) {
626             if (!mVirtualDisplays.contains(displayId)) {
627                 throw new SecurityException(
628                         "Cannot start audio session for a display not associated with this virtual "
629                                 + "device");
630             }
631 
632             if (mVirtualAudioController == null) {
633                 mVirtualAudioController = new VirtualAudioController(mContext, mAttributionSource);
634                 GenericWindowPolicyController gwpc = mVirtualDisplays.get(
635                         displayId).getWindowPolicyController();
636                 mVirtualAudioController.startListening(gwpc, routingCallback,
637                         configChangedCallback);
638             }
639         }
640     }
641 
642     @Override // Binder call
643     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
644     public void onAudioSessionEnded() {
645         super.onAudioSessionEnded_enforcePermission();
646         synchronized (mVirtualDeviceLock) {
647             if (mVirtualAudioController != null) {
648                 mVirtualAudioController.stopListening();
649                 mVirtualAudioController = null;
650             }
651         }
652     }
653 
654     @Override // Binder call
655     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
656     public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
657             @VirtualDeviceParams.DevicePolicy int devicePolicy) {
658         super.setDevicePolicy_enforcePermission();
659         if (!Flags.dynamicPolicy()) {
660             return;
661         }
662 
663         switch (policyType) {
664             case POLICY_TYPE_RECENTS:
665                 synchronized (mVirtualDeviceLock) {
666                     mDevicePolicies.put(policyType, devicePolicy);
667                     for (int i = 0; i < mVirtualDisplays.size(); i++) {
668                         mVirtualDisplays.valueAt(i).getWindowPolicyController()
669                                 .setShowInHostDeviceRecents(devicePolicy == DEVICE_POLICY_DEFAULT);
670                     }
671                 }
672                 break;
673             case POLICY_TYPE_ACTIVITY:
674                 synchronized (mVirtualDeviceLock) {
675                     mDevicePolicies.put(policyType, devicePolicy);
676                     for (int i = 0; i < mVirtualDisplays.size(); i++) {
677                         mVirtualDisplays.valueAt(i).getWindowPolicyController()
678                                 .setActivityLaunchDefaultAllowed(
679                                         devicePolicy == DEVICE_POLICY_DEFAULT);
680                     }
681                 }
682                 break;
683             case POLICY_TYPE_CLIPBOARD:
684                 if (Flags.crossDeviceClipboard()) {
685                     synchronized (mVirtualDeviceLock) {
686                         mDevicePolicies.put(policyType, devicePolicy);
687                     }
688                 }
689                 break;
690             default:
691                 throw new IllegalArgumentException("Device policy " + policyType
692                         + " cannot be changed at runtime. ");
693         }
694     }
695 
696     @Override // Binder call
697     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
698     public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
699         super.createVirtualDpad_enforcePermission();
700         Objects.requireNonNull(config);
701         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
702         final long ident = Binder.clearCallingIdentity();
703         try {
704             mInputController.createDpad(config.getInputDeviceName(), config.getVendorId(),
705                     config.getProductId(), deviceToken,
706                     getTargetDisplayIdForInput(config.getAssociatedDisplayId()));
707         } catch (InputController.DeviceCreationException e) {
708             throw new IllegalArgumentException(e);
709         } finally {
710             Binder.restoreCallingIdentity(ident);
711         }
712     }
713 
714     @Override // Binder call
715     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
716     public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
717         super.createVirtualKeyboard_enforcePermission();
718         Objects.requireNonNull(config);
719         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
720         final long ident = Binder.clearCallingIdentity();
721         try {
722             mInputController.createKeyboard(config.getInputDeviceName(), config.getVendorId(),
723                     config.getProductId(), deviceToken,
724                     getTargetDisplayIdForInput(config.getAssociatedDisplayId()),
725                     config.getLanguageTag(), config.getLayoutType());
726             synchronized (mVirtualDeviceLock) {
727                 mLocaleList = LocaleList.forLanguageTags(config.getLanguageTag());
728             }
729         } catch (InputController.DeviceCreationException e) {
730             throw new IllegalArgumentException(e);
731         } finally {
732             Binder.restoreCallingIdentity(ident);
733         }
734     }
735 
736     @Override // Binder call
737     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
738     public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
739         super.createVirtualMouse_enforcePermission();
740         Objects.requireNonNull(config);
741         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
742         final long ident = Binder.clearCallingIdentity();
743         try {
744             mInputController.createMouse(config.getInputDeviceName(), config.getVendorId(),
745                     config.getProductId(), deviceToken, config.getAssociatedDisplayId());
746         } catch (InputController.DeviceCreationException e) {
747             throw new IllegalArgumentException(e);
748         } finally {
749             Binder.restoreCallingIdentity(ident);
750         }
751     }
752 
753     @Override // Binder call
754     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
755     public void createVirtualTouchscreen(VirtualTouchscreenConfig config,
756             @NonNull IBinder deviceToken) {
757         super.createVirtualTouchscreen_enforcePermission();
758         Objects.requireNonNull(config);
759         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
760         final long ident = Binder.clearCallingIdentity();
761         try {
762             mInputController.createTouchscreen(config.getInputDeviceName(), config.getVendorId(),
763                     config.getProductId(), deviceToken, config.getAssociatedDisplayId(),
764                     config.getHeight(), config.getWidth());
765         } catch (InputController.DeviceCreationException e) {
766             throw new IllegalArgumentException(e);
767         } finally {
768             Binder.restoreCallingIdentity(ident);
769         }
770     }
771 
772     @Override // Binder call
773     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
774     public void createVirtualNavigationTouchpad(VirtualNavigationTouchpadConfig config,
775             @NonNull IBinder deviceToken) {
776         super.createVirtualNavigationTouchpad_enforcePermission();
777         Objects.requireNonNull(config);
778         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
779         final long ident = Binder.clearCallingIdentity();
780         try {
781             mInputController.createNavigationTouchpad(
782                     config.getInputDeviceName(), config.getVendorId(),
783                     config.getProductId(), deviceToken,
784                     getTargetDisplayIdForInput(config.getAssociatedDisplayId()),
785                     config.getHeight(), config.getWidth());
786         } catch (InputController.DeviceCreationException e) {
787             throw new IllegalArgumentException(e);
788         } finally {
789             Binder.restoreCallingIdentity(ident);
790         }
791     }
792 
793     @Override // Binder call
794     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
795     public void createVirtualStylus(@NonNull VirtualStylusConfig config,
796             @NonNull IBinder deviceToken) {
797         super.createVirtualStylus_enforcePermission();
798         Objects.requireNonNull(config);
799         Objects.requireNonNull(deviceToken);
800         checkVirtualInputDeviceDisplayIdAssociation(config.getAssociatedDisplayId());
801         final long ident = Binder.clearCallingIdentity();
802         try {
803             mInputController.createStylus(config.getInputDeviceName(), config.getVendorId(),
804                     config.getProductId(), deviceToken, config.getAssociatedDisplayId(),
805                     config.getHeight(), config.getWidth());
806         } catch (InputController.DeviceCreationException e) {
807             throw new IllegalArgumentException(e);
808         } finally {
809             Binder.restoreCallingIdentity(ident);
810         }
811     }
812 
813     @Override // Binder call
814     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
815     public void unregisterInputDevice(IBinder token) {
816         super.unregisterInputDevice_enforcePermission();
817         final long ident = Binder.clearCallingIdentity();
818         try {
819             mInputController.unregisterInputDevice(token);
820         } finally {
821             Binder.restoreCallingIdentity(ident);
822         }
823     }
824 
825     @Override // Binder call
826     public int getInputDeviceId(IBinder token) {
827         final long ident = Binder.clearCallingIdentity();
828         try {
829             return mInputController.getInputDeviceId(token);
830         } finally {
831             Binder.restoreCallingIdentity(ident);
832         }
833     }
834 
835 
836     @Override // Binder call
837     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
838     public boolean sendDpadKeyEvent(IBinder token, VirtualKeyEvent event) {
839         super.sendDpadKeyEvent_enforcePermission();
840         final long ident = Binder.clearCallingIdentity();
841         try {
842             return mInputController.sendDpadKeyEvent(token, event);
843         } finally {
844             Binder.restoreCallingIdentity(ident);
845         }
846     }
847 
848     @Override // Binder call
849     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
850     public boolean sendKeyEvent(IBinder token, VirtualKeyEvent event) {
851         super.sendKeyEvent_enforcePermission();
852         final long ident = Binder.clearCallingIdentity();
853         try {
854             return mInputController.sendKeyEvent(token, event);
855         } finally {
856             Binder.restoreCallingIdentity(ident);
857         }
858     }
859 
860     @Override // Binder call
861     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
862     public boolean sendButtonEvent(IBinder token, VirtualMouseButtonEvent event) {
863         super.sendButtonEvent_enforcePermission();
864         final long ident = Binder.clearCallingIdentity();
865         try {
866             return mInputController.sendButtonEvent(token, event);
867         } finally {
868             Binder.restoreCallingIdentity(ident);
869         }
870     }
871 
872     @Override // Binder call
873     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
874     public boolean sendTouchEvent(IBinder token, VirtualTouchEvent event) {
875         super.sendTouchEvent_enforcePermission();
876         final long ident = Binder.clearCallingIdentity();
877         try {
878             return mInputController.sendTouchEvent(token, event);
879         } finally {
880             Binder.restoreCallingIdentity(ident);
881         }
882     }
883 
884     @Override // Binder call
885     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
886     public boolean sendRelativeEvent(IBinder token, VirtualMouseRelativeEvent event) {
887         super.sendRelativeEvent_enforcePermission();
888         final long ident = Binder.clearCallingIdentity();
889         try {
890             return mInputController.sendRelativeEvent(token, event);
891         } finally {
892             Binder.restoreCallingIdentity(ident);
893         }
894     }
895 
896     @Override // Binder call
897     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
898     public boolean sendScrollEvent(IBinder token, VirtualMouseScrollEvent event) {
899         super.sendScrollEvent_enforcePermission();
900         final long ident = Binder.clearCallingIdentity();
901         try {
902             return mInputController.sendScrollEvent(token, event);
903         } finally {
904             Binder.restoreCallingIdentity(ident);
905         }
906     }
907 
908     @Override // Binder call
909     public PointF getCursorPosition(IBinder token) {
910         final long ident = Binder.clearCallingIdentity();
911         try {
912             return mInputController.getCursorPosition(token);
913         } finally {
914             Binder.restoreCallingIdentity(ident);
915         }
916     }
917 
918     @Override // Binder call
919     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
920     public boolean sendStylusMotionEvent(@NonNull IBinder token,
921             @NonNull VirtualStylusMotionEvent event) {
922         super.sendStylusMotionEvent_enforcePermission();
923         Objects.requireNonNull(token);
924         Objects.requireNonNull(event);
925         final long ident = Binder.clearCallingIdentity();
926         try {
927             return mInputController.sendStylusMotionEvent(token, event);
928         } finally {
929             Binder.restoreCallingIdentity(ident);
930         }
931     }
932 
933     @Override // Binder call
934     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
935     public boolean sendStylusButtonEvent(@NonNull IBinder token,
936             @NonNull VirtualStylusButtonEvent event) {
937         super.sendStylusButtonEvent_enforcePermission();
938         Objects.requireNonNull(token);
939         Objects.requireNonNull(event);
940         final long ident = Binder.clearCallingIdentity();
941         try {
942             return mInputController.sendStylusButtonEvent(token, event);
943         } finally {
944             Binder.restoreCallingIdentity(ident);
945         }
946     }
947 
948     @Override // Binder call
949     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
950     public void setShowPointerIcon(boolean showPointerIcon) {
951         super.setShowPointerIcon_enforcePermission();
952         final long ident = Binder.clearCallingIdentity();
953         try {
954             synchronized (mVirtualDeviceLock) {
955                 mDefaultShowPointerIcon = showPointerIcon;
956             }
957             final int[] displayIds = getDisplayIds();
958             for (int i = 0; i < displayIds.length; ++i) {
959                 mInputController.setShowPointerIcon(showPointerIcon, displayIds[i]);
960             }
961         } finally {
962             Binder.restoreCallingIdentity(ident);
963         }
964     }
965 
966     @Override // Binder call
967     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
968     public void setDisplayImePolicy(int displayId, @WindowManager.DisplayImePolicy int policy) {
969         super.setDisplayImePolicy_enforcePermission();
970         synchronized (mVirtualDeviceLock) {
971             if (!mVirtualDisplays.contains(displayId)) {
972                 throw new SecurityException("Display ID " + displayId
973                         + " not found for this virtual device");
974             }
975         }
976         final long ident = Binder.clearCallingIdentity();
977         try {
978             mInputController.setDisplayImePolicy(displayId, policy);
979         } finally {
980             Binder.restoreCallingIdentity(ident);
981         }
982     }
983 
984     @Override // Binder call
985     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
986     @Nullable
987     public List<VirtualSensor> getVirtualSensorList() {
988         super.getVirtualSensorList_enforcePermission();
989         return mSensorController.getSensorList();
990     }
991 
992     @Nullable
993     VirtualSensor getVirtualSensorByHandle(int handle) {
994         return mSensorController.getSensorByHandle(handle);
995     }
996 
997     @Override // Binder call
998     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
999     public boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
1000         super.sendSensorEvent_enforcePermission();
1001         final long ident = Binder.clearCallingIdentity();
1002         try {
1003             return mSensorController.sendSensorEvent(token, event);
1004         } finally {
1005             Binder.restoreCallingIdentity(ident);
1006         }
1007     }
1008 
1009     @Override // Binder call
1010     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
1011     public void registerIntentInterceptor(IVirtualDeviceIntentInterceptor intentInterceptor,
1012             IntentFilter filter) {
1013         super.registerIntentInterceptor_enforcePermission();
1014         Objects.requireNonNull(intentInterceptor);
1015         Objects.requireNonNull(filter);
1016         synchronized (mVirtualDeviceLock) {
1017             mIntentInterceptors.put(intentInterceptor.asBinder(), filter);
1018         }
1019     }
1020 
1021     @Override // Binder call
1022     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
1023     public void unregisterIntentInterceptor(
1024             @NonNull IVirtualDeviceIntentInterceptor intentInterceptor) {
1025         super.unregisterIntentInterceptor_enforcePermission();
1026         Objects.requireNonNull(intentInterceptor);
1027         synchronized (mVirtualDeviceLock) {
1028             mIntentInterceptors.remove(intentInterceptor.asBinder());
1029         }
1030     }
1031 
1032     @Override // Binder call
1033     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
1034     public void registerVirtualCamera(@NonNull VirtualCameraConfig cameraConfig)
1035             throws RemoteException {
1036         super.registerVirtualCamera_enforcePermission();
1037         Objects.requireNonNull(cameraConfig);
1038         if (mVirtualCameraController == null) {
1039             throw new UnsupportedOperationException("Virtual camera controller is not available");
1040         }
1041         mVirtualCameraController.registerCamera(cameraConfig, mAttributionSource);
1042     }
1043 
1044     @Override // Binder call
1045     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
1046     public void unregisterVirtualCamera(@NonNull VirtualCameraConfig cameraConfig)
1047             throws RemoteException {
1048         super.unregisterVirtualCamera_enforcePermission();
1049         Objects.requireNonNull(cameraConfig);
1050         if (mVirtualCameraController == null) {
1051             throw new UnsupportedOperationException("Virtual camera controller is not available");
1052         }
1053         mVirtualCameraController.unregisterCamera(cameraConfig);
1054     }
1055 
1056     @Override // Binder call
1057     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
1058     public String getVirtualCameraId(@NonNull VirtualCameraConfig cameraConfig)
1059             throws RemoteException {
1060         super.getVirtualCameraId_enforcePermission();
1061         Objects.requireNonNull(cameraConfig);
1062         if (mVirtualCameraController == null) {
1063             throw new UnsupportedOperationException("Virtual camera controller is not available");
1064         }
1065         return mVirtualCameraController.getCameraId(cameraConfig);
1066     }
1067 
1068     @Override
1069     public boolean hasCustomAudioInputSupport() throws RemoteException {
1070         return hasCustomAudioInputSupportInternal();
1071     }
1072 
1073     private boolean hasCustomAudioInputSupportInternal() {
1074         if (!Flags.vdmPublicApis()) {
1075             return false;
1076         }
1077 
1078         if (!android.media.audiopolicy.Flags.audioMixTestApi()) {
1079             return false;
1080         }
1081         if (!android.media.audiopolicy.Flags.recordAudioDeviceAwarePermission()) {
1082             return false;
1083         }
1084 
1085         if (getDevicePolicy(POLICY_TYPE_AUDIO) == VirtualDeviceParams.DEVICE_POLICY_CUSTOM) {
1086             return true;
1087         }
1088         final long token = Binder.clearCallingIdentity();
1089         try {
1090             AudioManager audioManager = mContext.getSystemService(AudioManager.class);
1091             for (AudioMix mix : audioManager.getRegisteredPolicyMixes()) {
1092                 if (mix.matchesVirtualDeviceId(getDeviceId())
1093                         && mix.getMixType() == AudioMix.MIX_TYPE_RECORDERS) {
1094                     return true;
1095                 }
1096             }
1097         } finally {
1098             Binder.restoreCallingIdentity(token);
1099         }
1100         return false;
1101     }
1102 
1103     @Override
1104     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1105         String indent = "    ";
1106         fout.println("  VirtualDevice: ");
1107         fout.println(indent + "mDeviceId: " + mDeviceId);
1108         fout.println(indent + "mAssociationId: " + mAssociationInfo.getId());
1109         fout.println(indent + "mOwnerPackageName: " + mOwnerPackageName);
1110         fout.println(indent + "mParams: ");
1111         mParams.dump(fout, indent + indent);
1112         fout.println(indent + "mVirtualDisplayIds: ");
1113         synchronized (mVirtualDeviceLock) {
1114             for (int i = 0; i < mVirtualDisplays.size(); i++) {
1115                 fout.println(indent + "  " + mVirtualDisplays.keyAt(i));
1116             }
1117             fout.println("    mDevicePolicies: " + mDevicePolicies);
1118             fout.println(indent + "mDefaultShowPointerIcon: " + mDefaultShowPointerIcon);
1119         }
1120         mInputController.dump(fout);
1121         mSensorController.dump(fout);
1122         if (mVirtualCameraController != null) {
1123             mVirtualCameraController.dump(fout, indent);
1124         }
1125         fout.println(
1126                 indent + "hasCustomAudioInputSupport: " + hasCustomAudioInputSupportInternal());
1127     }
1128 
1129     // For display mirroring, we want to dispatch all key events to the source (default) display,
1130     // as the virtual display doesn't have any focused windows. Hence, call this for
1131     // associating any input device to the source display if the input device emits any key events.
1132     private int getTargetDisplayIdForInput(int displayId) {
1133         if (!Flags.interactiveScreenMirror()) {
1134             return displayId;
1135         }
1136 
1137         DisplayManagerInternal displayManager = LocalServices.getService(
1138                 DisplayManagerInternal.class);
1139         int mirroredDisplayId = displayManager.getDisplayIdToMirror(displayId);
1140         return mirroredDisplayId == Display.INVALID_DISPLAY ? displayId : mirroredDisplayId;
1141     }
1142 
1143     @GuardedBy("mVirtualDeviceLock")
1144     private GenericWindowPolicyController createWindowPolicyControllerLocked(
1145             @NonNull Set<String> displayCategories) {
1146         final boolean activityLaunchAllowedByDefault =
1147                 Flags.dynamicPolicy()
1148                     ? getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
1149                     : mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
1150         final boolean crossTaskNavigationAllowedByDefault =
1151                 mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
1152         final boolean showTasksInHostDeviceRecents =
1153                 getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
1154         final ComponentName homeComponent =
1155                 Flags.vdmCustomHome() ? mParams.getHomeComponent() : null;
1156 
1157         final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
1158                 WindowManager.LayoutParams.FLAG_SECURE,
1159                 WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
1160                 mAttributionSource,
1161                 getAllowedUserHandles(),
1162                 activityLaunchAllowedByDefault,
1163                 mActivityPolicyExemptions,
1164                 crossTaskNavigationAllowedByDefault,
1165                 /* crossTaskNavigationExemptions= */crossTaskNavigationAllowedByDefault
1166                         ? mParams.getBlockedCrossTaskNavigations()
1167                         : mParams.getAllowedCrossTaskNavigations(),
1168                 mPermissionDialogComponent,
1169                 createListenerAdapter(),
1170                 this::onEnteringPipBlocked,
1171                 this::onActivityBlocked,
1172                 this::onSecureWindowShown,
1173                 this::shouldInterceptIntent,
1174                 displayCategories,
1175                 showTasksInHostDeviceRecents,
1176                 homeComponent);
1177         gwpc.registerRunningAppsChangedListener(/* listener= */ this);
1178         return gwpc;
1179     }
1180 
1181     private ComponentName getPermissionDialogComponent() {
1182         Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
1183         PackageManager packageManager = mContext.getPackageManager();
1184         intent.setPackage(packageManager.getPermissionControllerPackageName());
1185         return intent.resolveActivity(packageManager);
1186     }
1187 
1188     int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
1189             @NonNull IVirtualDisplayCallback callback, String packageName) {
1190         GenericWindowPolicyController gwpc;
1191         synchronized (mVirtualDeviceLock) {
1192             gwpc = createWindowPolicyControllerLocked(virtualDisplayConfig.getDisplayCategories());
1193         }
1194         int displayId;
1195         displayId = mDisplayManagerInternal.createVirtualDisplay(virtualDisplayConfig, callback,
1196                 this, gwpc, packageName);
1197         gwpc.setDisplayId(displayId, /* isMirrorDisplay= */ Flags.interactiveScreenMirror()
1198                 && mDisplayManagerInternal.getDisplayIdToMirror(displayId)
1199                     != Display.INVALID_DISPLAY);
1200 
1201         boolean showPointer;
1202         synchronized (mVirtualDeviceLock) {
1203             if (mVirtualDisplays.contains(displayId)) {
1204                 gwpc.unregisterRunningAppsChangedListener(this);
1205                 throw new IllegalStateException(
1206                         "Virtual device already has a virtual display with ID " + displayId);
1207             }
1208 
1209             PowerManager.WakeLock wakeLock = createAndAcquireWakeLockForDisplay(displayId);
1210             mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock));
1211             showPointer = mDefaultShowPointerIcon;
1212         }
1213 
1214         final long token = Binder.clearCallingIdentity();
1215         try {
1216             mInputController.setShowPointerIcon(showPointer, displayId);
1217             mInputController.setMousePointerAccelerationEnabled(false, displayId);
1218             mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
1219                     displayId);
1220             // WM throws a SecurityException if the display is untrusted.
1221             if ((mDisplayManagerInternal.getDisplayInfo(displayId).flags & Display.FLAG_TRUSTED)
1222                     == Display.FLAG_TRUSTED) {
1223                 mInputController.setDisplayImePolicy(displayId,
1224                         WindowManager.DISPLAY_IME_POLICY_LOCAL);
1225             }
1226         } finally {
1227             Binder.restoreCallingIdentity(token);
1228         }
1229 
1230         if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
1231             Counter.logIncrementWithUid(
1232                     "virtual_devices.value_virtual_display_created_count",
1233                     mAttributionSource.getUid());
1234         }
1235         return displayId;
1236     }
1237 
1238     private PowerManager.WakeLock createAndAcquireWakeLockForDisplay(int displayId) {
1239         final long token = Binder.clearCallingIdentity();
1240         try {
1241             PowerManager powerManager = mContext.getSystemService(PowerManager.class);
1242             PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
1243                     PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
1244                     TAG + ":" + displayId, displayId);
1245             wakeLock.acquire();
1246             return wakeLock;
1247         } finally {
1248             Binder.restoreCallingIdentity(token);
1249         }
1250     }
1251 
1252     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
1253     private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
1254         Intent intent = BlockedAppStreamingActivity.createIntent(
1255                 activityInfo, mAssociationInfo.getDisplayName());
1256         mContext.startActivityAsUser(
1257                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK),
1258                 ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(),
1259                 UserHandle.SYSTEM);
1260     }
1261 
1262     private void onSecureWindowShown(int displayId, int uid) {
1263         synchronized (mVirtualDeviceLock) {
1264             if (!mVirtualDisplays.contains(displayId)) {
1265                 return;
1266             }
1267         }
1268 
1269         // If a virtual display isn't secure, the screen can't be captured. Show a warning toast
1270         // if the secure window is shown on a non-secure virtual display.
1271         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
1272         Display display = displayManager.getDisplay(displayId);
1273         if ((display.getFlags() & Display.FLAG_SECURE) == 0) {
1274             showToastWhereUidIsRunning(uid, com.android.internal.R.string.vdm_secure_window,
1275                     Toast.LENGTH_LONG, mContext.getMainLooper());
1276 
1277             if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
1278                 Counter.logIncrementWithUid(
1279                         "virtual_devices.value_secure_window_blocked_count",
1280                         mAttributionSource.getUid());
1281             }
1282         }
1283     }
1284 
1285     private ArraySet<UserHandle> getAllowedUserHandles() {
1286         ArraySet<UserHandle> result = new ArraySet<>();
1287         final long token = Binder.clearCallingIdentity();
1288         try {
1289             DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
1290             UserManager userManager = mContext.getSystemService(UserManager.class);
1291             for (UserHandle profile : userManager.getAllProfiles()) {
1292                 int nearbyAppStreamingPolicy = dpm.getNearbyAppStreamingPolicy(
1293                         profile.getIdentifier());
1294                 if (nearbyAppStreamingPolicy == NEARBY_STREAMING_ENABLED
1295                         || nearbyAppStreamingPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY) {
1296                     result.add(profile);
1297                 } else if (nearbyAppStreamingPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY) {
1298                     if (mParams.getUsersWithMatchingAccounts().contains(profile)) {
1299                         result.add(profile);
1300                     }
1301                 }
1302             }
1303         } finally {
1304             Binder.restoreCallingIdentity(token);
1305         }
1306         return result;
1307     }
1308 
1309 
1310     void onVirtualDisplayRemoved(int displayId) {
1311         /* This is callback invoked by VirtualDeviceManagerService when VirtualDisplay was released
1312          * by DisplayManager (most probably caused by someone calling VirtualDisplay.close()).
1313          * At this point, the display is already released, but we still need to release the
1314          * corresponding wakeLock and unregister the RunningAppsChangedListener from corresponding
1315          * WindowPolicyController.
1316          *
1317          * Note that when the display is destroyed during VirtualDeviceImpl.close() call,
1318          * this callback won't be invoked because the display is removed from
1319          * VirtualDeviceManagerService before any resources are released.
1320          */
1321         VirtualDisplayWrapper virtualDisplayWrapper;
1322         synchronized (mVirtualDeviceLock) {
1323             virtualDisplayWrapper = mVirtualDisplays.removeReturnOld(displayId);
1324         }
1325 
1326         if (virtualDisplayWrapper == null) {
1327             Slog.w(TAG, "Virtual device " + mDeviceId + " doesn't have a virtual display with ID "
1328                     + displayId);
1329             return;
1330         }
1331 
1332         final long ident = Binder.clearCallingIdentity();
1333         try {
1334             releaseOwnedVirtualDisplayResources(virtualDisplayWrapper);
1335         } finally {
1336             Binder.restoreCallingIdentity(ident);
1337         }
1338     }
1339 
1340     @SuppressWarnings("AndroidFrameworkRequiresPermission")
1341     private void checkVirtualInputDeviceDisplayIdAssociation(int displayId) {
1342         if (mContext.checkCallingPermission(android.Manifest.permission.INJECT_EVENTS)
1343                     == PackageManager.PERMISSION_GRANTED) {
1344             // The INJECT_EVENTS permission allows for injecting input to any window / display.
1345             return;
1346         }
1347         synchronized (mVirtualDeviceLock) {
1348             if (!mVirtualDisplays.contains(displayId)) {
1349                 throw new SecurityException(
1350                         "Cannot create a virtual input device for display " + displayId
1351                                 + " which not associated with this virtual device");
1352             }
1353         }
1354     }
1355 
1356     /**
1357      * Release resources tied to virtual display owned by this VirtualDevice instance.
1358      *
1359      * Note that this method won't release the virtual display itself.
1360      *
1361      * @param virtualDisplayWrapper - VirtualDisplayWrapper to release resources for.
1362      */
1363     private void releaseOwnedVirtualDisplayResources(VirtualDisplayWrapper virtualDisplayWrapper) {
1364         virtualDisplayWrapper.getWakeLock().release();
1365         virtualDisplayWrapper.getWindowPolicyController().unregisterRunningAppsChangedListener(
1366                 this);
1367     }
1368 
1369     int getOwnerUid() {
1370         return mOwnerUid;
1371     }
1372 
1373     @Override  // Binder call
1374     public int[] getDisplayIds() {
1375         synchronized (mVirtualDeviceLock) {
1376             final int size = mVirtualDisplays.size();
1377             int[] displayIds = new int[size];
1378             for (int i = 0; i < size; i++) {
1379                 displayIds[i] = mVirtualDisplays.keyAt(i);
1380             }
1381             return displayIds;
1382         }
1383     }
1384 
1385     @VisibleForTesting
1386     GenericWindowPolicyController getDisplayWindowPolicyControllerForTest(int displayId) {
1387         VirtualDisplayWrapper virtualDisplayWrapper;
1388         synchronized (mVirtualDeviceLock) {
1389             virtualDisplayWrapper = mVirtualDisplays.get(displayId);
1390         }
1391         return virtualDisplayWrapper != null ? virtualDisplayWrapper.getWindowPolicyController()
1392                 : null;
1393     }
1394 
1395     /**
1396      * Returns true if an app with the given {@code uid} is currently running on this virtual
1397      * device.
1398      */
1399     boolean isAppRunningOnVirtualDevice(int uid) {
1400         synchronized (mVirtualDeviceLock) {
1401             for (int i = 0; i < mVirtualDisplays.size(); i++) {
1402                 if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) {
1403                     return true;
1404                 }
1405             }
1406         }
1407         return false;
1408     }
1409 
1410     /**
1411      * Shows a toast on virtual displays owned by this device which have a given uid running.
1412      */
1413     void showToastWhereUidIsRunning(int uid, @StringRes int resId, @Toast.Duration int duration,
1414             Looper looper) {
1415         showToastWhereUidIsRunning(uid, mContext.getString(resId), duration, looper);
1416     }
1417 
1418     /**
1419      * Shows a toast on virtual displays owned by this device which have a given uid running.
1420      */
1421     void showToastWhereUidIsRunning(int uid, String text, @Toast.Duration int duration,
1422             Looper looper) {
1423         IntArray displayIdsForUid = getDisplayIdsWhereUidIsRunning(uid);
1424         if (displayIdsForUid.size() == 0) {
1425             return;
1426         }
1427         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
1428         for (int i = 0; i < displayIdsForUid.size(); i++) {
1429             Display display = displayManager.getDisplay(displayIdsForUid.get(i));
1430             if (display != null && display.isValid()) {
1431                 Toast.makeText(mContext.createDisplayContext(display), looper, text,
1432                         duration).show();
1433             }
1434         }
1435     }
1436 
1437     private IntArray getDisplayIdsWhereUidIsRunning(int uid) {
1438         IntArray displayIdsForUid = new IntArray();
1439         synchronized (mVirtualDeviceLock) {
1440             for (int i = 0; i < mVirtualDisplays.size(); i++) {
1441                 if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) {
1442                     displayIdsForUid.add(mVirtualDisplays.keyAt(i));
1443                 }
1444             }
1445         }
1446         return displayIdsForUid;
1447     }
1448 
1449     boolean isDisplayOwnedByVirtualDevice(int displayId) {
1450         synchronized (mVirtualDeviceLock) {
1451             return mVirtualDisplays.contains(displayId);
1452         }
1453     }
1454 
1455     boolean isInputDeviceOwnedByVirtualDevice(int inputDeviceId) {
1456         return mInputController.getInputDeviceDescriptors().values().stream().anyMatch(
1457                 inputDeviceDescriptor -> inputDeviceDescriptor.getInputDeviceId() == inputDeviceId);
1458     }
1459 
1460     void onEnteringPipBlocked(int uid) {
1461         // Do nothing. ActivityRecord#checkEnterPictureInPictureState logs that the display does not
1462         // support PiP.
1463     }
1464 
1465     void playSoundEffect(int effectType) {
1466         try {
1467             mSoundEffectListener.onPlaySoundEffect(effectType);
1468         } catch (RemoteException exception) {
1469             Slog.w(TAG, "Unable to invoke sound effect listener", exception);
1470         }
1471     }
1472 
1473     /**
1474      * Intercepts intent when matching any of the IntentFilter of any interceptor. Returns true if
1475      * the intent matches any filter notifying the DisplayPolicyController to abort the
1476      * activity launch to be replaced by the interception.
1477      */
1478     private boolean shouldInterceptIntent(Intent intent) {
1479         synchronized (mVirtualDeviceLock) {
1480             boolean hasInterceptedIntent = false;
1481             for (Map.Entry<IBinder, IntentFilter> interceptor : mIntentInterceptors.entrySet()) {
1482                 IntentFilter intentFilter = interceptor.getValue();
1483                 // Explicitly match the actions because the intent filter will match any intent
1484                 // without an explicit action. If the intent has no action, then require that there
1485                 // are no actions specified in the filter either.
1486                 boolean explicitActionMatch = !intentInterceptionActionMatchingFix()
1487                         || intent.getAction() != null || intentFilter.countActions() == 0;
1488                 if (explicitActionMatch && intentFilter.match(
1489                         intent.getAction(), intent.getType(), intent.getScheme(), intent.getData(),
1490                         intent.getCategories(), TAG) >= 0) {
1491                     try {
1492                         // For privacy reasons, only returning the intents action and data. Any
1493                         // other required field will require a review.
1494                         IVirtualDeviceIntentInterceptor.Stub.asInterface(interceptor.getKey())
1495                             .onIntentIntercepted(new Intent(intent.getAction(), intent.getData()));
1496                         hasInterceptedIntent = true;
1497                     } catch (RemoteException e) {
1498                         Slog.w(TAG, "Unable to call mVirtualDeviceIntentInterceptor", e);
1499                     }
1500                 }
1501             }
1502 
1503             return hasInterceptedIntent;
1504         }
1505     }
1506 
1507     interface PendingTrampolineCallback {
1508         /**
1509          * Called when the callback should start waiting for the given pending trampoline.
1510          * Implementations should try to listen for activity starts associated with the given
1511          * {@code pendingTrampoline}, and launch the activity on the display with
1512          * {@link PendingTrampoline#mDisplayId}.
1513          */
1514         void startWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline);
1515 
1516         /**
1517          * Called when the callback should stop waiting for the given pending trampoline. This can
1518          * happen, for example, when the pending intent failed to send.
1519          */
1520         void stopWaitingForPendingTrampoline(PendingTrampoline pendingTrampoline);
1521     }
1522 
1523     /**
1524      * A data class storing a pending trampoline this device is expecting.
1525      */
1526     static class PendingTrampoline {
1527 
1528         /**
1529          * The original pending intent sent, for which a trampoline activity launch is expected.
1530          */
1531         final PendingIntent mPendingIntent;
1532 
1533         /**
1534          * The result receiver associated with this pending call. {@link Activity#RESULT_OK} will
1535          * be sent to the receiver if the trampoline activity was captured successfully.
1536          * {@link Activity#RESULT_CANCELED} is sent otherwise.
1537          */
1538         final ResultReceiver mResultReceiver;
1539 
1540         /**
1541          * The display ID to send the captured trampoline activity launch to.
1542          */
1543         final int mDisplayId;
1544 
1545         private PendingTrampoline(PendingIntent pendingIntent, ResultReceiver resultReceiver,
1546                 int displayId) {
1547             mPendingIntent = pendingIntent;
1548             mResultReceiver = resultReceiver;
1549             mDisplayId = displayId;
1550         }
1551 
1552         @Override
1553         public String toString() {
1554             return "PendingTrampoline{"
1555                     + "pendingIntent=" + mPendingIntent
1556                     + ", resultReceiver=" + mResultReceiver
1557                     + ", displayId=" + mDisplayId + "}";
1558         }
1559     }
1560 
1561     /** Data class wrapping resources tied to single virtual display. */
1562     private static final class VirtualDisplayWrapper {
1563         private final IVirtualDisplayCallback mToken;
1564         private final GenericWindowPolicyController mWindowPolicyController;
1565         private final PowerManager.WakeLock mWakeLock;
1566 
1567         VirtualDisplayWrapper(@NonNull IVirtualDisplayCallback token,
1568                 @NonNull GenericWindowPolicyController windowPolicyController,
1569                 @NonNull PowerManager.WakeLock wakeLock) {
1570             mToken = Objects.requireNonNull(token);
1571             mWindowPolicyController = Objects.requireNonNull(windowPolicyController);
1572             mWakeLock = Objects.requireNonNull(wakeLock);
1573         }
1574 
1575         GenericWindowPolicyController getWindowPolicyController() {
1576             return mWindowPolicyController;
1577         }
1578 
1579         PowerManager.WakeLock getWakeLock() {
1580             return mWakeLock;
1581         }
1582 
1583         IVirtualDisplayCallback getToken() {
1584             return mToken;
1585         }
1586     }
1587 
1588     private static boolean isVirtualCameraEnabled() {
1589         return Flags.virtualCamera() && virtualCameraServiceDiscovery()
1590                 && nativeVirtualCameraServiceBuildFlagEnabled();
1591     }
1592 
1593     // Returns true if virtual_camera service is enabled in this build.
1594     @FastNative
1595     private static native boolean nativeVirtualCameraServiceBuildFlagEnabled();
1596 }
1597