Merge "Allow virtual device owners to specify custom policies per policy type."

This commit is contained in:
Vladimir Komsiyski
2022-11-16 12:37:04 +00:00
committed by Android (Google) Code Review
9 changed files with 228 additions and 4 deletions

View File

@@ -2909,6 +2909,7 @@ package android.companion.virtual {
method @NonNull public java.util.Set<android.content.ComponentName> getBlockedCrossTaskNavigations();
method public int getDefaultActivityPolicy();
method public int getDefaultNavigationPolicy();
method public int getDevicePolicy(int);
method public int getLockState();
method @Nullable public String getName();
method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
@@ -2916,14 +2917,18 @@ package android.companion.virtual {
field public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; // 0x0
field public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; // 0x1
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR;
field public static final int DEVICE_POLICY_CUSTOM = 1; // 0x1
field public static final int DEVICE_POLICY_DEFAULT = 0; // 0x0
field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1
field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
}
public static final class VirtualDeviceParams.Builder {
ctor public VirtualDeviceParams.Builder();
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder addDevicePolicy(int, int);
method @NonNull public android.companion.virtual.VirtualDeviceParams build();
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);

View File

@@ -51,6 +51,11 @@ interface IVirtualDeviceManager {
*/
List<VirtualDevice> getVirtualDevices();
/**
* Returns the device policy for the given virtual device and policy type.
*/
int getDevicePolicy(int deviceId, int policyType);
/**
* Creates a virtual display owned by a particular virtual device.
*

View File

@@ -181,6 +181,28 @@ public final class VirtualDeviceManager {
}
}
/**
* Returns the device policy for the given virtual device and policy type.
*
* <p>In case the virtual device identifier is not valid, or there's no explicitly specified
* policy for that device and policy type, then
* {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
*
* @hide
*/
public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
if (mService == null) {
Log.w(TAG, "Failed to retrieve device policy; no virtual device manager service.");
return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
}
try {
return mService.getDevicePolicy(deviceId, policyType);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* A virtual device has its own virtual display, audio output, microphone, and camera etc. The
* creator of a virtual device can take the output from the virtual display and stream it over

View File

@@ -28,6 +28,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.SparseIntArray;
import com.android.internal.util.Preconditions;
@@ -103,6 +104,47 @@ public final class VirtualDeviceParams implements Parcelable {
*/
public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1;
/** @hide */
@IntDef(prefix = "DEVICE_POLICY_", value = {DEVICE_POLICY_DEFAULT, DEVICE_POLICY_CUSTOM})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface DevicePolicy {}
/**
* Indicates that there is no special logic for this virtual device and it should be treated
* the same way as the default device, keeping the default behavior unchanged.
*/
public static final int DEVICE_POLICY_DEFAULT = 0;
/**
* Indicates that there is custom logic, specific to this virtual device, which should be
* triggered instead of the default behavior.
*/
public static final int DEVICE_POLICY_CUSTOM = 1;
/**
* Any relevant component must be able to interpret the correct meaning of a custom policy for
* a given policy type.
* @hide
*/
@IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface PolicyType {}
/**
* Tells the sensor framework how to handle sensor requests from contexts associated with this
* virtual device, namely the sensors returned by
* {@link android.hardware.SensorManager#getSensorList}:
*
* <ul>
* <li>{@link #DEVICE_POLICY_DEFAULT}: Return the sensors of the default device.
* <li>{@link #DEVICE_POLICY_CUSTOM}: Return the sensors of the virtual device. Note that if
* the virtual device did not create any virtual sensors, then an empty list is returned.
* </ul>
*/
public static final int POLICY_TYPE_SENSORS = 0;
private final int mLockState;
@NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
@@ -114,6 +156,8 @@ public final class VirtualDeviceParams implements Parcelable {
@ActivityPolicy
private final int mDefaultActivityPolicy;
@Nullable private final String mName;
// Mapping of @PolicyType to @DevicePolicy
@NonNull private final SparseIntArray mDevicePolicies;
private VirtualDeviceParams(
@LockState int lockState,
@@ -124,12 +168,14 @@ public final class VirtualDeviceParams implements Parcelable {
@NonNull Set<ComponentName> allowedActivities,
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy,
@Nullable String name) {
@Nullable String name,
@NonNull SparseIntArray devicePolicies) {
Preconditions.checkNotNull(usersWithMatchingAccounts);
Preconditions.checkNotNull(allowedCrossTaskNavigations);
Preconditions.checkNotNull(blockedCrossTaskNavigations);
Preconditions.checkNotNull(allowedActivities);
Preconditions.checkNotNull(blockedActivities);
Preconditions.checkNotNull(devicePolicies);
mLockState = lockState;
mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
@@ -140,6 +186,7 @@ public final class VirtualDeviceParams implements Parcelable {
mBlockedActivities = new ArraySet<>(blockedActivities);
mDefaultActivityPolicy = defaultActivityPolicy;
mName = name;
mDevicePolicies = devicePolicies;
}
@SuppressWarnings("unchecked")
@@ -153,6 +200,7 @@ public final class VirtualDeviceParams implements Parcelable {
mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
mDefaultActivityPolicy = parcel.readInt();
mName = parcel.readString8();
mDevicePolicies = parcel.readSparseIntArray();
}
/**
@@ -258,6 +306,16 @@ public final class VirtualDeviceParams implements Parcelable {
return mName;
}
/**
* Returns the policy specified for this policy type, or {@link #DEVICE_POLICY_DEFAULT} if no
* policy for this type has been explicitly specified.
*
* @see Builder#addDevicePolicy
*/
public @DevicePolicy int getDevicePolicy(@PolicyType int policyType) {
return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
}
@Override
public int describeContents() {
return 0;
@@ -274,6 +332,7 @@ public final class VirtualDeviceParams implements Parcelable {
dest.writeArraySet(mBlockedActivities);
dest.writeInt(mDefaultActivityPolicy);
dest.writeString8(mName);
dest.writeSparseIntArray(mDevicePolicies);
}
@Override
@@ -285,6 +344,18 @@ public final class VirtualDeviceParams implements Parcelable {
return false;
}
VirtualDeviceParams that = (VirtualDeviceParams) o;
final int devicePoliciesCount = mDevicePolicies.size();
if (devicePoliciesCount != that.mDevicePolicies.size()) {
return false;
}
for (int i = 0; i < devicePoliciesCount; i++) {
if (mDevicePolicies.keyAt(i) != that.mDevicePolicies.keyAt(i)) {
return false;
}
if (mDevicePolicies.valueAt(i) != that.mDevicePolicies.valueAt(i)) {
return false;
}
}
return mLockState == that.mLockState
&& mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
&& Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
@@ -298,10 +369,15 @@ public final class VirtualDeviceParams implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(
int hashCode = Objects.hash(
mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
mBlockedActivities, mDefaultActivityPolicy, mName);
mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies);
for (int i = 0; i < mDevicePolicies.size(); i++) {
hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
}
return hashCode;
}
@Override
@@ -317,6 +393,7 @@ public final class VirtualDeviceParams implements Parcelable {
+ " mBlockedActivities=" + mBlockedActivities
+ " mDefaultActivityPolicy=" + mDefaultActivityPolicy
+ " mName=" + mName
+ " mDevicePolicies=" + mDevicePolicies
+ ")";
}
@@ -350,6 +427,7 @@ public final class VirtualDeviceParams implements Parcelable {
private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
private boolean mDefaultActivityPolicyConfigured = false;
@Nullable private String mName;
@NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
/**
* Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
@@ -527,6 +605,18 @@ public final class VirtualDeviceParams implements Parcelable {
return this;
}
/**
* Specifies a policy for this virtual device.
*
* @param policyType the type of policy, i.e. which behavior to specify a policy for.
* @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
*/
@NonNull
public Builder addDevicePolicy(@PolicyType int policyType, @DevicePolicy int devicePolicy) {
mDevicePolicies.put(policyType, devicePolicy);
return this;
}
/**
* Builds the {@link VirtualDeviceParams} instance.
*/
@@ -541,7 +631,8 @@ public final class VirtualDeviceParams implements Parcelable {
mAllowedActivities,
mBlockedActivities,
mDefaultActivityPolicy,
mName);
mName,
mDevicePolicies);
}
}
}

View File

@@ -227,6 +227,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
return mParams.getName();
}
/** Returns the policy specified for this policy type */
public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
@VirtualDeviceParams.PolicyType int policyType) {
return mParams.getDevicePolicy(policyType);
}
/** Returns the unique device ID of this device. */
@Override // Binder call
public int getDeviceId() {

View File

@@ -233,6 +233,13 @@ public class VirtualDeviceManagerService extends SystemService {
mLocalService.onAppsOnVirtualDeviceChanged();
}
@VisibleForTesting
void addVirtualDevice(VirtualDeviceImpl virtualDevice) {
synchronized (mVirtualDeviceManagerLock) {
mVirtualDevices.put(virtualDevice.getAssociationId(), virtualDevice);
}
}
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback {
@@ -358,6 +365,12 @@ public class VirtualDeviceManagerService extends SystemService {
return virtualDevices;
}
@Override // BinderCall
@VirtualDeviceParams.DevicePolicy
public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
return mLocalService.getDevicePolicy(deviceId, policyType);
}
@Nullable
private AssociationInfo getAssociationInfo(String packageName, int associationId) {
final int callingUserId = getCallingUserHandle().getIdentifier();
@@ -438,6 +451,20 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
@Override
@VirtualDeviceParams.DevicePolicy
public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
if (device.getDeviceId() == deviceId) {
return device.getDevicePolicy(policyType);
}
}
}
return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
}
@Override
public void onVirtualDisplayCreated(int displayId) {
final VirtualDisplayListener[] listeners;

View File

@@ -18,6 +18,7 @@ package com.android.server.companion.virtual;
import android.annotation.NonNull;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
import java.util.Set;
@@ -109,4 +110,14 @@ public abstract class VirtualDeviceManagerInternal {
* Returns true if the {@code displayId} is owned by any virtual device
*/
public abstract boolean isDisplayOwnedByAnyVirtualDevice(int displayId);
/**
* Returns the device policy for the given virtual device and policy type.
*
* <p>In case the virtual device identifier is not valid, or there's no explicitly specified
* policy for that device and policy type, then
* {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
*/
public abstract @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
int deviceId, @VirtualDeviceParams.PolicyType int policyType);
}

View File

@@ -16,6 +16,9 @@
package com.android.server.companion.virtual;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
import static com.google.common.truth.Truth.assertThat;
@@ -44,6 +47,7 @@ import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
@@ -240,6 +244,55 @@ public class VirtualDeviceManagerServiceTest {
mAssociationInfo, new Binder(), /* ownerUid */ 0, /* uniqueId */ 1,
mInputController, (int associationId) -> {}, mPendingTrampolineCallback,
mActivityListener, mRunningAppsChangedCallback, params);
mVdms.addVirtualDevice(mDeviceImpl);
}
@Test
public void getDevicePolicy_invalidDeviceId_returnsDefault() {
assertThat(
mLocalService.getDevicePolicy(
VirtualDeviceManager.INVALID_DEVICE_ID, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_defaultDeviceId_returnsDefault() {
assertThat(
mLocalService.getDevicePolicy(
VirtualDeviceManager.DEFAULT_DEVICE_ID, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_nonExistentDeviceId_returnsDefault() {
assertThat(
mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_unspecifiedPolicy_returnsDefault() {
assertThat(
mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
}
@Test
public void getDevicePolicy_returnsCustom() {
VirtualDeviceParams params = new VirtualDeviceParams
.Builder()
.setBlockedActivities(getBlockedActivities())
.addDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
.build();
mDeviceImpl = new VirtualDeviceImpl(mContext,
mAssociationInfo, new Binder(), /* ownerUid */ 0, /* uniqueId */ 1,
mInputController, (int associationId) -> {}, mPendingTrampolineCallback,
mActivityListener, mRunningAppsChangedCallback, params);
mVdms.addVirtualDevice(mDeviceImpl);
assertThat(
mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_CUSTOM);
}
@Test

View File

@@ -37,6 +37,8 @@ public class VirtualDeviceParamsTest {
VirtualDeviceParams originalParams = new VirtualDeviceParams.Builder()
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
.setUsersWithMatchingAccounts(Set.of(UserHandle.of(123), UserHandle.of(456)))
.addDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS,
VirtualDeviceParams.DEVICE_POLICY_CUSTOM)
.build();
Parcel parcel = Parcel.obtain();
originalParams.writeToParcel(parcel, 0);
@@ -47,5 +49,7 @@ public class VirtualDeviceParamsTest {
assertThat(params.getLockState()).isEqualTo(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED);
assertThat(params.getUsersWithMatchingAccounts())
.containsExactly(UserHandle.of(123), UserHandle.of(456));
assertThat(params.getDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS))
.isEqualTo(VirtualDeviceParams.DEVICE_POLICY_CUSTOM);
}
}