Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bcc7865e authored by Yuri Lin's avatar Yuri Lin
Browse files

Limit the size of lists in ZenPolicy

These lists are already size-limited by the set of things they may depict, but this change enforces the list sizes upon reading from a parcel in case any callers change the list sizes via reflection or something like it.

Bug: 251427644
Test: atest ZenPolicyTest
Change-Id: I301ee58afa03b6695294e8a46280169ecbbd3ba1
parent 08ea7a84
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -79,6 +79,12 @@ public final class ZenPolicy implements Parcelable {
    /** @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 @@ public final class ZenPolicy implements Parcelable {
    /** @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 @@ public final class ZenPolicy implements Parcelable {

    /** @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 @@ public final class ZenPolicy implements Parcelable {
        @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 @@ public final class ZenPolicy implements Parcelable {
                .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();
+65 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.notification;
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 com.google.protobuf.nano.InvalidProtocolBufferNanoException;
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 @@ public class ZenPolicyTest extends UiServiceTestCase {
        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());