Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9892548d authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

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
parent 9962f020
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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);
}
+14 −0
Original line number Diff line number Diff line
@@ -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();
+6 −0
Original line number Diff line number Diff line
@@ -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.
         */
+28 −9
Original line number Diff line number Diff line
@@ -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;
+5 −0
Original line number Diff line number Diff line
@@ -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 = "";
Loading