Merge "Limit the size of lists in ZenPolicy" into tm-qpr-dev am: 3e92172c8b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20788986

Change-Id: I42aec613c178569f678a5eb873f11ba538c55b1d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index a892570..bffa660 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -79,6 +79,12 @@
     /** @hide */
     public static final int PRIORITY_CATEGORY_CONVERSATIONS = 8;
 
+    /**
+     * Total number of priority categories. Keep updated with any updates to PriorityCategory enum.
+     * @hide
+     */
+    public static final int NUM_PRIORITY_CATEGORIES = 9;
+
     /** @hide */
     @IntDef(prefix = { "VISUAL_EFFECT_" }, value = {
             VISUAL_EFFECT_FULL_SCREEN_INTENT,
@@ -107,6 +113,12 @@
     /** @hide */
     public static final int VISUAL_EFFECT_NOTIFICATION_LIST = 6;
 
+    /**
+     * Total number of visual effects. Keep updated with any updates to VisualEffect enum.
+     * @hide
+     */
+    public static final int NUM_VISUAL_EFFECTS = 7;
+
     /** @hide */
     @IntDef(prefix = { "PEOPLE_TYPE_" }, value = {
             PEOPLE_TYPE_UNSET,
@@ -202,8 +214,8 @@
 
     /** @hide */
     public ZenPolicy() {
-        mPriorityCategories = new ArrayList<>(Collections.nCopies(9, 0));
-        mVisualEffects = new ArrayList<>(Collections.nCopies(7, 0));
+        mPriorityCategories = new ArrayList<>(Collections.nCopies(NUM_PRIORITY_CATEGORIES, 0));
+        mVisualEffects = new ArrayList<>(Collections.nCopies(NUM_VISUAL_EFFECTS, 0));
     }
 
     /**
@@ -804,8 +816,12 @@
         @Override
         public ZenPolicy createFromParcel(Parcel source) {
             ZenPolicy policy = new ZenPolicy();
-            policy.mPriorityCategories = source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
-            policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
+            policy.mPriorityCategories = trimList(
+                    source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class),
+                    NUM_PRIORITY_CATEGORIES);
+            policy.mVisualEffects = trimList(
+                    source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class),
+                    NUM_VISUAL_EFFECTS);
             policy.mPriorityCalls = source.readInt();
             policy.mPriorityMessages = source.readInt();
             policy.mConversationSenders = source.readInt();
@@ -832,6 +848,15 @@
                 .toString();
     }
 
+    // Returns a list containing the first maxLength elements of the input list if the list is
+    // longer than that size. For the lists in ZenPolicy, this should not happen unless the input
+    // is corrupt.
+    private static ArrayList<Integer> trimList(ArrayList<Integer> list, int maxLength) {
+        if (list == null || list.size() <= maxLength) {
+            return list;
+        }
+        return new ArrayList<>(list.subList(0, maxLength));
+    }
 
     private String priorityCategoriesToString() {
         StringBuilder builder = new StringBuilder();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index b16ca8b..b4a294d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -19,6 +19,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.fail;
 
+import android.os.Parcel;
 import android.service.notification.ZenPolicy;
 import android.service.notification.nano.DNDPolicyProto;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -32,9 +33,13 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ZenPolicyTest extends UiServiceTestCase {
+    private static final String CLASS = "android.service.notification.ZenPolicy";
 
     @Test
     public void testZenPolicyApplyAllowedToDisallowed() {
@@ -524,6 +529,66 @@
         assertProtoMatches(policy, policy.toProto());
     }
 
+    @Test
+    public void testTooLongLists_fromParcel() {
+        ArrayList<Integer> longList = new ArrayList<Integer>(50);
+        for (int i = 0; i < 50; i++) {
+            longList.add(ZenPolicy.STATE_UNSET);
+        }
+
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+        ZenPolicy policy = builder.build();
+
+        try {
+            Field priorityCategories = Class.forName(CLASS).getDeclaredField(
+                    "mPriorityCategories");
+            priorityCategories.setAccessible(true);
+            priorityCategories.set(policy, longList);
+
+            Field visualEffects = Class.forName(CLASS).getDeclaredField("mVisualEffects");
+            visualEffects.setAccessible(true);
+            visualEffects.set(policy, longList);
+        } catch (NoSuchFieldException e) {
+            fail(e.toString());
+        } catch (ClassNotFoundException e) {
+            fail(e.toString());
+        } catch (IllegalAccessException e) {
+            fail(e.toString());
+        }
+
+        Parcel parcel = Parcel.obtain();
+        policy.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        ZenPolicy fromParcel = ZenPolicy.CREATOR.createFromParcel(parcel);
+
+        // Confirm that all the fields are accessible and UNSET
+        assertAllPriorityCategoriesUnsetExcept(fromParcel, -1);
+        assertAllVisualEffectsUnsetExcept(fromParcel, -1);
+
+        // Because we don't access the lists directly, we also need to use reflection to make sure
+        // the lists are the right length.
+        try {
+            Field priorityCategories = Class.forName(CLASS).getDeclaredField(
+                    "mPriorityCategories");
+            priorityCategories.setAccessible(true);
+            ArrayList<Integer> pcList = (ArrayList<Integer>) priorityCategories.get(fromParcel);
+            assertEquals(ZenPolicy.NUM_PRIORITY_CATEGORIES, pcList.size());
+
+
+            Field visualEffects = Class.forName(CLASS).getDeclaredField("mVisualEffects");
+            visualEffects.setAccessible(true);
+            ArrayList<Integer> veList = (ArrayList<Integer>) visualEffects.get(fromParcel);
+            assertEquals(ZenPolicy.NUM_VISUAL_EFFECTS, veList.size());
+        } catch (NoSuchFieldException e) {
+            fail(e.toString());
+        } catch (ClassNotFoundException e) {
+            fail(e.toString());
+        } catch (IllegalAccessException e) {
+            fail(e.toString());
+        }
+    }
+
     private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) {
         if (except != ZenPolicy.PRIORITY_CATEGORY_REMINDERS) {
             assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryReminders());