diff options
7 files changed, 124 insertions, 22 deletions
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl index 24f18cc257f8..11b0327e152c 100644 --- a/core/java/android/companion/virtual/IVirtualDevice.aidl +++ b/core/java/android/companion/virtual/IVirtualDevice.aidl @@ -17,7 +17,9 @@ package android.companion.virtual; import android.app.PendingIntent; +import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; +import android.companion.virtual.IVirtualDeviceSoundEffectListener; import android.companion.virtual.audio.IAudioConfigChangedCallback; import android.companion.virtual.audio.IAudioRoutingCallback; import android.companion.virtual.sensor.VirtualSensor; @@ -282,4 +284,15 @@ interface IVirtualDevice { */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") String getVirtualCameraId(in VirtualCameraConfig camera); + + /** + * Setter for listeners that live in the client process, namely in + * {@link android.companion.virtual.VirtualDeviceInternal}. + * + * This is needed for virtual devices that are created by the system, as the VirtualDeviceImpl + * object is created before the returned VirtualDeviceInternal one. + */ + @EnforcePermission("CREATE_VIRTUAL_DEVICE") + void setListeners(in IVirtualDeviceActivityListener activityListener, + in IVirtualDeviceSoundEffectListener soundEffectListener); } diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java index 60448bad8e69..bb86af754b95 100644 --- a/core/java/android/companion/virtual/VirtualDeviceInternal.java +++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java @@ -162,6 +162,20 @@ public class VirtualDeviceInternal { mSoundEffectListener); } + VirtualDeviceInternal( + IVirtualDeviceManager service, + Context context, + IVirtualDevice virtualDevice) { + mService = service; + mContext = context.getApplicationContext(); + mVirtualDevice = virtualDevice; + try { + mVirtualDevice.setListeners(mActivityListenerBinder, mSoundEffectListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + int getDeviceId() { try { return mVirtualDevice.getDeviceId(); diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index ed55a3fe4392..a3c9ff7b653d 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -573,6 +573,12 @@ public final class VirtualDeviceManager { new VirtualDeviceInternal(service, context, associationId, params); } + /** @hide */ + public VirtualDevice(IVirtualDeviceManager service, Context context, + IVirtualDevice virtualDevice) { + mVirtualDeviceInternal = new VirtualDeviceInternal(service, context, virtualDevice); + } + /** * Returns the unique ID of this virtual device. */ diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 6704049e3612..f47c014a7e59 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -183,8 +183,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub private final SparseIntArray mDevicePolicies; @GuardedBy("mVirtualDeviceLock") private final SparseArray<VirtualDisplayWrapper> mVirtualDisplays = new SparseArray<>(); - private final IVirtualDeviceActivityListener mActivityListener; - private final IVirtualDeviceSoundEffectListener mSoundEffectListener; + private IVirtualDeviceActivityListener mActivityListener; + private IVirtualDeviceSoundEffectListener mSoundEffectListener; private final DisplayManagerGlobal mDisplayManager; private final DisplayManagerInternal mDisplayManagerInternal; @GuardedBy("mVirtualDeviceLock") @@ -301,7 +301,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(attributionSource.getUid()); mContext = context.createContextAsUser(ownerUserHandle, 0); mAssociationInfo = associationInfo; - mPersistentDeviceId = createPersistentDeviceId(associationInfo.getId()); + mPersistentDeviceId = associationInfo == null + ? null + : createPersistentDeviceId(associationInfo.getId()); mService = service; mPendingTrampolineCallback = pendingTrampolineCallback; mActivityListener = activityListener; @@ -403,7 +405,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub /** Returns the device display name. */ CharSequence getDisplayName() { - return mAssociationInfo.getDisplayName(); + return mAssociationInfo == null ? mParams.getName() : mAssociationInfo.getDisplayName(); } /** Returns the public representation of the device. */ @@ -418,6 +420,22 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } } + /** + * Setter for listeners that live in the client process, namely in + * {@link android.companion.virtual.VirtualDeviceInternal}. + * + * This is needed for virtual devices that are created by the system, as the VirtualDeviceImpl + * object is created before the returned VirtualDeviceInternal one. + */ + @Override // Binder call + @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) + public void setListeners(@NonNull IVirtualDeviceActivityListener activityListener, + @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) { + super.setListeners_enforcePermission(); + mActivityListener = Objects.requireNonNull(activityListener); + mSoundEffectListener = Objects.requireNonNull(soundEffectListener); + } + @Override // Binder call public @VirtualDeviceParams.DevicePolicy int getDevicePolicy( @VirtualDeviceParams.PolicyType int policyType) { @@ -454,7 +472,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call public int getAssociationId() { - return mAssociationInfo.getId(); + return mAssociationInfo == null + ? VirtualDeviceManagerService.CDM_ASSOCIATION_ID_NONE + : mAssociationInfo.getId(); } @Override // Binder call @@ -1105,7 +1125,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub String indent = " "; fout.println(" VirtualDevice: "); fout.println(indent + "mDeviceId: " + mDeviceId); - fout.println(indent + "mAssociationId: " + mAssociationInfo.getId()); + fout.println(indent + "mAssociationId: " + getAssociationId()); fout.println(indent + "mOwnerPackageName: " + mOwnerPackageName); fout.println(indent + "mParams: "); mParams.dump(fout, indent + indent); @@ -1251,8 +1271,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) private void onActivityBlocked(int displayId, ActivityInfo activityInfo) { - Intent intent = BlockedAppStreamingActivity.createIntent( - activityInfo, mAssociationInfo.getDisplayName()); + Intent intent = BlockedAppStreamingActivity.createIntent(activityInfo, getDisplayName()); mContext.startActivityAsUser( intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK), ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(), @@ -1339,7 +1358,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @SuppressWarnings("AndroidFrameworkRequiresPermission") private void checkVirtualInputDeviceDisplayIdAssociation(int displayId) { - if (mContext.checkCallingPermission(android.Manifest.permission.INJECT_EVENTS) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INJECT_EVENTS) == PackageManager.PERMISSION_GRANTED) { // The INJECT_EVENTS permission allows for injecting input to any window / display. return; diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java index c65aa5bd355b..b0bacfd158ed 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java @@ -19,6 +19,7 @@ package com.android.server.companion.virtual; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; +import android.os.Process; import android.util.SparseArray; import java.io.PrintWriter; @@ -35,6 +36,8 @@ final class VirtualDeviceLog { "MM-dd HH:mm:ss.SSS").withZone(ZoneId.systemDefault()); private static final int MAX_ENTRIES = 16; + private static final String VIRTUAL_DEVICE_OWNER_SYSTEM = "system"; + private final Context mContext; private final ArrayDeque<LogEntry> mLogEntries = new ArrayDeque<>(); @@ -132,6 +135,8 @@ final class VirtualDeviceLog { String[] packages; if (mUidToPackagesCache.contains(ownerUid)) { return mUidToPackagesCache.get(ownerUid); + } else if (ownerUid == Process.SYSTEM_UID) { + return VIRTUAL_DEVICE_OWNER_SYSTEM; } else { packages = mPackageManager.getPackagesForUid(ownerUid); String packageName = ""; diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index 9ad73cae08cd..1be1d2b1286b 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -101,6 +101,11 @@ public class VirtualDeviceManagerService extends SystemService { AssociationRequest.DEVICE_PROFILE_APP_STREAMING, AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING); + /** + * A virtual device association id corresponding to no CDM association. + */ + static final int CDM_ASSOCIATION_ID_NONE = 0; + private final Object mVirtualDeviceManagerLock = new Object(); private final VirtualDeviceManagerImpl mImpl; private final VirtualDeviceManagerNativeImpl mNativeImpl; @@ -316,7 +321,9 @@ public class VirtualDeviceManagerService extends SystemService { for (int i = 0; i < mVirtualDevices.size(); i++) { VirtualDeviceImpl virtualDevice = mVirtualDevices.valueAt(i); - if (!activeAssociationIds.contains(virtualDevice.getAssociationId())) { + int deviceAssociationId = virtualDevice.getAssociationId(); + if (deviceAssociationId != CDM_ASSOCIATION_ID_NONE + && !activeAssociationIds.contains(deviceAssociationId)) { virtualDevicesToRemove.add(virtualDevice); } } @@ -422,28 +429,39 @@ public class VirtualDeviceManagerService extends SystemService { @NonNull IVirtualDeviceActivityListener activityListener, @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) { createVirtualDevice_enforcePermission(); - attributionSource.enforceCallingUid(); - - final int callingUid = getCallingUid(); + Objects.requireNonNull(activityListener); + Objects.requireNonNull(soundEffectListener); final String packageName = attributionSource.getPackageName(); - if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) { - throw new SecurityException( - "Package name " + packageName + " does not belong to calling uid " - + callingUid); - } AssociationInfo associationInfo = getAssociationInfo(packageName, associationId); if (associationInfo == null) { throw new IllegalArgumentException("No association with ID " + associationId); - } - if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES + } else if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES .contains(associationInfo.getDeviceProfile()) && Flags.persistentDeviceIdApi()) { throw new IllegalArgumentException("Unsupported CDM Association device profile " + associationInfo.getDeviceProfile() + " for virtual device creation."); } + return createVirtualDevice(token, attributionSource, associationInfo, params, + activityListener, soundEffectListener); + } + + private IVirtualDevice createVirtualDevice( + IBinder token, + AttributionSource attributionSource, + AssociationInfo associationInfo, + @NonNull VirtualDeviceParams params, + @Nullable IVirtualDeviceActivityListener activityListener, + @Nullable IVirtualDeviceSoundEffectListener soundEffectListener) { + createVirtualDevice_enforcePermission(); + attributionSource.enforceCallingUid(); + + final String packageName = attributionSource.getPackageName(); + if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) { + throw new SecurityException( + "Package name " + packageName + " does not belong to calling uid " + + getCallingUid()); + } Objects.requireNonNull(params); - Objects.requireNonNull(activityListener); - Objects.requireNonNull(soundEffectListener); final UserHandle userHandle = getCallingUserHandle(); final CameraAccessController cameraAccessController = @@ -724,6 +742,21 @@ public class VirtualDeviceManagerService extends SystemService { private final ArraySet<Integer> mAllUidsOnVirtualDevice = new ArraySet<>(); @Override + public @NonNull VirtualDeviceManager.VirtualDevice createVirtualDevice( + @NonNull VirtualDeviceParams params) { + Objects.requireNonNull(params, "params must not be null"); + Objects.requireNonNull(params.getName(), "virtual device name must not be null"); + IVirtualDevice virtualDevice = mImpl.createVirtualDevice( + new Binder(), + getContext().getAttributionSource(), + /* associationInfo= */ null, + params, + /* activityListener= */ null, + /* soundEffectListener= */ null); + return new VirtualDeviceManager.VirtualDevice(mImpl, getContext(), virtualDevice); + } + + @Override public int getDeviceOwnerUid(int deviceId) { VirtualDeviceImpl virtualDevice; synchronized (mVirtualDeviceManagerLock) { diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java index b17978370bd7..6e38733f04c2 100644 --- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java +++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.companion.virtual.IVirtualDevice; import android.companion.virtual.VirtualDevice; +import android.companion.virtual.VirtualDeviceManager; +import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.sensor.VirtualSensor; import android.content.Context; import android.os.LocaleList; @@ -180,4 +182,14 @@ public abstract class VirtualDeviceManagerInternal { * exists, as long as one may have existed or can be created. */ public abstract @NonNull Set<String> getAllPersistentDeviceIds(); + + /** + * Creates a virtual device where applications can launch and receive input events injected by + * the creator. + * + * <p>A Companion Device Manager association is not required. Only the system may create such + * virtual devices.</p> + */ + public abstract @NonNull VirtualDeviceManager.VirtualDevice createVirtualDevice( + @NonNull VirtualDeviceParams params); } |