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

Commit f1e7be07 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "virtualdevice-params"

* changes:
  Implement VirtualDevice's device policy enforcement
  Add params object to createVirtualDevice
parents a6d19a4b a4ed6819
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.companion.virtual;

import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.VirtualDeviceParams;

/**
 * Interface for communication between VirtualDeviceManager and VirtualDeviceManagerService.
@@ -33,6 +34,10 @@ interface IVirtualDeviceManager {
     *   that this belongs to the calling UID.
     * @param associationId The association ID as returned by {@link AssociationInfo#getId()} from
     *   CDM. Virtual devices must have a corresponding association with CDM in order to be created.
     * @param params The parameters for creating this virtual device. See {@link
     *   VirtualDeviceManager.VirtualDeviceParams}.
     */
    IVirtualDevice createVirtualDevice(in IBinder token, String packageName, int associationId);
    IVirtualDevice createVirtualDevice(
            in IBinder token, String packageName, int associationId,
            in VirtualDeviceParams params);
}
+8 −2
Original line number Diff line number Diff line
@@ -100,11 +100,11 @@ public final class VirtualDeviceManager {
     */
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    @Nullable
    public VirtualDevice createVirtualDevice(int associationId) {
    public VirtualDevice createVirtualDevice(int associationId, VirtualDeviceParams params) {
        // TODO(b/194949534): Unhide this API
        try {
            IVirtualDevice virtualDevice = mService.createVirtualDevice(
                    new Binder(), mContext.getPackageName(), associationId);
                    new Binder(), mContext.getPackageName(), associationId, params);
            return new VirtualDevice(mContext, virtualDevice);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -273,6 +273,12 @@ public final class VirtualDeviceManager {
            }
        }

        /**
         * Returns the display flags that should be added to a particular virtual display.
         * Additional device-level flags from {@link
         * com.android.server.companion.virtual.VirtualDeviceImpl#getBaseVirtualDisplayFlags()} will
         * be added by DisplayManagerService.
         */
        private int getVirtualDisplayFlags(@DisplayFlags int flags) {
            int virtualDisplayFlags = DEFAULT_VIRTUAL_DISPLAY_FLAGS;
            if ((flags & DISPLAY_FLAG_TRUSTED) != 0) {
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.companion.virtual;

parcelable VirtualDeviceParams;
+197 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.companion.virtual;

import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.ArraySet;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;

/**
 * Params that can be configured when creating virtual devices.
 *
 * @hide
 */
// TODO(b/194949534): Unhide this API
public final class VirtualDeviceParams implements Parcelable {

    /** @hide */
    @IntDef(prefix = "LOCK_STATE_",
            value = {LOCK_STATE_ALWAYS_LOCKED, LOCK_STATE_ALWAYS_UNLOCKED})
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface LockState {}

    /**
     * Indicates that the lock state of the virtual device should be always locked.
     *
     * @hide  // TODO(b/194949534): Unhide this API
     */
    public static final int LOCK_STATE_ALWAYS_LOCKED = 0;

    /**
     * Indicates that the lock state of the virtual device should be always unlocked.
     *
     * @hide  // TODO(b/194949534): Unhide this API
     */
    public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1;

    private final int mLockState;
    private final ArraySet<UserHandle> mUsersWithMatchingAccounts;

    private VirtualDeviceParams(
            @LockState int lockState,
            @NonNull Set<UserHandle> usersWithMatchingAccounts) {
        mLockState = lockState;
        mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
    }

    @SuppressWarnings("unchecked")
    private VirtualDeviceParams(Parcel parcel) {
        mLockState = parcel.readInt();
        mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
    }

    /**
     * Returns the lock state of the virtual device.
     */
    @LockState
    public int getLockState() {
        return mLockState;
    }

    /**
     * Returns the user handles with matching managed accounts on the remote device to which
     * this virtual device is streaming.
     *
     * @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
     */
    @NonNull
    public Set<UserHandle> getUsersWithMatchingAccounts() {
        return Collections.unmodifiableSet(mUsersWithMatchingAccounts);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mLockState);
        dest.writeArraySet(mUsersWithMatchingAccounts);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof VirtualDeviceParams)) {
            return false;
        }
        VirtualDeviceParams that = (VirtualDeviceParams) o;
        return mLockState == that.mLockState && mUsersWithMatchingAccounts.equals(
                that.mUsersWithMatchingAccounts);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mLockState, mUsersWithMatchingAccounts);
    }

    @Override
    public String toString() {
        return "VirtualDeviceParams("
                + " mLockState=" + mLockState
                + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
                + ")";
    }

    public static final Parcelable.Creator<VirtualDeviceParams> CREATOR =
            new Parcelable.Creator<VirtualDeviceParams>() {
                public VirtualDeviceParams createFromParcel(Parcel in) {
                    return new VirtualDeviceParams(in);
                }

                public VirtualDeviceParams[] newArray(int size) {
                    return new VirtualDeviceParams[size];
                }
            };

    /**
     * Builder for {@link VirtualDeviceParams}.
     */
    public static final class Builder {

        private @LockState int mLockState = LOCK_STATE_ALWAYS_LOCKED;
        private Set<UserHandle> mUsersWithMatchingAccounts;

        /**
         * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
         * is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
         * The default is {@link #LOCK_STATE_ALWAYS_LOCKED}.
         *
         * @param lockState The lock state, either {@link #LOCK_STATE_ALWAYS_LOCKED} or
         *   {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
         */
        @RequiresPermission(value = ADD_ALWAYS_UNLOCKED_DISPLAY, conditional = true)
        @NonNull
        public Builder setLockState(@LockState int lockState) {
            mLockState = lockState;
            return this;
        }

        /**
         * Sets the user handles with matching managed accounts on the remote device to which
         * this virtual device is streaming.
         *
         * @param usersWithMatchingAccounts A set of user handles with matching managed
         *   accounts on the remote device this is streaming to.
         * @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
         */
        public Builder setUsersWithMatchingAccounts(
                @NonNull Set<UserHandle> usersWithMatchingAccounts) {
            mUsersWithMatchingAccounts = usersWithMatchingAccounts;
            return this;
        }

        /**
         * Builds the {@link VirtualDeviceParams} instance.
         */
        @NonNull
        public VirtualDeviceParams build() {
            if (mUsersWithMatchingAccounts == null) {
                mUsersWithMatchingAccounts = Collections.emptySet();
            }
            return new VirtualDeviceParams(mLockState, mUsersWithMatchingAccounts);
        }
    }
}
+36 −19
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.companion.virtual;

import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

@@ -27,9 +28,10 @@ import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
import android.window.DisplayWindowPolicyController;

import java.util.HashSet;
import java.util.List;


@@ -38,6 +40,8 @@ import java.util.List;
 */
class GenericWindowPolicyController extends DisplayWindowPolicyController {

    private static final String TAG = "VirtualDeviceManager";

    /**
     * If required, allow the secure activity to display on remote device since
     * {@link android.os.Build.VERSION_CODES#TIRAMISU}.
@@ -45,10 +49,13 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
    @NonNull private final ArraySet<UserHandle> mAllowedUsers;

    @NonNull final HashSet<Integer> mRunningUids = new HashSet<>();
    @NonNull final ArraySet<Integer> mRunningUids = new ArraySet<>();

    GenericWindowPolicyController(int windowFlags, int systemWindowFlags) {
    GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
            @NonNull ArraySet<UserHandle> allowedUsers) {
        mAllowedUsers = allowedUsers;
        setInterestedWindowFlags(windowFlags, systemWindowFlags);
    }

@@ -58,7 +65,7 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
        final int activityCount = activities.size();
        for (int i = 0; i < activityCount; i++) {
            final ActivityInfo aInfo = activities.get(i);
            if ((aInfo.flags & ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
            if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
                return false;
            }
        }
@@ -68,21 +75,7 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
    @Override
    public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
            int systemWindowFlags) {
        if ((activityInfo.flags & ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
            return false;
        }
        if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
                activityInfo.packageName,
                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid))) {
            // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
            if ((windowFlags & FLAG_SECURE) != 0) {
                return false;
            }
            if ((systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
                return false;
            }
        }
        return true;
        return canContainActivity(activityInfo, windowFlags, systemWindowFlags);
    }

    @Override
@@ -105,4 +98,28 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
    boolean containsUid(int uid) {
        return mRunningUids.contains(uid);
    }

    private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags,
            int systemWindowFlags) {
        if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
            return false;
        }
        final UserHandle activityUser =
                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
        if (!mAllowedUsers.contains(activityUser)) {
            Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser);
            return false;
        }
        if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
                activityInfo.packageName, activityUser)) {
            // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
            if ((windowFlags & FLAG_SECURE) != 0) {
                return false;
            }
            if ((systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
                return false;
            }
        }
        return true;
    }
}
Loading