Merge "Don't throw if the matching key contains ":"." into udc-dev am: 9c31083850

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

Change-Id: I921b0ec52280fe4987c3d71017e99a8487cfa033
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index d23d3cd..6357798 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -37,8 +37,6 @@
 import android.os.PowerExemptionManager.ReasonCode;
 import android.os.PowerExemptionManager.TempAllowListType;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -61,7 +59,8 @@
     private long mRequireCompatChangeId = CHANGE_INVALID;
     private long mIdForResponseEvent;
     private @DeliveryGroupPolicy int mDeliveryGroupPolicy;
-    private @Nullable String mDeliveryGroupMatchingKey;
+    private @Nullable String mDeliveryGroupMatchingNamespaceFragment;
+    private @Nullable String mDeliveryGroupMatchingKeyFragment;
     private @Nullable BundleMerger mDeliveryGroupExtrasMerger;
     private @Nullable IntentFilter mDeliveryGroupMatchingFilter;
     private @DeferralPolicy int mDeferralPolicy;
@@ -196,7 +195,13 @@
             "android:broadcast.deliveryGroupPolicy";
 
     /**
-     * Corresponds to {@link #setDeliveryGroupMatchingKey(String, String)}.
+     * Corresponds to namespace fragment of {@link #setDeliveryGroupMatchingKey(String, String)}.
+     */
+    private static final String KEY_DELIVERY_GROUP_NAMESPACE =
+            "android:broadcast.deliveryGroupMatchingNamespace";
+
+    /**
+     * Corresponds to key fragment of {@link #setDeliveryGroupMatchingKey(String, String)}.
      */
     private static final String KEY_DELIVERY_GROUP_KEY =
             "android:broadcast.deliveryGroupMatchingKey";
@@ -337,7 +342,8 @@
         mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
         mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY,
                 DELIVERY_GROUP_POLICY_ALL);
-        mDeliveryGroupMatchingKey = opts.getString(KEY_DELIVERY_GROUP_KEY);
+        mDeliveryGroupMatchingNamespaceFragment = opts.getString(KEY_DELIVERY_GROUP_NAMESPACE);
+        mDeliveryGroupMatchingKeyFragment = opts.getString(KEY_DELIVERY_GROUP_KEY);
         mDeliveryGroupExtrasMerger = opts.getParcelable(KEY_DELIVERY_GROUP_EXTRAS_MERGER,
                 BundleMerger.class);
         mDeliveryGroupMatchingFilter = opts.getParcelable(KEY_DELIVERY_GROUP_MATCHING_FILTER,
@@ -851,11 +857,8 @@
     @NonNull
     public BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String namespace,
             @NonNull String key) {
-        Preconditions.checkArgument(!namespace.contains(":"),
-                "namespace should not contain ':'");
-        Preconditions.checkArgument(!key.contains(":"),
-                "key should not contain ':'");
-        mDeliveryGroupMatchingKey = namespace + ":" + key;
+        mDeliveryGroupMatchingNamespaceFragment = Objects.requireNonNull(namespace);
+        mDeliveryGroupMatchingKeyFragment = Objects.requireNonNull(key);
         return this;
     }
 
@@ -868,7 +871,38 @@
      */
     @Nullable
     public String getDeliveryGroupMatchingKey() {
-        return mDeliveryGroupMatchingKey;
+        if (mDeliveryGroupMatchingNamespaceFragment == null
+                || mDeliveryGroupMatchingKeyFragment == null) {
+            return null;
+        }
+        return String.join(":", mDeliveryGroupMatchingNamespaceFragment,
+                mDeliveryGroupMatchingKeyFragment);
+    }
+
+    /**
+     * Return the namespace fragment that is used to identify the delivery group that this
+     * broadcast belongs to.
+     *
+     * @return the delivery group namespace fragment that was previously set using
+     *         {@link #setDeliveryGroupMatchingKey(String, String)}.
+     * @hide
+     */
+    @Nullable
+    public String getDeliveryGroupMatchingNamespaceFragment() {
+        return mDeliveryGroupMatchingNamespaceFragment;
+    }
+
+    /**
+     * Return the key fragment that is used to identify the delivery group that this
+     * broadcast belongs to.
+     *
+     * @return the delivery group key fragment that was previously set using
+     *         {@link #setDeliveryGroupMatchingKey(String, String)}.
+     * @hide
+     */
+    @Nullable
+    public String getDeliveryGroupMatchingKeyFragment() {
+        return mDeliveryGroupMatchingKeyFragment;
     }
 
     /**
@@ -876,7 +910,8 @@
      * {@link #setDeliveryGroupMatchingKey(String, String)}.
      */
     public void clearDeliveryGroupMatchingKey() {
-        mDeliveryGroupMatchingKey = null;
+        mDeliveryGroupMatchingNamespaceFragment = null;
+        mDeliveryGroupMatchingKeyFragment = null;
     }
 
     /**
@@ -1094,8 +1129,11 @@
         if (mDeliveryGroupPolicy != DELIVERY_GROUP_POLICY_ALL) {
             b.putInt(KEY_DELIVERY_GROUP_POLICY, mDeliveryGroupPolicy);
         }
-        if (mDeliveryGroupMatchingKey != null) {
-            b.putString(KEY_DELIVERY_GROUP_KEY, mDeliveryGroupMatchingKey);
+        if (mDeliveryGroupMatchingNamespaceFragment != null) {
+            b.putString(KEY_DELIVERY_GROUP_NAMESPACE, mDeliveryGroupMatchingNamespaceFragment);
+        }
+        if (mDeliveryGroupMatchingKeyFragment != null) {
+            b.putString(KEY_DELIVERY_GROUP_KEY, mDeliveryGroupMatchingKeyFragment);
         }
         if (mDeliveryGroupPolicy == DELIVERY_GROUP_POLICY_MERGED) {
             if (mDeliveryGroupExtrasMerger != null) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 6bd3c79..e6ef3b4 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -999,23 +999,50 @@
 
     private static boolean matchesDeliveryGroup(@NonNull BroadcastRecord newRecord,
             @NonNull BroadcastRecord oldRecord) {
-        final String newMatchingKey = getDeliveryGroupMatchingKey(newRecord);
-        final String oldMatchingKey = getDeliveryGroupMatchingKey(oldRecord);
         final IntentFilter newMatchingFilter = getDeliveryGroupMatchingFilter(newRecord);
         // If neither delivery group key nor matching filter is specified, then use
         // Intent.filterEquals() to identify the delivery group.
-        if (newMatchingKey == null && oldMatchingKey == null && newMatchingFilter == null) {
+        if (isMatchingKeyNull(newRecord) && isMatchingKeyNull(oldRecord)
+                && newMatchingFilter == null) {
             return newRecord.intent.filterEquals(oldRecord.intent);
         }
         if (newMatchingFilter != null && !newMatchingFilter.asPredicate().test(oldRecord.intent)) {
             return false;
         }
-        return Objects.equals(newMatchingKey, oldMatchingKey);
+        return areMatchingKeysEqual(newRecord, oldRecord);
+    }
+
+    private static boolean isMatchingKeyNull(@NonNull BroadcastRecord record) {
+        final String namespace = getDeliveryGroupMatchingNamespaceFragment(record);
+        final String key = getDeliveryGroupMatchingKeyFragment(record);
+        // If either namespace or key part is null, then treat the entire matching key as null.
+        return namespace == null || key == null;
+    }
+
+    private static boolean areMatchingKeysEqual(@NonNull BroadcastRecord newRecord,
+            @NonNull BroadcastRecord oldRecord) {
+        final String newNamespaceFragment = getDeliveryGroupMatchingNamespaceFragment(newRecord);
+        final String oldNamespaceFragment = getDeliveryGroupMatchingNamespaceFragment(oldRecord);
+        if (!Objects.equals(newNamespaceFragment, oldNamespaceFragment)) {
+            return false;
+        }
+
+        final String newKeyFragment = getDeliveryGroupMatchingKeyFragment(newRecord);
+        final String oldKeyFragment = getDeliveryGroupMatchingKeyFragment(oldRecord);
+        return Objects.equals(newKeyFragment, oldKeyFragment);
     }
 
     @Nullable
-    private static String getDeliveryGroupMatchingKey(@NonNull BroadcastRecord record) {
-        return record.options == null ? null : record.options.getDeliveryGroupMatchingKey();
+    private static String getDeliveryGroupMatchingNamespaceFragment(
+            @NonNull BroadcastRecord record) {
+        return record.options == null
+                ? null : record.options.getDeliveryGroupMatchingNamespaceFragment();
+    }
+
+    @Nullable
+    private static String getDeliveryGroupMatchingKeyFragment(@NonNull BroadcastRecord record) {
+        return record.options == null
+                ? null : record.options.getDeliveryGroupMatchingKeyFragment();
     }
 
     @Nullable