• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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