1 /* 2 * Copyright (C) 2021 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.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; 20 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS; 21 import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE; 22 23 import static com.android.server.wm.ActivityInterceptorCallback.VIRTUAL_DEVICE_SERVICE_ORDERED_ID; 24 25 import android.annotation.EnforcePermission; 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.annotation.RequiresPermission; 29 import android.annotation.SuppressLint; 30 import android.app.ActivityOptions; 31 import android.app.compat.CompatChanges; 32 import android.companion.AssociationInfo; 33 import android.companion.AssociationRequest; 34 import android.companion.CompanionDeviceManager; 35 import android.companion.virtual.IVirtualDevice; 36 import android.companion.virtual.IVirtualDeviceActivityListener; 37 import android.companion.virtual.IVirtualDeviceListener; 38 import android.companion.virtual.IVirtualDeviceManager; 39 import android.companion.virtual.IVirtualDeviceSoundEffectListener; 40 import android.companion.virtual.VirtualDevice; 41 import android.companion.virtual.VirtualDeviceManager; 42 import android.companion.virtual.VirtualDeviceParams; 43 import android.companion.virtual.sensor.VirtualSensor; 44 import android.companion.virtualnative.IVirtualDeviceManagerNative; 45 import android.compat.annotation.ChangeId; 46 import android.compat.annotation.EnabledAfter; 47 import android.content.AttributionSource; 48 import android.content.Context; 49 import android.content.Intent; 50 import android.hardware.display.DisplayManagerInternal; 51 import android.hardware.display.IVirtualDisplayCallback; 52 import android.os.Binder; 53 import android.os.Build; 54 import android.os.Handler; 55 import android.os.IBinder; 56 import android.os.LocaleList; 57 import android.os.Looper; 58 import android.os.Parcel; 59 import android.os.Process; 60 import android.os.RemoteCallbackList; 61 import android.os.RemoteException; 62 import android.os.UserHandle; 63 import android.util.ArrayMap; 64 import android.util.ArraySet; 65 import android.util.ExceptionUtils; 66 import android.util.Slog; 67 import android.util.SparseArray; 68 import android.view.Display; 69 import android.widget.Toast; 70 import android.window.DisplayWindowPolicyController; 71 72 import com.android.internal.R; 73 import com.android.internal.annotations.GuardedBy; 74 import com.android.internal.annotations.VisibleForTesting; 75 import com.android.internal.util.DumpUtils; 76 import com.android.internal.widget.LockPatternUtils; 77 import com.android.modules.expresslog.Counter; 78 import com.android.server.LocalServices; 79 import com.android.server.SystemService; 80 import com.android.server.companion.virtual.VirtualDeviceImpl.PendingTrampoline; 81 import com.android.server.wm.ActivityInterceptorCallback; 82 import com.android.server.wm.ActivityTaskManagerInternal; 83 84 import java.io.FileDescriptor; 85 import java.io.PrintWriter; 86 import java.util.ArrayList; 87 import java.util.Arrays; 88 import java.util.HashSet; 89 import java.util.List; 90 import java.util.Objects; 91 import java.util.Set; 92 import java.util.concurrent.ConcurrentHashMap; 93 import java.util.concurrent.atomic.AtomicInteger; 94 import java.util.function.Consumer; 95 import java.util.stream.Collectors; 96 97 @SuppressLint("LongLogTag") 98 public class VirtualDeviceManagerService extends SystemService { 99 100 private static final String TAG = "VirtualDeviceManagerService"; 101 102 private static final String VIRTUAL_DEVICE_NATIVE_SERVICE = "virtualdevice_native"; 103 104 private static final List<String> VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES = Arrays.asList( 105 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, 106 AssociationRequest.DEVICE_PROFILE_APP_STREAMING, 107 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, 108 AssociationRequest.DEVICE_PROFILE_VIRTUAL_DEVICE); 109 110 /** Enable default device camera access for apps running on virtual devices. */ 111 @ChangeId 112 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 113 public static final long ENABLE_DEFAULT_DEVICE_CAMERA_ACCESS = 371173368L; 114 115 /** 116 * A virtual device association id corresponding to no CDM association. 117 */ 118 static final int CDM_ASSOCIATION_ID_NONE = 0; 119 120 /** 121 * Global VDM lock. 122 * 123 * Never call outside this class while holding this lock. A number of other system services like 124 * WindowManager, DisplayManager, etc. call into VDM to get device-specific information, while 125 * holding their own global locks. 126 * 127 * Making a call to another service while holding this lock creates lock order inversion and 128 * will potentially cause a deadlock. 129 */ 130 private final Object mVirtualDeviceManagerLock = new Object(); 131 132 private final VirtualDeviceManagerImpl mImpl; 133 private final VirtualDeviceManagerNativeImpl mNativeImpl; 134 private final VirtualDeviceManagerInternal mLocalService; 135 private final VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext()); 136 private final Handler mHandler = new Handler(Looper.getMainLooper()); 137 private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler); 138 139 private static AtomicInteger sNextUniqueIndex = new AtomicInteger( 140 Context.DEVICE_ID_DEFAULT + 1); 141 142 @GuardedBy("mVirtualDeviceManagerLock") 143 private ArrayMap<String, AssociationInfo> mActiveAssociations = new ArrayMap<>(); 144 145 private class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { 146 final Set<Integer> mUsersInLockdown = new ArraySet<>(); 147 StrongAuthTracker(Context context)148 StrongAuthTracker(Context context) { 149 super(context); 150 } 151 152 @Override onStrongAuthRequiredChanged(int userId)153 public synchronized void onStrongAuthRequiredChanged(int userId) { 154 if ((getStrongAuthForUser(userId) & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) > 0) { 155 if (mUsersInLockdown.add(userId) && mUsersInLockdown.size() == 1) { 156 onLockdownChanged(true); 157 } 158 } else if (mUsersInLockdown.remove(userId) && mUsersInLockdown.isEmpty()) { 159 onLockdownChanged(false); 160 } 161 } 162 } 163 private StrongAuthTracker mStrongAuthTracker; 164 165 private final RemoteCallbackList<IVirtualDeviceListener> mVirtualDeviceListeners = 166 new RemoteCallbackList<>(); 167 168 /** 169 * Mapping from device IDs to virtual devices. 170 */ 171 @GuardedBy("mVirtualDeviceManagerLock") 172 private final SparseArray<VirtualDeviceImpl> mVirtualDevices = new SparseArray<>(); 173 174 /** 175 * Mapping from device IDs to app UIDs running on the corresponding virtual device. 176 */ 177 @GuardedBy("mVirtualDeviceManagerLock") 178 private final SparseArray<ArraySet<Integer>> mAppsOnVirtualDevices = new SparseArray<>(); 179 VirtualDeviceManagerService(Context context)180 public VirtualDeviceManagerService(Context context) { 181 super(context); 182 mImpl = new VirtualDeviceManagerImpl(); 183 mNativeImpl = new VirtualDeviceManagerNativeImpl(); 184 mLocalService = new LocalService(); 185 } 186 187 private final ActivityInterceptorCallback mActivityInterceptorCallback = 188 new ActivityInterceptorCallback() { 189 190 @Nullable 191 @Override 192 public ActivityInterceptResult onInterceptActivityLaunch(@NonNull 193 ActivityInterceptorInfo info) { 194 if (info.getCallingPackage() == null) { 195 return null; 196 } 197 PendingTrampoline pt = mPendingTrampolines.remove(info.getCallingPackage()); 198 if (pt == null) { 199 return null; 200 } 201 pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null); 202 ActivityOptions options = info.getCheckedOptions(); 203 if (options == null) { 204 options = ActivityOptions.makeBasic(); 205 } 206 return new ActivityInterceptResult( 207 info.getIntent(), options.setLaunchDisplayId(pt.mDisplayId)); 208 } 209 }; 210 211 @Override 212 @RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES) onStart()213 public void onStart() { 214 publishBinderService(Context.VIRTUAL_DEVICE_SERVICE, mImpl); 215 publishBinderService(VIRTUAL_DEVICE_NATIVE_SERVICE, mNativeImpl); 216 publishLocalService(VirtualDeviceManagerInternal.class, mLocalService); 217 ActivityTaskManagerInternal activityTaskManagerInternal = getLocalService( 218 ActivityTaskManagerInternal.class); 219 activityTaskManagerInternal.registerActivityStartInterceptor( 220 VIRTUAL_DEVICE_SERVICE_ORDERED_ID, 221 mActivityInterceptorCallback); 222 223 CompanionDeviceManager cdm = getContext().getSystemService(CompanionDeviceManager.class); 224 if (cdm != null) { 225 onCdmAssociationsChanged(cdm.getAllAssociations(UserHandle.USER_ALL)); 226 cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(), 227 this::onCdmAssociationsChanged, UserHandle.USER_ALL); 228 } else { 229 Slog.e(TAG, "Failed to find CompanionDeviceManager. No CDM association info " 230 + " will be available."); 231 } 232 if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()) { 233 mStrongAuthTracker = new StrongAuthTracker(getContext()); 234 new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker); 235 } 236 } 237 238 // Called when the global lockdown state changes, i.e. lockdown is considered active if any user 239 // is in lockdown mode, and inactive if no users are in lockdown mode. onLockdownChanged(boolean lockdownActive)240 void onLockdownChanged(boolean lockdownActive) { 241 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 242 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 243 virtualDevicesSnapshot.get(i).onLockdownChanged(lockdownActive); 244 } 245 } 246 onCameraAccessBlocked(int appUid)247 private void onCameraAccessBlocked(int appUid) { 248 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 249 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 250 VirtualDeviceImpl virtualDevice = virtualDevicesSnapshot.get(i); 251 virtualDevice.showToastWhereUidIsRunning(appUid, 252 getContext().getString( 253 R.string.vdm_camera_access_denied, 254 virtualDevice.getDisplayName()), 255 Toast.LENGTH_LONG, Looper.myLooper()); 256 } 257 } 258 getCameraAccessController(UserHandle userHandle, VirtualDeviceParams params, String callingPackage)259 private CameraAccessController getCameraAccessController(UserHandle userHandle, 260 VirtualDeviceParams params, String callingPackage) { 261 if (CompatChanges.isChangeEnabled(ENABLE_DEFAULT_DEVICE_CAMERA_ACCESS, callingPackage, 262 userHandle) 263 && android.companion.virtualdevice.flags.Flags.defaultDeviceCameraAccessPolicy() 264 && (params.getDevicePolicy(POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS) 265 == DEVICE_POLICY_DEFAULT)) { 266 return null; 267 } 268 int userId = userHandle.getIdentifier(); 269 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 270 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 271 final CameraAccessController cameraAccessController = 272 virtualDevicesSnapshot.get(i).getCameraAccessController(); 273 if (cameraAccessController.getUserId() == userId) { 274 return cameraAccessController; 275 } 276 } Context userContext = getContext().createContextAsUser(userHandle, 0); 277 return new CameraAccessController(userContext, mLocalService, this::onCameraAccessBlocked); 278 } 279 280 @VisibleForTesting getLocalServiceInstance()281 VirtualDeviceManagerInternal getLocalServiceInstance() { 282 return mLocalService; 283 } 284 285 @VisibleForTesting notifyRunningAppsChanged(int deviceId, ArraySet<Integer> uids)286 void notifyRunningAppsChanged(int deviceId, ArraySet<Integer> uids) { 287 synchronized (mVirtualDeviceManagerLock) { 288 if (!mVirtualDevices.contains(deviceId)) { 289 Slog.e(TAG, "notifyRunningAppsChanged called for unknown deviceId:" + deviceId 290 + " (maybe it was recently closed?)"); 291 return; 292 } 293 mAppsOnVirtualDevices.put(deviceId, uids); 294 } 295 mLocalService.onAppsOnVirtualDeviceChanged(); 296 } 297 298 @VisibleForTesting addVirtualDevice(VirtualDeviceImpl virtualDevice)299 void addVirtualDevice(VirtualDeviceImpl virtualDevice) { 300 synchronized (mVirtualDeviceManagerLock) { 301 mVirtualDevices.put(virtualDevice.getDeviceId(), virtualDevice); 302 } 303 } 304 305 /** 306 * Remove the virtual device. Sends the 307 * {@link VirtualDeviceManager#ACTION_VIRTUAL_DEVICE_REMOVED} broadcast as a result. 308 * 309 * @param deviceId deviceId to be removed 310 * @return {@code true} if the device was removed, {@code false} if the operation was a no-op 311 */ removeVirtualDevice(int deviceId)312 boolean removeVirtualDevice(int deviceId) { 313 synchronized (mVirtualDeviceManagerLock) { 314 if (!mVirtualDevices.contains(deviceId)) { 315 return false; 316 } 317 318 mAppsOnVirtualDevices.remove(deviceId); 319 mVirtualDevices.remove(deviceId); 320 } 321 322 mVirtualDeviceListeners.broadcast(listener -> { 323 try { 324 listener.onVirtualDeviceClosed(deviceId); 325 } catch (RemoteException e) { 326 Slog.i(TAG, "Failed to invoke onVirtualDeviceClosed listener: " 327 + e.getMessage()); 328 } 329 }); 330 331 Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED); 332 i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId); 333 i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 334 final long identity = Binder.clearCallingIdentity(); 335 try { 336 getContext().sendBroadcastAsUser(i, UserHandle.ALL); 337 } finally { 338 Binder.restoreCallingIdentity(identity); 339 } 340 return true; 341 } 342 onCdmAssociationsChanged(List<AssociationInfo> associations)343 void onCdmAssociationsChanged(List<AssociationInfo> associations) { 344 ArrayMap<String, AssociationInfo> vdmAssociations = new ArrayMap<>(); 345 for (int i = 0; i < associations.size(); ++i) { 346 AssociationInfo association = associations.get(i); 347 if (VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains(association.getDeviceProfile()) 348 && !association.isRevoked()) { 349 String persistentId = 350 VirtualDeviceImpl.createPersistentDeviceId(association.getId()); 351 vdmAssociations.put(persistentId, association); 352 } 353 } 354 Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>(); 355 Set<String> removedPersistentDeviceIds; 356 synchronized (mVirtualDeviceManagerLock) { 357 removedPersistentDeviceIds = mActiveAssociations.keySet(); 358 removedPersistentDeviceIds.removeAll(vdmAssociations.keySet()); 359 mActiveAssociations = vdmAssociations; 360 361 for (int i = 0; i < mVirtualDevices.size(); i++) { 362 VirtualDeviceImpl virtualDevice = mVirtualDevices.valueAt(i); 363 if (removedPersistentDeviceIds.contains(virtualDevice.getPersistentDeviceId())) { 364 virtualDevicesToRemove.add(virtualDevice); 365 } 366 } 367 } 368 369 for (VirtualDeviceImpl virtualDevice : virtualDevicesToRemove) { 370 virtualDevice.close(); 371 } 372 373 if (!removedPersistentDeviceIds.isEmpty()) { 374 mLocalService.onPersistentDeviceIdsRemoved(removedPersistentDeviceIds); 375 } 376 } 377 getVirtualDevicesSnapshot()378 private ArrayList<VirtualDeviceImpl> getVirtualDevicesSnapshot() { 379 synchronized (mVirtualDeviceManagerLock) { 380 ArrayList<VirtualDeviceImpl> virtualDevices = new ArrayList<>(mVirtualDevices.size()); 381 for (int i = 0; i < mVirtualDevices.size(); i++) { 382 virtualDevices.add(mVirtualDevices.valueAt(i)); 383 } 384 return virtualDevices; 385 } 386 } 387 getVirtualDeviceForId(int deviceId)388 private VirtualDeviceImpl getVirtualDeviceForId(int deviceId) { 389 synchronized (mVirtualDeviceManagerLock) { 390 return mVirtualDevices.get(deviceId); 391 } 392 } 393 394 class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub { 395 396 private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback = 397 new VirtualDeviceImpl.PendingTrampolineCallback() { 398 @Override 399 public void startWaitingForPendingTrampoline( 400 PendingTrampoline pendingTrampoline) { 401 PendingTrampoline existing = mPendingTrampolines.put( 402 pendingTrampoline.mPendingIntent.getCreatorPackage(), 403 pendingTrampoline); 404 if (existing != null) { 405 existing.mResultReceiver.send( 406 VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null); 407 } 408 } 409 410 @Override 411 public void stopWaitingForPendingTrampoline( 412 PendingTrampoline pendingTrampoline) { 413 mPendingTrampolines.remove( 414 pendingTrampoline.mPendingIntent.getCreatorPackage()); 415 } 416 }; 417 418 @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) 419 @Override // Binder call createVirtualDevice( IBinder token, AttributionSource attributionSource, int associationId, @NonNull VirtualDeviceParams params, @NonNull IVirtualDeviceActivityListener activityListener, @NonNull IVirtualDeviceSoundEffectListener soundEffectListener)420 public IVirtualDevice createVirtualDevice( 421 IBinder token, 422 AttributionSource attributionSource, 423 int associationId, 424 @NonNull VirtualDeviceParams params, 425 @NonNull IVirtualDeviceActivityListener activityListener, 426 @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) { 427 createVirtualDevice_enforcePermission(); 428 Objects.requireNonNull(activityListener); 429 Objects.requireNonNull(soundEffectListener); 430 final String packageName = attributionSource.getPackageName(); 431 AssociationInfo associationInfo = getAssociationInfo(packageName, associationId); 432 if (associationInfo == null) { 433 throw new IllegalArgumentException("No association with ID " + associationId); 434 } else if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains( 435 associationInfo.getDeviceProfile())) { 436 throw new IllegalArgumentException("Unsupported CDM Association device profile " 437 + associationInfo.getDeviceProfile() + " for virtual device creation."); 438 } 439 return createVirtualDevice(token, attributionSource, associationInfo, params, 440 activityListener, soundEffectListener); 441 } 442 createVirtualDevice( IBinder token, AttributionSource attributionSource, AssociationInfo associationInfo, @NonNull VirtualDeviceParams params, @Nullable IVirtualDeviceActivityListener activityListener, @Nullable IVirtualDeviceSoundEffectListener soundEffectListener)443 private IVirtualDevice createVirtualDevice( 444 IBinder token, 445 AttributionSource attributionSource, 446 AssociationInfo associationInfo, 447 @NonNull VirtualDeviceParams params, 448 @Nullable IVirtualDeviceActivityListener activityListener, 449 @Nullable IVirtualDeviceSoundEffectListener soundEffectListener) { 450 createVirtualDevice_enforcePermission(); 451 attributionSource.enforceCallingUid(); 452 453 final String packageName = attributionSource.getPackageName(); 454 if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) { 455 throw new SecurityException( 456 "Package name " + packageName + " does not belong to calling uid " 457 + getCallingUid()); 458 } 459 Objects.requireNonNull(params); 460 461 final UserHandle userHandle = getCallingUserHandle(); 462 final CameraAccessController cameraAccessController = 463 getCameraAccessController(userHandle, params, 464 attributionSource.getPackageName()); 465 final int deviceId = sNextUniqueIndex.getAndIncrement(); 466 final Consumer<ArraySet<Integer>> runningAppsChangedCallback = 467 runningUids -> notifyRunningAppsChanged(deviceId, runningUids); 468 VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(), associationInfo, 469 VirtualDeviceManagerService.this, mVirtualDeviceLog, token, attributionSource, 470 deviceId, 471 cameraAccessController, mPendingTrampolineCallback, activityListener, 472 soundEffectListener, runningAppsChangedCallback, params); 473 Counter.logIncrement("virtual_devices.value_virtual_devices_created_count"); 474 475 synchronized (mVirtualDeviceManagerLock) { 476 mVirtualDevices.put(deviceId, virtualDevice); 477 } 478 479 mVirtualDeviceListeners.broadcast(listener -> { 480 try { 481 listener.onVirtualDeviceCreated(deviceId); 482 } catch (RemoteException e) { 483 Slog.i(TAG, "Failed to invoke onVirtualDeviceCreated listener: " 484 + e.getMessage()); 485 } 486 }); 487 Counter.logIncrementWithUid( 488 "virtual_devices.value_virtual_devices_created_with_uid_count", 489 attributionSource.getUid()); 490 return virtualDevice; 491 } 492 493 @Override // Binder call getVirtualDevices()494 public List<VirtualDevice> getVirtualDevices() { 495 List<VirtualDevice> virtualDevices = new ArrayList<>(); 496 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 497 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 498 VirtualDeviceImpl device = virtualDevicesSnapshot.get(i); 499 virtualDevices.add(device.getPublicVirtualDeviceObject()); 500 } 501 return virtualDevices; 502 } 503 504 @Override // Binder call getVirtualDevice(int deviceId)505 public VirtualDevice getVirtualDevice(int deviceId) { 506 VirtualDeviceImpl device = getVirtualDeviceForId(deviceId); 507 return device == null ? null : device.getPublicVirtualDeviceObject(); 508 } 509 510 @Override // Binder call registerVirtualDeviceListener(IVirtualDeviceListener listener)511 public void registerVirtualDeviceListener(IVirtualDeviceListener listener) { 512 mVirtualDeviceListeners.register(listener); 513 } 514 515 @Override // Binder call unregisterVirtualDeviceListener(IVirtualDeviceListener listener)516 public void unregisterVirtualDeviceListener(IVirtualDeviceListener listener) { 517 mVirtualDeviceListeners.unregister(listener); 518 } 519 520 @Override // BinderCall 521 @VirtualDeviceParams.DevicePolicy getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType)522 public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) { 523 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 524 return virtualDevice != null 525 ? virtualDevice.getDevicePolicy(policyType) : DEVICE_POLICY_DEFAULT; 526 } 527 528 @Override // Binder call getDeviceIdForDisplayId(int displayId)529 public int getDeviceIdForDisplayId(int displayId) { 530 if (displayId == Display.INVALID_DISPLAY || displayId == Display.DEFAULT_DISPLAY) { 531 return Context.DEVICE_ID_DEFAULT; 532 } 533 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 534 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 535 VirtualDeviceImpl virtualDevice = virtualDevicesSnapshot.get(i); 536 if (virtualDevice.isDisplayOwnedByVirtualDevice(displayId)) { 537 return virtualDevice.getDeviceId(); 538 } 539 } 540 return Context.DEVICE_ID_DEFAULT; 541 } 542 543 @Override // Binder call getDisplayNameForPersistentDeviceId( @onNull String persistentDeviceId)544 public @Nullable CharSequence getDisplayNameForPersistentDeviceId( 545 @NonNull String persistentDeviceId) { 546 final AssociationInfo associationInfo; 547 synchronized (mVirtualDeviceManagerLock) { 548 associationInfo = mActiveAssociations.get(persistentDeviceId); 549 } 550 return associationInfo == null ? null : associationInfo.getDisplayName(); 551 } 552 553 @Override // Binder call getAllPersistentDeviceIds()554 public @NonNull List<String> getAllPersistentDeviceIds() { 555 return new ArrayList<>(mLocalService.getAllPersistentDeviceIds()); 556 } 557 558 // Binder call 559 @Override isValidVirtualDeviceId(int deviceId)560 public boolean isValidVirtualDeviceId(int deviceId) { 561 synchronized (mVirtualDeviceManagerLock) { 562 return mVirtualDevices.contains(deviceId); 563 } 564 } 565 566 @Override // Binder call getAudioPlaybackSessionId(int deviceId)567 public int getAudioPlaybackSessionId(int deviceId) { 568 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 569 return virtualDevice != null 570 ? virtualDevice.getAudioPlaybackSessionId() : AUDIO_SESSION_ID_GENERATE; 571 } 572 573 @Override // Binder call getAudioRecordingSessionId(int deviceId)574 public int getAudioRecordingSessionId(int deviceId) { 575 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 576 return virtualDevice != null 577 ? virtualDevice.getAudioRecordingSessionId() : AUDIO_SESSION_ID_GENERATE; 578 } 579 580 @Override // Binder call playSoundEffect(int deviceId, int effectType)581 public void playSoundEffect(int deviceId, int effectType) { 582 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 583 584 if (virtualDevice != null) { 585 virtualDevice.playSoundEffect(effectType); 586 } 587 } 588 589 @Override // Binder call isVirtualDeviceOwnedMirrorDisplay(int displayId)590 public boolean isVirtualDeviceOwnedMirrorDisplay(int displayId) { 591 if (getDeviceIdForDisplayId(displayId) == Context.DEVICE_ID_DEFAULT) { 592 return false; 593 } 594 595 DisplayManagerInternal displayManager = LocalServices.getService( 596 DisplayManagerInternal.class); 597 return displayManager.getDisplayIdToMirror(displayId) != Display.INVALID_DISPLAY; 598 } 599 600 @Nullable getAssociationInfo(String packageName, int associationId)601 private AssociationInfo getAssociationInfo(String packageName, int associationId) { 602 final UserHandle userHandle = getCallingUserHandle(); 603 final CompanionDeviceManager cdm = 604 getContext().createContextAsUser(userHandle, 0) 605 .getSystemService(CompanionDeviceManager.class); 606 List<AssociationInfo> associations; 607 final long identity = Binder.clearCallingIdentity(); 608 try { 609 associations = cdm.getAllAssociations(); 610 } finally { 611 Binder.restoreCallingIdentity(identity); 612 } 613 final int callingUserId = userHandle.getIdentifier(); 614 if (associations != null) { 615 final int associationSize = associations.size(); 616 for (int i = 0; i < associationSize; i++) { 617 AssociationInfo associationInfo = associations.get(i); 618 if (associationInfo.belongsToPackage(callingUserId, packageName) 619 && associationId == associationInfo.getId()) { 620 return associationInfo; 621 } 622 } 623 } else { 624 Slog.w(TAG, "No associations for user " + callingUserId); 625 } 626 return null; 627 } 628 629 @Override onTransact(int code, Parcel data, Parcel reply, int flags)630 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 631 throws RemoteException { 632 try { 633 return super.onTransact(code, data, reply, flags); 634 } catch (Throwable e) { 635 Slog.e(TAG, "Error during IPC", e); 636 throw ExceptionUtils.propagate(e, RemoteException.class); 637 } 638 } 639 640 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args)641 public void dump(@NonNull FileDescriptor fd, 642 @NonNull PrintWriter fout, 643 @Nullable String[] args) { 644 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, fout)) { 645 return; 646 } 647 fout.println("Created virtual devices: "); 648 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 649 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 650 virtualDevicesSnapshot.get(i).dump(fd, fout, args); 651 } 652 653 mVirtualDeviceLog.dump(fout); 654 } 655 } 656 657 final class VirtualDeviceManagerNativeImpl extends IVirtualDeviceManagerNative.Stub { 658 @Override // Binder call getDeviceIdsForUid(int uid)659 public int[] getDeviceIdsForUid(int uid) { 660 return mLocalService 661 .getDeviceIdsForUid(uid).stream().mapToInt(Integer::intValue).toArray(); 662 } 663 664 @Override // Binder call getDevicePolicy(int deviceId, int policyType)665 public int getDevicePolicy(int deviceId, int policyType) { 666 return mImpl.getDevicePolicy(deviceId, policyType); 667 } 668 669 @Override // Binder call getDeviceIdForDisplayId(int displayId)670 public int getDeviceIdForDisplayId(int displayId) { 671 return mImpl.getDeviceIdForDisplayId(displayId); 672 } 673 } 674 675 private final class LocalService extends VirtualDeviceManagerInternal { 676 @GuardedBy("mVirtualDeviceManagerLock") 677 private final ArrayList<AppsOnVirtualDeviceListener> mAppsOnVirtualDeviceListeners = 678 new ArrayList<>(); 679 @GuardedBy("mVirtualDeviceManagerLock") 680 private final ArrayList<Consumer<String>> mPersistentDeviceIdRemovedListeners = 681 new ArrayList<>(); 682 683 @GuardedBy("mVirtualDeviceManagerLock") 684 private final ArraySet<Integer> mAllUidsOnVirtualDevice = new ArraySet<>(); 685 686 @Override createVirtualDevice( @onNull VirtualDeviceParams params)687 public @NonNull VirtualDeviceManager.VirtualDevice createVirtualDevice( 688 @NonNull VirtualDeviceParams params) { 689 Objects.requireNonNull(params, "params must not be null"); 690 Objects.requireNonNull(params.getName(), "virtual device name must not be null"); 691 IVirtualDevice virtualDevice = mImpl.createVirtualDevice( 692 new Binder(), 693 getContext().getAttributionSource(), 694 /* associationInfo= */ null, 695 params, 696 /* activityListener= */ null, 697 /* soundEffectListener= */ null); 698 return new VirtualDeviceManager.VirtualDevice(getContext(), virtualDevice); 699 } 700 701 @Override getDeviceOwnerUid(int deviceId)702 public int getDeviceOwnerUid(int deviceId) { 703 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 704 return virtualDevice != null ? virtualDevice.getOwnerUid() : Process.INVALID_UID; 705 } 706 707 @Override getVirtualSensor(int deviceId, int handle)708 public @Nullable VirtualSensor getVirtualSensor(int deviceId, int handle) { 709 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 710 return virtualDevice != null ? virtualDevice.getVirtualSensorByHandle(handle) : null; 711 } 712 713 @Override getDeviceIdsForUid(int uid)714 public @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid) { 715 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 716 ArraySet<Integer> result = new ArraySet<>(); 717 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 718 VirtualDeviceImpl device = virtualDevicesSnapshot.get(i); 719 if (device.isAppRunningOnVirtualDevice(uid)) { 720 result.add(device.getDeviceId()); 721 } 722 } 723 return result; 724 } 725 726 @Override onVirtualDisplayCreated(IVirtualDevice virtualDevice, int displayId, IVirtualDisplayCallback callback, DisplayWindowPolicyController dwpc)727 public void onVirtualDisplayCreated(IVirtualDevice virtualDevice, int displayId, 728 IVirtualDisplayCallback callback, DisplayWindowPolicyController dwpc) { 729 VirtualDeviceImpl virtualDeviceImpl = getVirtualDeviceForId( 730 ((VirtualDeviceImpl) virtualDevice).getDeviceId()); 731 if (virtualDeviceImpl != null) { 732 virtualDeviceImpl.onVirtualDisplayCreated(displayId, callback, dwpc); 733 } 734 } 735 736 @Override onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId)737 public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) { 738 VirtualDeviceImpl virtualDeviceImpl = getVirtualDeviceForId( 739 ((VirtualDeviceImpl) virtualDevice).getDeviceId()); 740 if (virtualDeviceImpl != null) { 741 virtualDeviceImpl.onVirtualDisplayRemoved(displayId); 742 } 743 } 744 745 @Override onAppsOnVirtualDeviceChanged()746 public void onAppsOnVirtualDeviceChanged() { 747 ArraySet<Integer> latestRunningUids = new ArraySet<>(); 748 final AppsOnVirtualDeviceListener[] listeners; 749 synchronized (mVirtualDeviceManagerLock) { 750 int size = mAppsOnVirtualDevices.size(); 751 for (int i = 0; i < size; i++) { 752 latestRunningUids.addAll(mAppsOnVirtualDevices.valueAt(i)); 753 } 754 if (!mAllUidsOnVirtualDevice.equals(latestRunningUids)) { 755 mAllUidsOnVirtualDevice.clear(); 756 mAllUidsOnVirtualDevice.addAll(latestRunningUids); 757 listeners = 758 mAppsOnVirtualDeviceListeners.toArray( 759 new AppsOnVirtualDeviceListener[0]); 760 } else { 761 listeners = null; 762 } 763 } 764 if (listeners != null) { 765 mHandler.post(() -> { 766 for (AppsOnVirtualDeviceListener listener : listeners) { 767 listener.onAppsOnAnyVirtualDeviceChanged(latestRunningUids); 768 } 769 }); 770 } 771 } 772 773 @Override onPersistentDeviceIdsRemoved(Set<String> removedPersistentDeviceIds)774 public void onPersistentDeviceIdsRemoved(Set<String> removedPersistentDeviceIds) { 775 final List<Consumer<String>> persistentDeviceIdRemovedListeners; 776 synchronized (mVirtualDeviceManagerLock) { 777 persistentDeviceIdRemovedListeners = List.copyOf( 778 mPersistentDeviceIdRemovedListeners); 779 } 780 mHandler.post(() -> { 781 for (String persistentDeviceId : removedPersistentDeviceIds) { 782 for (Consumer<String> listener : persistentDeviceIdRemovedListeners) { 783 listener.accept(persistentDeviceId); 784 } 785 } 786 }); 787 } 788 789 @Override onAuthenticationPrompt(int uid)790 public void onAuthenticationPrompt(int uid) { 791 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 792 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 793 VirtualDeviceImpl device = virtualDevicesSnapshot.get(i); 794 device.showToastWhereUidIsRunning(uid, 795 R.string.app_streaming_blocked_message_for_fingerprint_dialog, 796 Toast.LENGTH_LONG, Looper.getMainLooper()); 797 } 798 } 799 800 @Override getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice)801 public int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice) { 802 return ((VirtualDeviceImpl) virtualDevice).getBaseVirtualDisplayFlags(); 803 } 804 805 @Override 806 @Nullable getPreferredLocaleListForUid(int uid)807 public LocaleList getPreferredLocaleListForUid(int uid) { 808 // TODO: b/263188984 support the case where an app is running on multiple VDs 809 VirtualDeviceImpl virtualDevice = null; 810 synchronized (mVirtualDeviceManagerLock) { 811 for (int i = 0; i < mAppsOnVirtualDevices.size(); i++) { 812 if (mAppsOnVirtualDevices.valueAt(i).contains(uid)) { 813 int deviceId = mAppsOnVirtualDevices.keyAt(i); 814 virtualDevice = mVirtualDevices.get(deviceId); 815 break; 816 } 817 } 818 } 819 return virtualDevice == null ? null : virtualDevice.getDeviceLocaleList(); 820 } 821 822 @Override isAppRunningOnAnyVirtualDevice(int uid)823 public boolean isAppRunningOnAnyVirtualDevice(int uid) { 824 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 825 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 826 if (virtualDevicesSnapshot.get(i).isAppRunningOnVirtualDevice(uid)) { 827 return true; 828 } 829 } 830 return false; 831 } 832 833 @Override isInputDeviceOwnedByVirtualDevice(int inputDeviceId)834 public boolean isInputDeviceOwnedByVirtualDevice(int inputDeviceId) { 835 ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); 836 for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { 837 if (virtualDevicesSnapshot.get(i) 838 .isInputDeviceOwnedByVirtualDevice(inputDeviceId)) { 839 return true; 840 } 841 } 842 return false; 843 } 844 845 @Override getDisplayIdsForDevice(int deviceId)846 public @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId) { 847 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 848 return virtualDevice == null ? new ArraySet<>() 849 : Arrays.stream(virtualDevice.getDisplayIds()).boxed() 850 .collect(Collectors.toCollection(ArraySet::new)); 851 } 852 853 @Override getDeviceIdForDisplayId(int displayId)854 public int getDeviceIdForDisplayId(int displayId) { 855 return mImpl.getDeviceIdForDisplayId(displayId); 856 } 857 858 @Override getVirtualDevice(int deviceId)859 public VirtualDevice getVirtualDevice(int deviceId) { 860 return mImpl.getVirtualDevice(deviceId); 861 } 862 863 @Override getDimDurationMillisForDeviceId(int deviceId)864 public long getDimDurationMillisForDeviceId(int deviceId) { 865 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 866 return virtualDevice == null ? -1 : virtualDevice.getDimDurationMillis(); 867 } 868 869 @Override getScreenOffTimeoutMillisForDeviceId(int deviceId)870 public long getScreenOffTimeoutMillisForDeviceId(int deviceId) { 871 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 872 return virtualDevice == null ? -1 : virtualDevice.getScreenOffTimeoutMillis(); 873 } 874 875 @Override isValidVirtualDeviceId(int deviceId)876 public boolean isValidVirtualDeviceId(int deviceId) { 877 return mImpl.isValidVirtualDeviceId(deviceId); 878 } 879 880 @Override getPersistentIdForDevice(int deviceId)881 public @Nullable String getPersistentIdForDevice(int deviceId) { 882 if (deviceId == Context.DEVICE_ID_DEFAULT) { 883 return VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT; 884 } 885 886 VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); 887 return virtualDevice == null ? null : virtualDevice.getPersistentDeviceId(); 888 } 889 890 @Override getAllPersistentDeviceIds()891 public @NonNull Set<String> getAllPersistentDeviceIds() { 892 synchronized (mVirtualDeviceManagerLock) { 893 return Set.copyOf(mActiveAssociations.keySet()); 894 } 895 } 896 897 @Override registerAppsOnVirtualDeviceListener( @onNull AppsOnVirtualDeviceListener listener)898 public void registerAppsOnVirtualDeviceListener( 899 @NonNull AppsOnVirtualDeviceListener listener) { 900 synchronized (mVirtualDeviceManagerLock) { 901 mAppsOnVirtualDeviceListeners.add(listener); 902 } 903 } 904 905 @Override unregisterAppsOnVirtualDeviceListener( @onNull AppsOnVirtualDeviceListener listener)906 public void unregisterAppsOnVirtualDeviceListener( 907 @NonNull AppsOnVirtualDeviceListener listener) { 908 synchronized (mVirtualDeviceManagerLock) { 909 mAppsOnVirtualDeviceListeners.remove(listener); 910 } 911 } 912 913 @Override registerPersistentDeviceIdRemovedListener( @onNull Consumer<String> persistentDeviceIdRemovedListener)914 public void registerPersistentDeviceIdRemovedListener( 915 @NonNull Consumer<String> persistentDeviceIdRemovedListener) { 916 synchronized (mVirtualDeviceManagerLock) { 917 mPersistentDeviceIdRemovedListeners.add(persistentDeviceIdRemovedListener); 918 } 919 } 920 921 @Override unregisterPersistentDeviceIdRemovedListener( @onNull Consumer<String> persistentDeviceIdRemovedListener)922 public void unregisterPersistentDeviceIdRemovedListener( 923 @NonNull Consumer<String> persistentDeviceIdRemovedListener) { 924 synchronized (mVirtualDeviceManagerLock) { 925 mPersistentDeviceIdRemovedListeners.remove(persistentDeviceIdRemovedListener); 926 } 927 } 928 } 929 930 private static final class PendingTrampolineMap { 931 /** 932 * The maximum duration, in milliseconds, to wait for a trampoline activity launch after 933 * invoking a pending intent. 934 */ 935 private static final int TRAMPOLINE_WAIT_MS = 5000; 936 937 private final ConcurrentHashMap<String, PendingTrampoline> mMap = new ConcurrentHashMap<>(); 938 private final Handler mHandler; 939 PendingTrampolineMap(Handler handler)940 PendingTrampolineMap(Handler handler) { 941 mHandler = handler; 942 } 943 put( @onNull String packageName, @NonNull PendingTrampoline pendingTrampoline)944 PendingTrampoline put( 945 @NonNull String packageName, @NonNull PendingTrampoline pendingTrampoline) { 946 PendingTrampoline existing = mMap.put(packageName, pendingTrampoline); 947 mHandler.removeCallbacksAndMessages(existing); 948 mHandler.postDelayed( 949 () -> { 950 final String creatorPackage = 951 pendingTrampoline.mPendingIntent.getCreatorPackage(); 952 if (creatorPackage != null) { 953 remove(creatorPackage); 954 } 955 }, 956 pendingTrampoline, 957 TRAMPOLINE_WAIT_MS); 958 return existing; 959 } 960 remove(@onNull String packageName)961 PendingTrampoline remove(@NonNull String packageName) { 962 PendingTrampoline pendingTrampoline = mMap.remove(packageName); 963 mHandler.removeCallbacksAndMessages(pendingTrampoline); 964 return pendingTrampoline; 965 } 966 } 967 } 968