diff options
| author | 2022-11-16 12:37:04 +0000 | |
|---|---|---|
| committer | 2022-11-16 12:37:04 +0000 | |
| commit | 07e7541ea453401932a084ac4df9ccdd0432b0a8 (patch) | |
| tree | 56ed1d85bc20ea5505bdb60624187d21f77569a0 | |
| parent | 0a8ef45e564676fa604d71b353edbbb3fe438431 (diff) | |
| parent | 877f52c27a1883e334e715a36e22ab553a14e643 (diff) | |
Merge "Allow virtual device owners to specify custom policies per policy type."
9 files changed, 228 insertions, 4 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ce1eff143185..001ebf5c0840 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -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>); diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl index 82d7534c84d9..7d6336a225bd 100644 --- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl +++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl @@ -52,6 +52,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. * * @param virtualDisplayConfig The configuration used in creating the display diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index 0bb86fbf00f8..c14bb1beb025 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -182,6 +182,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 * to another device, and inject input events that are received from the remote device. diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index d40c9d63039d..c6e6f8324cff 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -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} @@ -528,6 +606,18 @@ public final class VirtualDeviceParams implements Parcelable { } /** + * 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. */ @NonNull @@ -541,7 +631,8 @@ public final class VirtualDeviceParams implements Parcelable { mAllowedActivities, mBlockedActivities, mDefaultActivityPolicy, - mName); + mName, + mDevicePolicies); } } } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index be2107529f8b..fbde9e0ea5d1 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -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() { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index c400a74da4ce..a8797a05ed24 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -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(); @@ -439,6 +452,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; synchronized (mVirtualDeviceManagerLock) { diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java index 81b56a310738..d2e572f2f979 100644 --- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java +++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java @@ -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); } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 5fda3d6b36ab..c715a217f221 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -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 diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java index 77f1e24ee771..036b6df92ef9 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java @@ -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); } } |