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

Commit dbfc73bd authored by Yuri Lin's avatar Yuri Lin Committed by Automerger Merge Worker
Browse files

Merge "Trim any long string inputs that come in to AutomaticZenRule" into tm-dev am: de7b49d1

parents 0dc27616 de7b49d1
Loading
Loading
Loading
Loading
+51 −11
Original line number Diff line number Diff line
@@ -47,6 +47,13 @@ public final class AutomaticZenRule implements Parcelable {
    private boolean mModified = false;
    private String mPkg;

    /**
     * The maximum string length for any string contained in this automatic zen rule. This pertains
     * both to fields in the rule itself (such as its name) and items with sub-fields.
     * @hide
     */
    public static final int MAX_STRING_LENGTH = 1000;

    /**
     * Creates an automatic zen rule.
     *
@@ -93,10 +100,10 @@ public final class AutomaticZenRule implements Parcelable {
    public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner,
            @Nullable ComponentName configurationActivity, @NonNull Uri conditionId,
            @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) {
        this.name = name;
        this.owner = owner;
        this.configurationActivity = configurationActivity;
        this.conditionId = conditionId;
        this.name = getTrimmedString(name);
        this.owner = getTrimmedComponentName(owner);
        this.configurationActivity = getTrimmedComponentName(configurationActivity);
        this.conditionId = getTrimmedUri(conditionId);
        this.interruptionFilter = interruptionFilter;
        this.enabled = enabled;
        this.mZenPolicy = policy;
@@ -115,12 +122,14 @@ public final class AutomaticZenRule implements Parcelable {
    public AutomaticZenRule(Parcel source) {
        enabled = source.readInt() == ENABLED;
        if (source.readInt() == ENABLED) {
            name = source.readString();
            name = getTrimmedString(source.readString());
        }
        interruptionFilter = source.readInt();
        conditionId = source.readParcelable(null, android.net.Uri.class);
        owner = source.readParcelable(null, android.content.ComponentName.class);
        configurationActivity = source.readParcelable(null, android.content.ComponentName.class);
        conditionId = getTrimmedUri(source.readParcelable(null, android.net.Uri.class));
        owner = getTrimmedComponentName(
                source.readParcelable(null, android.content.ComponentName.class));
        configurationActivity = getTrimmedComponentName(
                source.readParcelable(null, android.content.ComponentName.class));
        creationTime = source.readLong();
        mZenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
        mModified = source.readInt() == ENABLED;
@@ -196,7 +205,7 @@ public final class AutomaticZenRule implements Parcelable {
     * Sets the representation of the state that causes this rule to become active.
     */
    public void setConditionId(Uri conditionId) {
        this.conditionId = conditionId;
        this.conditionId = getTrimmedUri(conditionId);
    }

    /**
@@ -211,7 +220,7 @@ public final class AutomaticZenRule implements Parcelable {
     * Sets the name of this rule.
     */
    public void setName(String name) {
        this.name = name;
        this.name = getTrimmedString(name);
    }

    /**
@@ -243,7 +252,7 @@ public final class AutomaticZenRule implements Parcelable {
     * that are not backed by {@link android.service.notification.ConditionProviderService}.
     */
    public void setConfigurationActivity(@Nullable ComponentName componentName) {
        this.configurationActivity = componentName;
        this.configurationActivity = getTrimmedComponentName(componentName);
    }

    /**
@@ -333,4 +342,35 @@ public final class AutomaticZenRule implements Parcelable {
            return new AutomaticZenRule[size];
        }
    };

    /**
     * If the package or class name of the provided ComponentName are longer than MAX_STRING_LENGTH,
     * return a trimmed version that truncates each of the package and class name at the max length.
     */
    private static ComponentName getTrimmedComponentName(ComponentName cn) {
        if (cn == null) return null;
        return new ComponentName(getTrimmedString(cn.getPackageName()),
                getTrimmedString(cn.getClassName()));
    }

    /**
     * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
     */
    private static String getTrimmedString(String input) {
        if (input != null && input.length() > MAX_STRING_LENGTH) {
            return input.substring(0, MAX_STRING_LENGTH);
        }
        return input;
    }

    /**
     * Returns a truncated copy of the Uri by trimming the string representation to the maximum
     * string length.
     */
    private static Uri getTrimmedUri(Uri input) {
        if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
            return Uri.parse(getTrimmedString(input.toString()));
        }
        return input;
    }
}
+153 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;

import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.google.common.base.Strings;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.lang.reflect.Field;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class AutomaticZenRuleTest {
    private static final String CLASS = "android.app.AutomaticZenRule";

    @Test
    public void testLongFields_inConstructor() {
        String longString = Strings.repeat("A", 65536);
        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));

        // test both variants where there's an owner, and where there's a configuration activity
        AutomaticZenRule rule1 = new AutomaticZenRule(
                longString, // name
                new ComponentName("pkg", longString), // owner
                null,  // configuration activity
                longUri, // conditionId
                null, // zen policy
                0, // interruption filter
                true); // enabled

        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule1.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getOwner().getClassName().length());

        AutomaticZenRule rule2 = new AutomaticZenRule(
                longString, // name
                null, // owner
                new ComponentName(longString, "SomeClassName"), // configuration activity
                longUri, // conditionId
                null, // zen policy
                0, // interruption filter
                false); // enabled

        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule2.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule2.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule2.getConfigurationActivity().getPackageName().length());
    }

    @Test
    public void testLongFields_inSetters() {
        String longString = Strings.repeat("A", 65536);
        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));

        AutomaticZenRule rule = new AutomaticZenRule(
                "sensible name",
                new ComponentName("pkg", "ShortClass"),
                null,
                Uri.parse("uri://short"),
                null, 0, true);

        rule.setName(longString);
        rule.setConditionId(longUri);
        rule.setConfigurationActivity(new ComponentName(longString, longString));

        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule.getConfigurationActivity().getPackageName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule.getConfigurationActivity().getClassName().length());
    }

    @Test
    public void testLongInputsFromParcel() {
        // Create a rule with long fields, set directly via reflection so that we can confirm that
        // a rule with too-long fields that comes in via a parcel has its fields truncated directly.
        AutomaticZenRule rule = new AutomaticZenRule(
                "placeholder",
                new ComponentName("place", "holder"),
                null,
                Uri.parse("uri://placeholder"),
                null, 0, true);

        try {
            String longString = Strings.repeat("A", 65536);
            Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
            Field name = Class.forName(CLASS).getDeclaredField("name");
            name.setAccessible(true);
            name.set(rule, longString);
            Field conditionId = Class.forName(CLASS).getDeclaredField("conditionId");
            conditionId.setAccessible(true);
            conditionId.set(rule, longUri);
            Field owner = Class.forName(CLASS).getDeclaredField("owner");
            owner.setAccessible(true);
            owner.set(rule, new ComponentName(longString, longString));
            Field configActivity = Class.forName(CLASS).getDeclaredField("configurationActivity");
            configActivity.setAccessible(true);
            configActivity.set(rule, new ComponentName(longString, longString));
        } catch (NoSuchFieldException e) {
            fail(e.toString());
        } catch (ClassNotFoundException e) {
            fail(e.toString());
        } catch (IllegalAccessException e) {
            fail(e.toString());
        }

        Parcel parcel = Parcel.obtain();
        rule.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);

        AutomaticZenRule fromParcel = new AutomaticZenRule(parcel);
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, fromParcel.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getConfigurationActivity().getPackageName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getConfigurationActivity().getClassName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getOwner().getPackageName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getOwner().getClassName().length());
    }
}