summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hongwei Wang <hwwang@google.com> 2023-08-01 16:00:31 -0700
committer Cherrypicker Worker <android-build-cherrypicker-worker@google.com> 2024-07-01 15:25:08 +0000
commite2e01571b42bfcc3308c41f677b85dd06d7d4f7d (patch)
treed78b301f8e25bf21db4c85810b9edad44e9b2be1
parent03d9c1450aa441454dfdf6abeee6ae37304aa8da (diff)
Rate limiting PiP aspect ratio change request
Using CountQuotaTrack to limit how frequent an app can request aspect ratio change via PictureInPictureParams, which could result flood of PiP resizing requests and freeze the PiP window. Note that CountQuotaTrack is initialized out of the WM lock to avoid dead lock with the AM one. Bug: 283103220 Test: Manually, using the POC app Test: Manually, switching YT PiP video functions at a regular rate Test: atest WindowOrganizerTests ActivityThreadTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:17b00deed56a6bbd3b78fbac76c2f1089f615002) Merged-In: Icb7dd17bbf7df573a9bb28f3dc56e90e78384f4f Change-Id: Icb7dd17bbf7df573a9bb28f3dc56e90e78384f4f 24D1-dev is based on 24Q2-release. Therefore, we merged this CL to 24D1-dev.
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java39
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java6
2 files changed, 45 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 981c4c078dd1..8655b3eb58eb 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -99,6 +99,7 @@ import android.view.RemoteAnimationDefinition;
import android.window.SizeConfigurationBuckets;
import android.window.TransitionInfo;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.protolog.common.ProtoLog;
@@ -108,6 +109,9 @@ import com.android.server.pm.KnownPackages;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.uri.GrantUri;
import com.android.server.uri.NeededUriGrants;
+import com.android.server.utils.quota.Categorizer;
+import com.android.server.utils.quota.Category;
+import com.android.server.utils.quota.CountQuotaTracker;
import com.android.server.vr.VrManagerInternal;
/**
@@ -123,6 +127,13 @@ class ActivityClientController extends IActivityClientController.Stub {
private final ActivityTaskSupervisor mTaskSupervisor;
private final Context mContext;
+ // Prevent malicious app abusing the Activity#setPictureInPictureParams API
+ @VisibleForTesting CountQuotaTracker mSetPipAspectRatioQuotaTracker;
+ // Limit to 60 times / minute
+ private static final int SET_PIP_ASPECT_RATIO_LIMIT = 60;
+ // The timeWindowMs here can not be smaller than QuotaTracker#MIN_WINDOW_SIZE_MS
+ private static final long SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS = 60_000;
+
/** Wrapper around VoiceInteractionServiceManager. */
private AssistUtils mAssistUtils;
@@ -946,6 +957,7 @@ class ActivityClientController extends IActivityClientController.Stub {
public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) {
final long origId = Binder.clearCallingIdentity();
try {
+ ensureSetPipAspectRatioQuotaTracker();
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParams(
"enterPictureInPictureMode", token, params);
@@ -960,6 +972,7 @@ class ActivityClientController extends IActivityClientController.Stub {
public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) {
final long origId = Binder.clearCallingIdentity();
try {
+ ensureSetPipAspectRatioQuotaTracker();
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParams(
"setPictureInPictureParams", token, params);
@@ -1012,6 +1025,19 @@ class ActivityClientController extends IActivityClientController.Stub {
}
/**
+ * Initialize the {@link #mSetPipAspectRatioQuotaTracker} if applicable, which should happen
+ * out of {@link #mGlobalLock} to avoid deadlock (AM lock is used in QuotaTrack ctor).
+ */
+ private void ensureSetPipAspectRatioQuotaTracker() {
+ if (mSetPipAspectRatioQuotaTracker == null) {
+ mSetPipAspectRatioQuotaTracker = new CountQuotaTracker(mContext,
+ Categorizer.SINGLE_CATEGORIZER);
+ mSetPipAspectRatioQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY,
+ SET_PIP_ASPECT_RATIO_LIMIT, SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS);
+ }
+ }
+
+ /**
* Checks the state of the system and the activity associated with the given {@param token} to
* verify that picture-in-picture is supported for that activity.
*
@@ -1035,6 +1061,19 @@ class ActivityClientController extends IActivityClientController.Stub {
+ ": Current activity does not support picture-in-picture.");
}
+ // Rate limit how frequent an app can request aspect ratio change via
+ // Activity#setPictureInPictureParams
+ final int userId = UserHandle.getCallingUserId();
+ if (r.pictureInPictureArgs.hasSetAspectRatio()
+ && params.hasSetAspectRatio()
+ && !r.pictureInPictureArgs.getAspectRatio().equals(
+ params.getAspectRatio())
+ && !mSetPipAspectRatioQuotaTracker.noteEvent(
+ userId, r.packageName, "setPipAspectRatio")) {
+ throw new IllegalStateException(caller
+ + ": Too many PiP aspect ratio change requests from " + r.packageName);
+ }
+
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
final float maxAspectRatio = mContext.getResources().getFloat(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 03b695d170ad..25949877524c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -1235,6 +1235,12 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertNotNull(o.mInfo);
assertNotNull(o.mInfo.pictureInPictureParams);
+ // Bypass the quota check, which causes NPE in current test setup.
+ if (mWm.mAtmService.mActivityClientController.mSetPipAspectRatioQuotaTracker != null) {
+ mWm.mAtmService.mActivityClientController.mSetPipAspectRatioQuotaTracker
+ .setEnabled(false);
+ }
+
final PictureInPictureParams p2 = new PictureInPictureParams.Builder()
.setAspectRatio(new Rational(3, 4)).build();
mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2);