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