From 9ed5fe201c7ec6a80b306a4d52ac09116db56a1f Mon Sep 17 00:00:00 2001 From: Maurice Lam Date: Wed, 19 Jan 2022 00:06:45 -0800 Subject: [PATCH] Add setAllowedActivities/setBlockActivities implementation These APIs allow Virtual Device owners to configure allow and deny lists of components which are allowed to be streamed. Bug: 201559291 Test: To be added in ag/15781910 Change-Id: I5e9297b9fdbe987690e164b7215352e741806fd5 --- .../virtual/VirtualDeviceParams.java | 106 +++++++++++++++++- .../GenericWindowPolicyController.java | 30 ++++- .../companion/virtual/VirtualDeviceImpl.java | 5 +- 3 files changed, 133 insertions(+), 8 deletions(-) diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index d61d4741637a2..169f4e1ad2812 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -20,7 +20,9 @@ import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; @@ -65,18 +67,26 @@ public final class VirtualDeviceParams implements Parcelable { private final int mLockState; private final ArraySet mUsersWithMatchingAccounts; + @Nullable private final ArraySet mAllowedActivities; + @Nullable private final ArraySet mBlockedActivities; private VirtualDeviceParams( @LockState int lockState, - @NonNull Set usersWithMatchingAccounts) { + @NonNull Set usersWithMatchingAccounts, + @Nullable Set allowedActivities, + @Nullable Set blockedActivities) { mLockState = lockState; mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts); + mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities); + mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities); } @SuppressWarnings("unchecked") private VirtualDeviceParams(Parcel parcel) { mLockState = parcel.readInt(); mUsersWithMatchingAccounts = (ArraySet) parcel.readArraySet(null); + mAllowedActivities = (ArraySet) parcel.readArraySet(null); + mBlockedActivities = (ArraySet) parcel.readArraySet(null); } /** @@ -98,6 +108,33 @@ public final class VirtualDeviceParams implements Parcelable { return Collections.unmodifiableSet(mUsersWithMatchingAccounts); } + /** + * Returns the set of activities allowed to be streamed, or {@code null} if this is not set. + * + * @see Builder#setAllowedActivities(Set) + */ + @Nullable + public Set getAllowedActivities() { + if (mAllowedActivities == null) { + return null; + } + return Collections.unmodifiableSet(mAllowedActivities); + } + + /** + * Returns the set of activities that are blocked from streaming, or {@code null} if this is not + * set. + * + * @see Builder#setBlockedActivities(Set) + */ + @Nullable + public Set getBlockedActivities() { + if (mBlockedActivities == null) { + return null; + } + return Collections.unmodifiableSet(mBlockedActivities); + } + @Override public int describeContents() { return 0; @@ -107,6 +144,8 @@ public final class VirtualDeviceParams implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mLockState); dest.writeArraySet(mUsersWithMatchingAccounts); + dest.writeArraySet(mAllowedActivities); + dest.writeArraySet(mBlockedActivities); } @Override @@ -118,8 +157,10 @@ public final class VirtualDeviceParams implements Parcelable { return false; } VirtualDeviceParams that = (VirtualDeviceParams) o; - return mLockState == that.mLockState && mUsersWithMatchingAccounts.equals( - that.mUsersWithMatchingAccounts); + return mLockState == that.mLockState + && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts) + && Objects.equals(mAllowedActivities, that.mAllowedActivities) + && Objects.equals(mBlockedActivities, that.mBlockedActivities); } @Override @@ -132,6 +173,8 @@ public final class VirtualDeviceParams implements Parcelable { return "VirtualDeviceParams(" + " mLockState=" + mLockState + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts + + " mAllowedActivities=" + mAllowedActivities + + " mBlockedActivities=" + mBlockedActivities + ")"; } @@ -153,6 +196,8 @@ public final class VirtualDeviceParams implements Parcelable { private @LockState int mLockState = LOCK_STATE_ALWAYS_LOCKED; private Set mUsersWithMatchingAccounts; + @Nullable private Set mBlockedActivities; + @Nullable private Set mAllowedActivities; /** * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY} @@ -175,6 +220,7 @@ public final class VirtualDeviceParams implements Parcelable { * * @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( @@ -183,6 +229,52 @@ public final class VirtualDeviceParams implements Parcelable { return this; } + /** + * Sets the activities allowed to be launched in the virtual device. If + * {@code allowedActivities} is non-null, all activities other than the ones in the set will + * be blocked from launching. + * + *

{@code allowedActivities} and the set in {@link #setBlockedActivities(Set)} cannot + * both be non-null at the same time. + * + * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been set to a + * non-null value. + * + * @param allowedActivities A set of activity {@link ComponentName} allowed to be launched + * in the virtual device. + */ + public Builder setAllowedActivities(@Nullable Set allowedActivities) { + if (mBlockedActivities != null && allowedActivities != null) { + throw new IllegalArgumentException( + "Allowed activities and Blocked activities cannot both be set."); + } + mAllowedActivities = allowedActivities; + return this; + } + + /** + * Sets the activities blocked from launching in the virtual device. If the {@code + * blockedActivities} is non-null, activities in the set are blocked from launching in the + * virtual device. + * + * {@code blockedActivities} and the set in {@link #setAllowedActivities(Set)} cannot both + * be non-null at the same time. + * + * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been set to a + * non-null value. + * + * @param blockedActivities A set of {@link ComponentName} to be blocked launching from + * virtual device. + */ + public Builder setBlockedActivities(@Nullable Set blockedActivities) { + if (mAllowedActivities != null && blockedActivities != null) { + throw new IllegalArgumentException( + "Allowed activities and Blocked activities cannot both be set."); + } + mBlockedActivities = blockedActivities; + return this; + } + /** * Builds the {@link VirtualDeviceParams} instance. */ @@ -191,7 +283,13 @@ public final class VirtualDeviceParams implements Parcelable { if (mUsersWithMatchingAccounts == null) { mUsersWithMatchingAccounts = Collections.emptySet(); } - return new VirtualDeviceParams(mLockState, mUsersWithMatchingAccounts); + if (mAllowedActivities != null && mBlockedActivities != null) { + // Should never reach here because the setters block this as well. + throw new IllegalStateException( + "Allowed activities and Blocked activities cannot both be set."); + } + return new VirtualDeviceParams(mLockState, mUsersWithMatchingAccounts, + mAllowedActivities, mBlockedActivities); } } } diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index 734e5c3f6f8b6..0fd29675d4694 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -21,6 +21,7 @@ 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.annotation.Nullable; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; @@ -33,6 +34,7 @@ import android.util.Slog; import android.window.DisplayWindowPolicyController; import java.util.List; +import java.util.Set; /** @@ -49,13 +51,23 @@ 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 mAllowedUsers; + @NonNull + private final ArraySet mAllowedUsers; + @Nullable + private final ArraySet mAllowedActivities; + @Nullable + private final ArraySet mBlockedActivities; - @NonNull final ArraySet mRunningUids = new ArraySet<>(); + @NonNull + final ArraySet mRunningUids = new ArraySet<>(); GenericWindowPolicyController(int windowFlags, int systemWindowFlags, - @NonNull ArraySet allowedUsers) { + @NonNull ArraySet allowedUsers, + @Nullable Set allowedActivities, + @Nullable Set blockedActivities) { mAllowedUsers = allowedUsers; + mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities); + mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities); setInterestedWindowFlags(windowFlags, systemWindowFlags); } @@ -108,6 +120,18 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController { Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser); return false; } + if (mBlockedActivities != null + && mBlockedActivities.contains(activityInfo.getComponentName())) { + Slog.d(TAG, + "Virtual device blocking launch of " + activityInfo.getComponentName()); + return false; + } + if (mAllowedActivities != null + && !mAllowedActivities.contains(activityInfo.getComponentName())) { + Slog.d(TAG, + activityInfo.getComponentName() + " is not in the allowed list."); + 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. 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 0c0ee521af0f6..03b2c8c067049 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -328,6 +328,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { fout.println(" VirtualDevice: "); fout.println(" mAssociationId: " + mAssociationInfo.getId()); + fout.println(" mParams: " + mParams); fout.println(" mVirtualDisplayIds: "); synchronized (mVirtualDeviceLock) { for (int id : mVirtualDisplayIds) { @@ -345,7 +346,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mVirtualDisplayIds.add(displayId); final GenericWindowPolicyController dwpc = new GenericWindowPolicyController(FLAG_SECURE, - SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, getAllowedUserHandles()); + SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, getAllowedUserHandles(), + mParams.getAllowedActivities(), + mParams.getBlockedActivities()); mWindowPolicyControllers.put(displayId, dwpc); return dwpc; }