summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Komsiyski <vladokom@google.com> 2024-03-06 15:44:25 +0100
committer Vladimir Komsiyski <vladokom@google.com> 2024-06-27 09:46:22 +0000
commit9892548d2a69ce8477d4e38e75608bc97ad6d55f (patch)
tree650befb98327ea5535fb28ad85d5bc359deb8c86
parent9962f0204bf0eb768c169c51d6a31372a574f9eb (diff)
Support CDM-less virtual devices.
- New VDMInternal#createVirtualDevice, which creates a VD with CDM association id = 0 and display name from the params. The name is required in this case (it's optional otherwise) - The VD is fully functional, it just doesn't have a persistent id. - The VD is also visible via the public VDM APIs. This is by design, because if any activity ever runs on such device its deviceId will not be the default one and the app must be able to get to that VirtualDevice and its capabilities. - Never assume that VirtualDeviceImpl#mAssociationInfo is not null Not testable in CTS and not really flaggable. A flag disabling the new functionality will effectively crash system server when off. Fix: 341060398 Test: manual Flag: EXEMPT behavioural change Change-Id: I65eca165362b0ef819d55b743de8a7780646c26e
-rw-r--r--core/java/android/companion/virtual/IVirtualDevice.aidl13
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceInternal.java14
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java37
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceLog.java5
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java59
-rw-r--r--services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java12
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);
}