Merge changes from topic "virtualdevice-params"
* changes: Implement VirtualDevice's device policy enforcement Add params object to createVirtualDevice
This commit is contained in:
committed by
Android (Google) Code Review
commit
f1e7be07c0
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
core/java/android/companion/virtual/VirtualDeviceParams.aidl
Normal file
19
core/java/android/companion/virtual/VirtualDeviceParams.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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
core/java/android/companion/virtual/VirtualDeviceParams.java
Normal file
197
core/java/android/companion/virtual/VirtualDeviceParams.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
package com.android.server.companion.virtual;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_ENABLED;
|
||||
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY;
|
||||
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
||||
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.companion.AssociationInfo;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.input.VirtualKeyEvent;
|
||||
import android.hardware.input.VirtualMouseButtonEvent;
|
||||
import android.hardware.input.VirtualMouseRelativeEvent;
|
||||
@@ -32,6 +38,9 @@ import android.hardware.input.VirtualTouchEvent;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseArray;
|
||||
import android.window.DisplayWindowPolicyController;
|
||||
|
||||
@@ -56,6 +65,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
final List<Integer> mVirtualDisplayIds = new ArrayList<>();
|
||||
private final OnDeviceCloseListener mListener;
|
||||
private final IBinder mAppToken;
|
||||
private final VirtualDeviceParams mParams;
|
||||
|
||||
/**
|
||||
* A mapping from the virtual display ID to its corresponding
|
||||
@@ -65,17 +75,21 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
new SparseArray<>();
|
||||
|
||||
VirtualDeviceImpl(Context context, AssociationInfo associationInfo,
|
||||
IBinder token, int ownerUid, OnDeviceCloseListener listener) {
|
||||
this(context, associationInfo, token, ownerUid, /* inputController= */ null, listener);
|
||||
IBinder token, int ownerUid, OnDeviceCloseListener listener,
|
||||
VirtualDeviceParams params) {
|
||||
this(context, associationInfo, token, ownerUid, /* inputController= */ null, listener,
|
||||
params);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
VirtualDeviceImpl(Context context, AssociationInfo associationInfo, IBinder token,
|
||||
int ownerUid, InputController inputController, OnDeviceCloseListener listener) {
|
||||
int ownerUid, InputController inputController, OnDeviceCloseListener listener,
|
||||
VirtualDeviceParams params) {
|
||||
mContext = context;
|
||||
mAssociationInfo = associationInfo;
|
||||
mOwnerUid = ownerUid;
|
||||
mAppToken = token;
|
||||
mParams = params;
|
||||
if (inputController == null) {
|
||||
mInputController = new InputController(mVirtualDeviceLock);
|
||||
} else {
|
||||
@@ -89,7 +103,19 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Returns the flags that should be added to any virtual displays created on this virtual
|
||||
* device.
|
||||
*/
|
||||
int getBaseVirtualDisplayFlags() {
|
||||
int flags = 0;
|
||||
if (mParams.getLockState() == VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED) {
|
||||
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public int getAssociationId() {
|
||||
return mAssociationInfo.getId();
|
||||
}
|
||||
@@ -267,11 +293,29 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
mVirtualDisplayIds.add(displayId);
|
||||
final GenericWindowPolicyController dwpc =
|
||||
new GenericWindowPolicyController(FLAG_SECURE,
|
||||
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, getAllowedUserHandles());
|
||||
mWindowPolicyControllers.put(displayId, dwpc);
|
||||
return dwpc;
|
||||
}
|
||||
|
||||
private ArraySet<UserHandle> getAllowedUserHandles() {
|
||||
ArraySet<UserHandle> result = new ArraySet<>();
|
||||
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
|
||||
UserManager userManager = mContext.getSystemService(UserManager.class);
|
||||
for (UserHandle profile : userManager.getAllProfiles()) {
|
||||
int nearbyAppStreamingPolicy = dpm.getNearbyAppStreamingPolicy(profile.getIdentifier());
|
||||
if (nearbyAppStreamingPolicy == NEARBY_STREAMING_ENABLED
|
||||
|| nearbyAppStreamingPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY) {
|
||||
result.add(profile);
|
||||
} else if (nearbyAppStreamingPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY) {
|
||||
if (mParams.getUsersWithMatchingAccounts().contains(profile)) {
|
||||
result.add(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void onVirtualDisplayRemovedLocked(int displayId) {
|
||||
if (!mVirtualDisplayIds.contains(displayId)) {
|
||||
throw new IllegalStateException(
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.companion.CompanionDeviceManager;
|
||||
import android.companion.CompanionDeviceManager.OnAssociationsChangedListener;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
import android.companion.virtual.IVirtualDeviceManager;
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
@@ -131,7 +132,10 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
|
||||
@Override // Binder call
|
||||
public IVirtualDevice createVirtualDevice(
|
||||
IBinder token, String packageName, int associationId) {
|
||||
IBinder token,
|
||||
String packageName,
|
||||
int associationId,
|
||||
@NonNull VirtualDeviceParams params) {
|
||||
getContext().enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
|
||||
"createVirtualDevice");
|
||||
@@ -160,7 +164,7 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
mVirtualDevices.remove(associationId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, params);
|
||||
mVirtualDevices.put(associationInfo.getId(), virtualDevice);
|
||||
return virtualDevice;
|
||||
}
|
||||
@@ -237,6 +241,11 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice) {
|
||||
return ((VirtualDeviceImpl) virtualDevice).getBaseVirtualDisplayFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAppOwnerOfAnyVirtualDevice(int uid) {
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
|
||||
@@ -49,6 +49,12 @@ public abstract class VirtualDeviceManagerInternal {
|
||||
*/
|
||||
public abstract void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId);
|
||||
|
||||
/**
|
||||
* Returns the flags that should be added to any virtual displays created on this virtual
|
||||
* device.
|
||||
*/
|
||||
public abstract int getBaseVirtualDisplayFlags(IVirtualDevice virtualDevice);
|
||||
|
||||
/**
|
||||
* Returns true if the given {@code uid} is the owner of any virtual devices that are
|
||||
* currently active.
|
||||
|
||||
@@ -1250,6 +1250,14 @@ public final class DisplayManagerService extends SystemService {
|
||||
}
|
||||
final Surface surface = virtualDisplayConfig.getSurface();
|
||||
int flags = virtualDisplayConfig.getFlags();
|
||||
if (virtualDevice != null) {
|
||||
final VirtualDeviceManagerInternal vdm =
|
||||
getLocalService(VirtualDeviceManagerInternal.class);
|
||||
if (!vdm.isValidVirtualDevice(virtualDevice)) {
|
||||
throw new SecurityException("Invalid virtual device");
|
||||
}
|
||||
flags |= vdm.getBaseVirtualDisplayFlags(virtualDevice);
|
||||
}
|
||||
|
||||
if (surface != null && surface.isSingleBuffered()) {
|
||||
throw new IllegalArgumentException("Surface can't be single-buffered");
|
||||
@@ -1282,14 +1290,6 @@ public final class DisplayManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
if (virtualDevice != null) {
|
||||
final VirtualDeviceManagerInternal vdm =
|
||||
getLocalService(VirtualDeviceManagerInternal.class);
|
||||
if (!vdm.isValidVirtualDevice(virtualDevice)) {
|
||||
throw new SecurityException("Invalid virtual device");
|
||||
}
|
||||
}
|
||||
|
||||
if (callingUid != Process.SYSTEM_UID
|
||||
&& (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
|
||||
if (!canProjectVideo(projection)) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.Manifest;
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.graphics.Point;
|
||||
@@ -84,7 +85,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mInputController = new InputController(new Object(), mNativeWrapperMock);
|
||||
mDeviceImpl = new VirtualDeviceImpl(mContext,
|
||||
/* association info */ null, new Binder(), /* uid */ 0, mInputController,
|
||||
(int associationId) -> {});
|
||||
(int associationId) -> {}, new VirtualDeviceParams.Builder().build());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 com.android.server.companion.virtual;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.os.Parcel;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class VirtualDeviceParamsTest {
|
||||
|
||||
@Test
|
||||
public void parcelable_shouldRecreateSuccessfully() {
|
||||
VirtualDeviceParams originalParams = new VirtualDeviceParams.Builder()
|
||||
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
|
||||
.setUsersWithMatchingAccounts(Set.of(UserHandle.of(123), UserHandle.of(456)))
|
||||
.build();
|
||||
Parcel parcel = Parcel.obtain();
|
||||
originalParams.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
VirtualDeviceParams params = VirtualDeviceParams.CREATOR.createFromParcel(parcel);
|
||||
assertThat(params).isEqualTo(originalParams);
|
||||
assertThat(params.getLockState()).isEqualTo(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED);
|
||||
assertThat(params.getUsersWithMatchingAccounts())
|
||||
.containsExactly(UserHandle.of(123), UserHandle.of(456));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user