Loading core/java/android/app/AutomaticZenRule.java +51 −11 Original line number Diff line number Diff line Loading @@ -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. * Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } /** Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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; } } core/tests/coretests/src/android/app/AutomaticZenRuleTest.java 0 → 100644 +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()); } } Loading
core/java/android/app/AutomaticZenRule.java +51 −11 Original line number Diff line number Diff line Loading @@ -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. * Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } /** Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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; } }
core/tests/coretests/src/android/app/AutomaticZenRuleTest.java 0 → 100644 +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()); } }