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

Commit 604bf23d authored by Biswarup Pal's avatar Biswarup Pal
Browse files

Allow VDM to access default device camera

By default, allow a virtual device to access the default
device camera and add an API for the virtual device owner
to explicitly disallow this during the creation of the virtual
device. Also, clean up the old stream_camera flag, as this
change is guarded by a new flag and a targetSdk check.

Test: atest VirtualDeviceParamsTest
Bug: 371173368
Flag: android.companion.virtualdevice.flags.default_device_camera_access_policy
Change-Id: Iedf68beb2a9f3003f675e125605facf8837dcb1b
parent d8e5981d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3575,6 +3575,7 @@ package android.companion.virtual {
    field @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6; // 0x6
    field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5
    field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
    field @FlaggedApi("android.companion.virtualdevice.flags.default_device_camera_access_policy") public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7; // 0x7
    field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
    field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
  }
+21 −2
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ public final class VirtualDeviceParams implements Parcelable {
     */
    @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
            POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, POLICY_TYPE_CLIPBOARD, POLICY_TYPE_CAMERA,
            POLICY_TYPE_BLOCKED_ACTIVITY})
            POLICY_TYPE_BLOCKED_ACTIVITY, POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS})
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface PolicyType {}
@@ -301,6 +301,21 @@ public final class VirtualDeviceParams implements Parcelable {
    @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
    public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6;

    /**
     * Tells the virtual device framework how to handle camera access of the default device by apps
     * running on the virtual device.
     *
     * <ul>
     *     <li>{@link #DEVICE_POLICY_DEFAULT}: Default device camera access will be allowed.
     *     <li>{@link #DEVICE_POLICY_CUSTOM}: Default device camera access will be blocked.
     * </ul>
     *
     * @see Context#DEVICE_ID_DEFAULT
     */
    @FlaggedApi(android.companion.virtualdevice.flags.Flags
            .FLAG_DEFAULT_DEVICE_CAMERA_ACCESS_POLICY)
    public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7;

    private final int mLockState;
    @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
    @NavigationPolicy
@@ -696,7 +711,7 @@ public final class VirtualDeviceParams implements Parcelable {

    @NonNull
    public static final Parcelable.Creator<VirtualDeviceParams> CREATOR =
            new Parcelable.Creator<VirtualDeviceParams>() {
            new Parcelable.Creator<>() {
                public VirtualDeviceParams createFromParcel(Parcel in) {
                    return new VirtualDeviceParams(in);
                }
@@ -1213,6 +1228,10 @@ public final class VirtualDeviceParams implements Parcelable {
                mDevicePolicies.delete(POLICY_TYPE_CAMERA);
            }

            if (!android.companion.virtualdevice.flags.Flags.defaultDeviceCameraAccessPolicy()) {
                mDevicePolicies.delete(POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS);
            }

            if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
                mDevicePolicies.delete(POLICY_TYPE_BLOCKED_ACTIVITY);
            }
+0 −7
Original line number Diff line number Diff line
@@ -66,13 +66,6 @@ flag {
  bug: "270352264"
}

flag {
  name: "stream_camera"
  namespace: "virtual_devices"
  description: "Enable streaming camera to Virtual Devices"
  bug: "291740640"
}

flag {
  name: "persistent_device_id_api"
  is_exported: true
+11 −2
Original line number Diff line number Diff line
@@ -59,14 +59,14 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
    private int mObserverCount = 0;

    @GuardedBy("mLock")
    private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
    private final ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();

    /**
     * Mapping from camera ID to open camera app associations. Key is the camera id, value is the
     * information of the app's uid and package name.
     */
    @GuardedBy("mLock")
    private ArrayMap<String, OpenCameraInfo> mAppsToBlockOnVirtualDevice = new ArrayMap<>();
    private final ArrayMap<String, OpenCameraInfo> mAppsToBlockOnVirtualDevice = new ArrayMap<>();

    static class InjectionSessionData {
        public int appUid;
@@ -179,6 +179,15 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
                Slog.w(TAG, "Unexpected close with observers remaining: " + mObserverCount);
            }
        }
        // Clean up camera injection sessions (if any).
        synchronized (mLock) {
            for (InjectionSessionData sessionData : mPackageToSessionData.values()) {
                for (CameraInjectionSession session : sessionData.cameraIdToSession.values()) {
                    session.close();
                }
            }
            mPackageToSessionData.clear();
        }
        mCameraManager.unregisterAvailabilityCallback(this);
    }

+21 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.companion.virtual;

import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS;
import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;

import static com.android.server.wm.ActivityInterceptorCallback.VIRTUAL_DEVICE_SERVICE_ORDERED_ID;
@@ -27,6 +28,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.app.compat.CompatChanges;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
@@ -41,11 +43,14 @@ import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.flags.Flags;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtualnative.IVirtualDeviceManagerNative;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.AttributionSource;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManagerInternal;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
@@ -88,7 +93,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;


@SuppressLint("LongLogTag")
public class VirtualDeviceManagerService extends SystemService {

@@ -101,6 +105,11 @@ public class VirtualDeviceManagerService extends SystemService {
            AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
            AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING);

    /** Enable default device camera access for apps running on virtual devices. */
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
    public static final long ENABLE_DEFAULT_DEVICE_CAMERA_ACCESS = 371173368L;

    /**
     * A virtual device association id corresponding to no CDM association.
     */
@@ -110,7 +119,7 @@ public class VirtualDeviceManagerService extends SystemService {
    private final VirtualDeviceManagerImpl mImpl;
    private final VirtualDeviceManagerNativeImpl mNativeImpl;
    private final VirtualDeviceManagerInternal mLocalService;
    private VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext());
    private final VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext());
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler);

@@ -236,7 +245,7 @@ public class VirtualDeviceManagerService extends SystemService {
        }
    }

    void onCameraAccessBlocked(int appUid) {
    private void onCameraAccessBlocked(int appUid) {
        ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot();
        for (int i = 0; i < virtualDevicesSnapshot.size(); i++) {
            VirtualDeviceImpl virtualDevice = virtualDevicesSnapshot.get(i);
@@ -248,8 +257,13 @@ public class VirtualDeviceManagerService extends SystemService {
        }
    }

    CameraAccessController getCameraAccessController(UserHandle userHandle) {
        if (Flags.streamCamera()) {
    private CameraAccessController getCameraAccessController(UserHandle userHandle,
            VirtualDeviceParams params, String callingPackage) {
        if (CompatChanges.isChangeEnabled(ENABLE_DEFAULT_DEVICE_CAMERA_ACCESS, callingPackage,
                userHandle)
                && android.companion.virtualdevice.flags.Flags.defaultDeviceCameraAccessPolicy()
                && (params.getDevicePolicy(POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS)
                    == DEVICE_POLICY_DEFAULT)) {
            return null;
        }
        int userId = userHandle.getIdentifier();
@@ -496,7 +510,8 @@ public class VirtualDeviceManagerService extends SystemService {

            final UserHandle userHandle = getCallingUserHandle();
            final CameraAccessController cameraAccessController =
                    getCameraAccessController(userHandle);
                    getCameraAccessController(userHandle, params,
                            attributionSource.getPackageName());
            final int deviceId = sNextUniqueIndex.getAndIncrement();
            final Consumer<ArraySet<Integer>> runningAppsChangedCallback =
                    runningUids -> notifyRunningAppsChanged(deviceId, runningUids);