N1_MODE_CAPABILITY Exclusion for Emergency Session am: 62a52056a5

Original change: https://android-review.googlesource.com/c/platform/packages/services/Iwlan/+/2935533

Change-Id: Id870a9ba5ed9245c8281ae6ab9819ebec7e0d59c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/flags/main.aconfig b/flags/main.aconfig
index 9bc80a1..57b0527 100644
--- a/flags/main.aconfig
+++ b/flags/main.aconfig
@@ -1,4 +1,5 @@
 package: "com.google.android.iwlan.flags"
+container: "system"
 
 flag {
     name: "prevent_epdg_selection_threads_exhausted"
@@ -7,6 +8,24 @@
     bug: "278788983"
 }
 flag {
+    name: "aead_algos_enabled"
+    namespace: "iwlan_telephony"
+    description: "Add AES_GCM algorithm support in IWLAN."
+    bug: "306119890"
+}
+flag {
+    name: "multiple_sa_proposals"
+    namespace: "iwlan_telephony"
+    description: "Add multiple proposals of IKE SA and Child SA"
+    bug: "287296642"
+}
+flag {
+    name: "high_secure_transforms_prioritized"
+    namespace: "iwlan_telephony"
+    description: "Reorder IKE and Child SA security transforms with high secured as prioritized"
+    bug: "306323917"
+}
+flag {
     name: "epdg_selection_exclude_failed_ip_address"
     namespace: "iwlan_telephony"
     description: "Exclude the failed ip address in epdg selection until tunnel establish successfully or all ip address candidates are failed"
diff --git a/src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java b/src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java
new file mode 100644
index 0000000..d85e322
--- /dev/null
+++ b/src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 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 com.google.android.iwlan.epdg;
+
+import android.net.ipsec.ike.ChildSaProposal;
+import android.util.Pair;
+
+public class EpdgChildSaProposal extends EpdgSaProposal {
+    /**
+     * Builds {@link ChildSaProposal} of carrier proposed encryption algorithms (non-AEAD) cipher
+     * suit.
+     */
+    public ChildSaProposal buildProposedChildSaProposal() {
+        return buildProposal(false, true);
+    }
+
+    /** Builds {@link ChildSaProposal} of carrier proposed AEAD algorithms cipher suit. */
+    public ChildSaProposal buildProposedChildSaAeadProposal() {
+        return buildProposal(true, true);
+    }
+
+    /**
+     * Builds {@link ChildSaProposal} of Iwlan supported encryption algorithms (non-AEAD) cipher
+     * suit.
+     */
+    public ChildSaProposal buildSupportedChildSaProposal() {
+        return buildProposal(false, false);
+    }
+
+    /** Builds {@link ChildSaProposal} of Iwlan supported AEAD algorithms cipher suit. */
+    public ChildSaProposal buildSupportedChildSaAeadProposal() {
+        return buildProposal(true, false);
+    }
+
+    private ChildSaProposal buildProposal(boolean isAead, boolean isProposed) {
+        ChildSaProposal.Builder saProposalBuilder = new ChildSaProposal.Builder();
+
+        int[] dhGroups = getDhGroups();
+        for (int dhGroup : dhGroups) {
+            saProposalBuilder.addDhGroup(dhGroup);
+        }
+
+        Pair<Integer, Integer>[] encrAlgos;
+
+        if (isAead) {
+            encrAlgos = (isProposed) ? getAeadAlgos() : getSupportedAeadAlgos();
+        } else {
+            encrAlgos = (isProposed) ? getEncryptionAlgos() : getSupportedEncryptionAlgos();
+        }
+
+        for (Pair<Integer, Integer> encrAlgo : encrAlgos) {
+            saProposalBuilder.addEncryptionAlgorithm(encrAlgo.first, encrAlgo.second);
+        }
+
+        if (!isAead) {
+            int[] integrityAlgos =
+                    (isProposed) ? getIntegrityAlgos() : getSupportedIntegrityAlgos();
+            for (int integrityAlgo : integrityAlgos) {
+                saProposalBuilder.addIntegrityAlgorithm(integrityAlgo);
+            }
+        }
+
+        return saProposalBuilder.build();
+    }
+}
diff --git a/src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java b/src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java
new file mode 100644
index 0000000..f4d6d56
--- /dev/null
+++ b/src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020 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 com.google.android.iwlan.epdg;
+
+import android.net.ipsec.ike.IkeSaProposal;
+import android.util.Pair;
+
+import java.util.LinkedHashSet;
+
+public class EpdgIkeSaProposal extends EpdgSaProposal {
+    protected final LinkedHashSet<Integer> mProposedPrfAlgos = new LinkedHashSet<>();
+
+    /**
+     * Add proposed PRF algorithms by the carrier.
+     *
+     * @param prfAlgos proposed PRF algorithms
+     */
+    public void addProposedPrfAlgorithm(int[] prfAlgos) {
+        for (int prfAlgo : prfAlgos) {
+            if (validateConfig(prfAlgo, VALID_PRF_ALGOS, CONFIG_TYPE_PRF_ALGO)) {
+                mProposedPrfAlgos.add(prfAlgo);
+            }
+        }
+    }
+
+    private int[] getPrfAlgos() {
+        if (isSaferProposalsPrioritized()) {
+            return mProposedPrfAlgos.stream()
+                    .sorted(
+                            (item1, item2) ->
+                                    compareTransformPriority(VALID_PRF_ALGOS, item1, item2))
+                    .mapToInt(Integer::intValue)
+                    .toArray();
+        }
+
+        return mProposedPrfAlgos.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    private int[] getSupportedPrfAlgos() {
+        return VALID_PRF_ALGOS.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    /**
+     * Builds {@link IkeSaProposal} of carrier proposed encryption algorithms (non-AEAD) cipher
+     * suit.
+     */
+    public IkeSaProposal buildProposedIkeSaProposal() {
+        return buildProposal(false, true);
+    }
+
+    /** Builds {@link IkeSaProposal} of carrier proposed AEAD algorithms cipher suit. */
+    public IkeSaProposal buildProposedIkeSaAeadProposal() {
+        return buildProposal(true, true);
+    }
+
+    /**
+     * Builds {@link IkeSaProposal} of Iwlan supported encryption algorithms (non-AEAD) cipher suit.
+     */
+    public IkeSaProposal buildSupportedIkeSaProposal() {
+        return buildProposal(false, false);
+    }
+
+    /** Builds {@link IkeSaProposal} of Iwlan supported AEAD algorithms cipher suit. */
+    public IkeSaProposal buildSupportedIkeSaAeadProposal() {
+        return buildProposal(true, false);
+    }
+
+    private IkeSaProposal buildProposal(boolean isAead, boolean isProposed) {
+        IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder();
+
+        int[] dhGroups = isProposed ? getDhGroups() : getSupportedDhGroups();
+        for (int dhGroup : dhGroups) {
+            saProposalBuilder.addDhGroup(dhGroup);
+        }
+
+        Pair<Integer, Integer>[] encrAlgos;
+
+        if (isAead) {
+            encrAlgos = (isProposed) ? getAeadAlgos() : getSupportedAeadAlgos();
+        } else {
+            encrAlgos = (isProposed) ? getEncryptionAlgos() : getSupportedEncryptionAlgos();
+        }
+
+        for (Pair<Integer, Integer> encrAlgo : encrAlgos) {
+            saProposalBuilder.addEncryptionAlgorithm(encrAlgo.first, encrAlgo.second);
+        }
+
+        if (!isAead) {
+            int[] integrityAlgos =
+                    (isProposed) ? getIntegrityAlgos() : getSupportedIntegrityAlgos();
+            for (int integrityAlgo : integrityAlgos) {
+                saProposalBuilder.addIntegrityAlgorithm(integrityAlgo);
+            }
+        }
+
+        int[] prfAlgos = (isProposed) ? getPrfAlgos() : getSupportedPrfAlgos();
+        for (int prfAlgo : prfAlgos) {
+            saProposalBuilder.addPseudorandomFunction(prfAlgo);
+        }
+
+        return saProposalBuilder.build();
+    }
+}
diff --git a/src/com/google/android/iwlan/epdg/EpdgSaProposal.java b/src/com/google/android/iwlan/epdg/EpdgSaProposal.java
new file mode 100644
index 0000000..871cc5c
--- /dev/null
+++ b/src/com/google/android/iwlan/epdg/EpdgSaProposal.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2020 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 com.google.android.iwlan.epdg;
+
+import android.net.ipsec.ike.SaProposal;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+abstract class EpdgSaProposal {
+    private static final String TAG = EpdgSaProposal.class.getSimpleName();
+    private static final Set<Integer> VALID_DH_GROUPS;
+    private static final Set<Integer> VALID_KEY_LENGTHS;
+    protected static final Set<Integer> VALID_PRF_ALGOS;
+    private static final Set<Integer> VALID_INTEGRITY_ALGOS;
+    private static final Set<Integer> VALID_ENCRYPTION_ALGOS;
+    private static final Set<Integer> VALID_AEAD_ALGOS;
+
+    private static final String CONFIG_TYPE_DH_GROUP = "dh group";
+    private static final String CONFIG_TYPE_KEY_LEN = "algorithm key length";
+    protected static final String CONFIG_TYPE_PRF_ALGO = "prf algorithm";
+    private static final String CONFIG_TYPE_INTEGRITY_ALGO = "integrity algorithm";
+    private static final String CONFIG_TYPE_ENCRYPT_ALGO = "encryption algorithm";
+    private static final String CONFIG_TYPE_AEAD_ALGO = "AEAD algorithm";
+
+    private boolean mSaferAlgosPrioritized = false;
+
+    /*
+     * Each transform below filled with high secured order and index of each value
+     * represents the priority.
+     * Safer transform has high priority and proposals will be orders based on
+     * the priority order.
+     * For example, DH Group 4096 has more priority compare to 3072, and 3072
+     * has more priority than 2048.
+     * With reference to 3GPP TS 33.210 and RFC 8221, high secured transforms
+     * are prioritized in IKE and CHILD SA proposals.
+     */
+    static {
+        VALID_DH_GROUPS =
+                Collections.unmodifiableSet(
+                        new LinkedHashSet<Integer>(
+                                List.of(
+                                        SaProposal.DH_GROUP_4096_BIT_MODP,
+                                        SaProposal.DH_GROUP_3072_BIT_MODP,
+                                        SaProposal.DH_GROUP_2048_BIT_MODP,
+                                        SaProposal.DH_GROUP_1536_BIT_MODP,
+                                        SaProposal.DH_GROUP_1024_BIT_MODP)));
+
+        VALID_KEY_LENGTHS =
+                Collections.unmodifiableSet(
+                        new LinkedHashSet<Integer>(
+                                List.of(
+                                        SaProposal.KEY_LEN_AES_256,
+                                        SaProposal.KEY_LEN_AES_192,
+                                        SaProposal.KEY_LEN_AES_128)));
+
+        VALID_ENCRYPTION_ALGOS =
+                Collections.unmodifiableSet(
+                        new LinkedHashSet<Integer>(
+                                List.of(
+                                        SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
+                                        SaProposal.ENCRYPTION_ALGORITHM_AES_CTR)));
+
+        VALID_INTEGRITY_ALGOS =
+                Collections.unmodifiableSet(
+                        new LinkedHashSet<Integer>(
+                                List.of(
+                                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
+                                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
+                                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
+                                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+                                        SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96)));
+
+        VALID_AEAD_ALGOS =
+                Collections.unmodifiableSet(
+                        new LinkedHashSet<Integer>(
+                                List.of(
+                                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
+                                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
+                                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)));
+
+        VALID_PRF_ALGOS =
+                Collections.unmodifiableSet(
+                        new LinkedHashSet<Integer>(
+                                List.of(
+                                        SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512,
+                                        SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384,
+                                        SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256,
+                                        SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
+                                        SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)));
+    }
+
+    protected final LinkedHashSet<Integer> mProposedDhGroups = new LinkedHashSet<>();
+    protected final LinkedHashSet<Integer> mProposedIntegrityAlgos = new LinkedHashSet<>();
+    protected final LinkedHashSet<Pair<Integer, Integer>> mProposedEncryptAlgos =
+            new LinkedHashSet<>();
+    protected final LinkedHashSet<Pair<Integer, Integer>> mProposedAeadAlgos =
+            new LinkedHashSet<>();
+
+    /**
+     * Add proposed DH groups by the carrier.
+     *
+     * @param dhGroups proposed DH groups
+     */
+    public void addProposedDhGroups(int[] dhGroups) {
+        for (int dhGroup : dhGroups) {
+            if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
+                mProposedDhGroups.add(dhGroup);
+            }
+        }
+    }
+
+    /**
+     * Add proposed integrity algorithms by the carrier.
+     *
+     * @param integrityAlgos proposed integrity algorithms
+     */
+    public void addProposedIntegrityAlgorithm(int[] integrityAlgos) {
+        for (int integrityAlgo : integrityAlgos) {
+            if (validateConfig(integrityAlgo, VALID_INTEGRITY_ALGOS, CONFIG_TYPE_INTEGRITY_ALGO)) {
+                mProposedIntegrityAlgos.add(integrityAlgo);
+            }
+        }
+    }
+
+    /**
+     * Add proposed encryption algorithms and respective key lengths by the carrier.
+     *
+     * @param encryptionAlgo proposed encryption algorithm
+     * @param keyLens proposed key lengths for the encryption algorithm
+     */
+    public void addProposedEncryptionAlgorithm(int encryptionAlgo, int[] keyLens) {
+        if (validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
+            for (int keyLen : keyLens) {
+                if (validateConfig(keyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
+                    mProposedEncryptAlgos.add(new Pair<Integer, Integer>(encryptionAlgo, keyLen));
+                }
+            }
+        }
+    }
+
+    /**
+     * Add proposed AEAD algorithms and respective key lengths by the carrier.
+     *
+     * @param aeadAlgo proposed AEAD algorithm
+     * @param keyLens proposed key lengths for the encryption algorithm
+     */
+    public void addProposedAeadAlgorithm(int aeadAlgo, int[] keyLens) {
+        if (validateConfig(aeadAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_AEAD_ALGO)) {
+            for (int keyLen : keyLens) {
+                if (validateConfig(keyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
+                    mProposedAeadAlgos.add(new Pair<Integer, Integer>(aeadAlgo, keyLen));
+                }
+            }
+        }
+    }
+
+    /** Enable to reorder proposals with safer ciphers prioritized. */
+    public void enableReorderingSaferProposals() {
+        mSaferAlgosPrioritized = true;
+    }
+
+    /**
+     * Disable to reorder proposals with safer ciphers prioritized.Follows default configured order.
+     */
+    public void disableReorderingSaferProposals() {
+        mSaferAlgosPrioritized = false;
+    }
+
+    protected boolean isSaferProposalsPrioritized() {
+        return mSaferAlgosPrioritized;
+    }
+
+    protected int getIndexOf(Set<Integer> set, int value) {
+        Iterator<Integer> itr = set.iterator();
+        int index = 0;
+
+        while (itr.hasNext()) {
+            if (itr.next().equals(value)) {
+                return index;
+            }
+            index++;
+        }
+
+        return -1;
+    }
+
+    /**
+     * Compares the priority of the transforms.
+     */
+    protected int compareTransformPriority(Set<Integer> transformGroup, int item1, int item2) {
+        return getIndexOf(transformGroup, item1) - getIndexOf(transformGroup, item2);
+    }
+
+    /**
+     * Compares the priority of the encryption/AEAD transforms.
+     * First value in pair is encryption/AEAD algorithm and
+     * second value in pair is key length of that algorithm.
+     * If Algorithms are same then compare the priotity of the key lengths else compare
+     * the priority of the algorithms.
+     */
+    protected int compareEncryptionTransformPriority(
+            Set<Integer> algos,
+            Set<Integer> keyLens,
+            Pair<Integer, Integer> item1,
+            Pair<Integer, Integer> item2) {
+        return item1.first.equals(item2.first)
+                ? getIndexOf(keyLens, item1.second) - getIndexOf(keyLens, item2.second)
+                : getIndexOf(algos, item1.first) - getIndexOf(algos, item2.first);
+    }
+
+    protected int[] getDhGroups() {
+        if (isSaferProposalsPrioritized()) {
+            return mProposedDhGroups.stream()
+                    .sorted(
+                            (item1, item2) ->
+                                    compareTransformPriority(VALID_DH_GROUPS, item1, item2))
+                    .mapToInt(Integer::intValue)
+                    .toArray();
+        }
+
+        return mProposedDhGroups.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    protected int[] getSupportedDhGroups() {
+        return VALID_DH_GROUPS.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    protected int[] getIntegrityAlgos() {
+        if (isSaferProposalsPrioritized()) {
+            return mProposedIntegrityAlgos.stream()
+                    .sorted(
+                            (item1, item2) ->
+                                    compareTransformPriority(VALID_INTEGRITY_ALGOS, item1, item2))
+                    .mapToInt(Integer::intValue)
+                    .toArray();
+        }
+
+        return mProposedIntegrityAlgos.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    protected int[] getSupportedIntegrityAlgos() {
+        return VALID_INTEGRITY_ALGOS.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    protected Pair<Integer, Integer>[] getEncryptionAlgos() {
+        if (isSaferProposalsPrioritized()) {
+            return mProposedEncryptAlgos.stream()
+                    .sorted(
+                            (item1, item2) ->
+                                    compareEncryptionTransformPriority(
+                                            VALID_ENCRYPTION_ALGOS,
+                                            VALID_KEY_LENGTHS,
+                                            item1,
+                                            item2))
+                    .toArray(Pair[]::new);
+        }
+
+        return mProposedEncryptAlgos.toArray(new Pair[mProposedEncryptAlgos.size()]);
+    }
+
+    protected Pair<Integer, Integer>[] getSupportedEncryptionAlgos() {
+        Pair<Integer, Integer>[] encrAlgos =
+                new Pair[VALID_ENCRYPTION_ALGOS.size() * VALID_KEY_LENGTHS.size()];
+        int index = 0;
+        for (int algo : VALID_ENCRYPTION_ALGOS) {
+            for (int len : VALID_KEY_LENGTHS) {
+                encrAlgos[index++] = new Pair(algo, len);
+            }
+        }
+
+        return encrAlgos;
+    }
+
+    protected Pair<Integer, Integer>[] getAeadAlgos() {
+        if (isSaferProposalsPrioritized()) {
+            return mProposedAeadAlgos.stream()
+                    .sorted(
+                            (item1, item2) ->
+                                    compareEncryptionTransformPriority(
+                                            VALID_AEAD_ALGOS, VALID_KEY_LENGTHS, item1, item2))
+                    .toArray(Pair[]::new);
+        }
+
+        return mProposedAeadAlgos.toArray(new Pair[mProposedAeadAlgos.size()]);
+    }
+
+    protected Pair<Integer, Integer>[] getSupportedAeadAlgos() {
+        Pair<Integer, Integer>[] aeadAlgos =
+                new Pair[VALID_AEAD_ALGOS.size() * VALID_KEY_LENGTHS.size()];
+        int index = 0;
+        for (int algo : VALID_AEAD_ALGOS) {
+            for (int len : VALID_KEY_LENGTHS) {
+                aeadAlgos[index++] = new Pair(algo, len);
+            }
+        }
+
+        return aeadAlgos;
+    }
+
+    protected static boolean validateConfig(
+            int config, Set<Integer> validConfigValues, String configType) {
+        if (validConfigValues.contains(config)) {
+            return true;
+        }
+
+        Log.e(TAG, "Invalid config value for " + configType + ":" + config);
+        return false;
+    }
+}
diff --git a/src/com/google/android/iwlan/epdg/EpdgSelector.java b/src/com/google/android/iwlan/epdg/EpdgSelector.java
index 3db6ac2..c231d50 100644
--- a/src/com/google/android/iwlan/epdg/EpdgSelector.java
+++ b/src/com/google/android/iwlan/epdg/EpdgSelector.java
@@ -153,6 +153,9 @@
         mV4PcoData = new ArrayList<>();
         mV6PcoData = new ArrayList<>();
 
+        mV4PcoData = new ArrayList<>();
+        mV6PcoData = new ArrayList<>();
+
         mErrorPolicyManager = ErrorPolicyManager.getInstance(mContext, mSlotId);
 
         mTemporaryExcludedAddresses = new HashSet<>();
diff --git a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
index 47f3fa3..fc9be74 100644
--- a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
+++ b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
@@ -76,6 +76,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.android.iwlan.ErrorPolicyManager;
+import com.google.android.iwlan.IwlanCarrierConfig;
 import com.google.android.iwlan.IwlanError;
 import com.google.android.iwlan.IwlanHelper;
 import com.google.android.iwlan.IwlanTunnelMetricsImpl;
@@ -187,6 +188,7 @@
     private static final Set<Integer> VALID_PRF_ALGOS;
     private static final Set<Integer> VALID_INTEGRITY_ALGOS;
     private static final Set<Integer> VALID_ENCRYPTION_ALGOS;
+    private static final Set<Integer> VALID_AEAD_ALGOS;
 
     private static final String CONFIG_TYPE_DH_GROUP = "dh group";
     private static final String CONFIG_TYPE_KEY_LEN = "algorithm key length";
@@ -221,6 +223,12 @@
                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
 
+        VALID_AEAD_ALGOS =
+                Set.of(
+                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
+                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
+                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16);
+
         VALID_PRF_ALGOS =
                 Set.of(
                         SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
@@ -920,7 +928,35 @@
                 new TunnelModeChildSessionParams.Builder()
                         .setLifetimeSeconds(hardTimeSeconds, softTimeSeconds);
 
-        childSessionParamsBuilder.addChildSaProposal(buildChildSaProposal());
+        if (mFeatureFlags.multipleSaProposals()
+                && IwlanCarrierConfig.getConfigBoolean(
+                        mContext,
+                        mSlotId,
+                        CarrierConfigManager.Iwlan
+                                .KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL)) {
+            EpdgChildSaProposal epdgChildSaProposal = createEpdgChildSaProposal();
+
+            if (mFeatureFlags.highSecureTransformsPrioritized()) {
+                epdgChildSaProposal.enableReorderingSaferProposals();
+            }
+
+            if (isChildSessionAeadAlgosAvailable()) {
+                childSessionParamsBuilder.addChildSaProposal(
+                        epdgChildSaProposal.buildProposedChildSaAeadProposal());
+            }
+            childSessionParamsBuilder.addChildSaProposal(
+                    epdgChildSaProposal.buildProposedChildSaProposal());
+            childSessionParamsBuilder.addChildSaProposal(
+                    epdgChildSaProposal.buildSupportedChildSaAeadProposal());
+            childSessionParamsBuilder.addChildSaProposal(
+                    epdgChildSaProposal.buildSupportedChildSaProposal());
+        } else {
+            if (mFeatureFlags.aeadAlgosEnabled() && isChildSessionAeadAlgosAvailable()) {
+                childSessionParamsBuilder.addChildSaProposal(buildAeadChildSaProposal());
+            } else {
+                childSessionParamsBuilder.addChildSaProposal(buildChildSaProposal());
+            }
+        }
 
         boolean handoverIPv4Present = setupRequest.srcIpv4Address().isPresent();
         boolean handoverIPv6Present = setupRequest.srcIpv6Address().isPresent();
@@ -1049,7 +1085,6 @@
                         .setLocalIdentification(getLocalIdentification())
                         .setRemoteIdentification(getId(setupRequest.apnName(), false))
                         .setAuthEap(null, getEapConfig())
-                        .addIkeSaProposal(buildIkeSaProposal())
                         .setNetwork(mDefaultNetwork)
                         .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
                         .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
@@ -1058,6 +1093,32 @@
                         .setRetransmissionTimeoutsMillis(getRetransmissionTimeoutsFromConfig())
                         .setDpdDelaySeconds(getDpdDelayFromConfig());
 
+        if (mFeatureFlags.multipleSaProposals()
+                && IwlanCarrierConfig.getConfigBoolean(
+                        mContext,
+                        mSlotId,
+                        CarrierConfigManager.Iwlan
+                                .KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL)) {
+            EpdgIkeSaProposal epdgIkeSaProposal = createEpdgIkeSaProposal();
+
+            if (mFeatureFlags.highSecureTransformsPrioritized()) {
+                epdgIkeSaProposal.enableReorderingSaferProposals();
+            }
+
+            if (isIkeSessionAeadAlgosAvailable()) {
+                builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaAeadProposal());
+            }
+            builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaProposal());
+            builder.addIkeSaProposal(epdgIkeSaProposal.buildSupportedIkeSaAeadProposal());
+            builder.addIkeSaProposal(epdgIkeSaProposal.buildSupportedIkeSaProposal());
+        } else {
+            if (mFeatureFlags.aeadAlgosEnabled() && isIkeSessionAeadAlgosAvailable()) {
+                builder.addIkeSaProposal(buildIkeSaAeadProposal());
+            } else {
+                builder.addIkeSaProposal(buildIkeSaProposal());
+            }
+        }
+
         if (numPdnTunnels() == 0) {
             builder.addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT);
             Log.d(TAG, "IKE_OPTION_INITIAL_CONTACT");
@@ -1122,6 +1183,32 @@
                 builder3gppParams.build(), new TmIke3gppCallback(apnName, token));
     }
 
+    private boolean isChildSessionAeadAlgosAvailable() {
+        int[] encryptionAlgos =
+                getConfig(
+                        CarrierConfigManager.Iwlan
+                                .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
+        for (int encryptionAlgo : encryptionAlgos) {
+            if (validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isIkeSessionAeadAlgosAvailable() {
+        int[] encryptionAlgos =
+                getConfig(
+                        CarrierConfigManager.Iwlan
+                                .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
+        for (int encryptionAlgo : encryptionAlgos) {
+            if (validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean isValidChildSessionLifetime(int hardLifetimeSeconds, int softLifetimeSeconds) {
         return hardLifetimeSeconds >= CHILD_HARD_LIFETIME_SEC_MINIMUM
                 && hardLifetimeSeconds <= CHILD_HARD_LIFETIME_SEC_MAXIMUM
@@ -1140,6 +1227,124 @@
         return IwlanHelper.getConfig(configKey, mContext, mSlotId);
     }
 
+    private void createEpdgSaProposal(EpdgSaProposal epdgSaProposal, boolean isChildProposal) {
+        epdgSaProposal.addProposedDhGroups(
+                IwlanCarrierConfig.getConfigIntArray(
+                        mContext,
+                        mSlotId,
+                        CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY));
+
+        int[] encryptionAlgos =
+                isChildProposal
+                        ? IwlanCarrierConfig.getConfigIntArray(
+                                mContext,
+                                mSlotId,
+                                CarrierConfigManager.Iwlan
+                                    .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY)
+                        : IwlanCarrierConfig.getConfigIntArray(
+                                mContext,
+                                mSlotId,
+                                CarrierConfigManager.Iwlan
+                                    .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY);
+
+        for (int encryptionAlgo : encryptionAlgos) {
+            if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CBC) {
+                int[] aesCbcKeyLens =
+                        isChildProposal
+                                ? IwlanCarrierConfig.getConfigIntArray(
+                                        mContext,
+                                        mSlotId,
+                                        CarrierConfigManager.Iwlan
+                                                .KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY)
+                                : IwlanCarrierConfig.getConfigIntArray(
+                                        mContext,
+                                        mSlotId,
+                                        CarrierConfigManager.Iwlan
+                                                .KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY);
+                epdgSaProposal.addProposedEncryptionAlgorithm(encryptionAlgo, aesCbcKeyLens);
+            }
+
+            if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CTR) {
+                int[] aesCtrKeyLens =
+                        isChildProposal
+                                ? IwlanCarrierConfig.getConfigIntArray(
+                                        mContext,
+                                        mSlotId,
+                                        CarrierConfigManager.Iwlan
+                                                .KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY)
+                                : IwlanCarrierConfig.getConfigIntArray(
+                                        mContext,
+                                        mSlotId,
+                                        CarrierConfigManager.Iwlan
+                                                .KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY);
+                epdgSaProposal.addProposedEncryptionAlgorithm(encryptionAlgo, aesCtrKeyLens);
+            }
+        }
+
+        if (encryptionAlgos.length > 0) {
+            epdgSaProposal.addProposedIntegrityAlgorithm(
+                    IwlanCarrierConfig.getConfigIntArray(
+                            mContext,
+                            mSlotId,
+                            CarrierConfigManager.Iwlan
+                                    .KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY));
+        }
+
+        int[] aeadAlgos =
+                isChildProposal
+                        ? IwlanCarrierConfig.getConfigIntArray(
+                                mContext,
+                                mSlotId,
+                                CarrierConfigManager.Iwlan
+                                        .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY)
+                        : IwlanCarrierConfig.getConfigIntArray(
+                                mContext,
+                                mSlotId,
+                                CarrierConfigManager.Iwlan
+                                        .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
+        for (int aeadAlgo : aeadAlgos) {
+            if (!validateConfig(aeadAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
+                continue;
+            }
+            if ((aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)
+                    || (aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
+                    || (aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) {
+                int[] aesGcmKeyLens =
+                        isChildProposal
+                                ? IwlanCarrierConfig.getConfigIntArray(
+                                        mContext,
+                                        mSlotId,
+                                        CarrierConfigManager.Iwlan
+                                                .KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY)
+                                : IwlanCarrierConfig.getConfigIntArray(
+                                        mContext,
+                                        mSlotId,
+                                        CarrierConfigManager.Iwlan
+                                                .KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY);
+                epdgSaProposal.addProposedAeadAlgorithm(aeadAlgo, aesGcmKeyLens);
+            }
+        }
+    }
+
+    private EpdgChildSaProposal createEpdgChildSaProposal() {
+        EpdgChildSaProposal epdgChildSaProposal = new EpdgChildSaProposal();
+        createEpdgSaProposal(epdgChildSaProposal, true);
+        return epdgChildSaProposal;
+    }
+
+    private EpdgIkeSaProposal createEpdgIkeSaProposal() {
+        EpdgIkeSaProposal epdgIkeSaProposal = new EpdgIkeSaProposal();
+
+        createEpdgSaProposal(epdgIkeSaProposal, false);
+
+        epdgIkeSaProposal.addProposedPrfAlgorithm(
+                IwlanCarrierConfig.getConfigIntArray(
+                        mContext,
+                        mSlotId,
+                        CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY));
+        return epdgIkeSaProposal;
+    }
+
     private IkeSaProposal buildIkeSaProposal() {
         IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder();
 
@@ -1201,6 +1406,50 @@
         return saProposalBuilder.build();
     }
 
+    private IkeSaProposal buildIkeSaAeadProposal() {
+        IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder();
+
+        int[] dhGroups = getConfig(CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY);
+        for (int dhGroup : dhGroups) {
+            if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
+                saProposalBuilder.addDhGroup(dhGroup);
+            }
+        }
+
+        int[] encryptionAlgos =
+                getConfig(
+                        CarrierConfigManager.Iwlan
+                                .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
+        for (int encryptionAlgo : encryptionAlgos) {
+            if (!validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
+                continue;
+            }
+            if ((encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)
+                    || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
+                    || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) {
+                int[] aesGcmKeyLens =
+                        getConfig(
+                                CarrierConfigManager.Iwlan
+                                        .KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY);
+                for (int aesGcmKeyLen : aesGcmKeyLens) {
+                    if (validateConfig(aesGcmKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
+                        saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesGcmKeyLen);
+                    }
+                }
+            }
+        }
+
+        int[] prfAlgos =
+                getConfig(CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY);
+        for (int prfAlgo : prfAlgos) {
+            if (validateConfig(prfAlgo, VALID_PRF_ALGOS, CONFIG_TYPE_PRF_ALGO)) {
+                saProposalBuilder.addPseudorandomFunction(prfAlgo);
+            }
+        }
+
+        return saProposalBuilder.build();
+    }
+
     private boolean validateConfig(int config, Set<Integer> validConfigValues, String configType) {
         if (validConfigValues.contains(config)) {
             return true;
@@ -1280,6 +1529,42 @@
         return saProposalBuilder.build();
     }
 
+    private ChildSaProposal buildAeadChildSaProposal() {
+        ChildSaProposal.Builder saProposalBuilder = new ChildSaProposal.Builder();
+
+        int[] dhGroups = getConfig(CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY);
+        for (int dhGroup : dhGroups) {
+            if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
+                saProposalBuilder.addDhGroup(dhGroup);
+            }
+        }
+
+        int[] encryptionAlgos =
+                getConfig(
+                        CarrierConfigManager.Iwlan
+                                .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY);
+        for (int encryptionAlgo : encryptionAlgos) {
+            if (!validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
+                continue;
+            }
+            if ((encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)
+                    || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
+                    || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) {
+                int[] aesGcmKeyLens =
+                        getConfig(
+                                CarrierConfigManager.Iwlan
+                                        .KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY);
+                for (int aesGcmKeyLen : aesGcmKeyLens) {
+                    if (validateConfig(aesGcmKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
+                        saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesGcmKeyLen);
+                    }
+                }
+            }
+        }
+
+        return saProposalBuilder.build();
+    }
+
     private IkeIdentification getLocalIdentification() throws IwlanSimNotReadyException {
         String nai;
 
diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
index b7004e7..ff413b5 100644
--- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
+++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
@@ -72,6 +73,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
+import android.util.Pair;
 
 import com.google.android.iwlan.IwlanError;
 import com.google.android.iwlan.IwlanTunnelMetricsImpl;
@@ -543,6 +545,207 @@
     }
 
     @Test
+    public void testAeadSaProposals() throws Exception {
+        when(mFakeFeatureFlags.aeadAlgosEnabled()).thenReturn(true);
+        final String apnName = "ims";
+        int[] aeadAlgos = {
+            SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
+            SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
+            SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
+        };
+        int[] aeadAlgosKeyLens = {
+            SaProposal.KEY_LEN_AES_128, SaProposal.KEY_LEN_AES_192, SaProposal.KEY_LEN_AES_256,
+        };
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY,
+                aeadAlgos);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY,
+                aeadAlgosKeyLens);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY,
+                aeadAlgos);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY,
+                aeadAlgosKeyLens);
+
+        setupMockForGetConfig(bundle);
+
+        IkeSessionArgumentCaptors tunnelArgumentCaptors =
+                verifyBringUpTunnelWithDnsQuery(apnName, mMockDefaultNetwork);
+
+        IkeSessionParams ikeTunnelParams = tunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue();
+
+        List<Pair<Integer, Integer>> ikeEncrAlgos =
+                ikeTunnelParams.getIkeSaProposals().get(0).getEncryptionAlgorithms();
+
+        assertTrue(ikeEncrAlgos.contains(new Pair(aeadAlgos[0], aeadAlgosKeyLens[0])));
+        assertEquals(
+                "IKE AEAD algorithms mismatch",
+                (long) aeadAlgos.length * aeadAlgosKeyLens.length,
+                (long) ikeEncrAlgos.size());
+
+        ChildSessionParams childTunnelParams =
+                tunnelArgumentCaptors.mChildSessionParamsCaptor.getValue();
+
+        List<Pair<Integer, Integer>> childEncrAlgos =
+                childTunnelParams.getChildSaProposals().get(0).getEncryptionAlgorithms();
+
+        assertTrue(childEncrAlgos.contains(new Pair(aeadAlgos[0], aeadAlgosKeyLens[0])));
+        assertEquals(
+                "Child AEAD algorithms mismatch",
+                (long) aeadAlgos.length * aeadAlgosKeyLens.length,
+                (long) childEncrAlgos.size());
+    }
+
+    @Test
+    public void testMultipleSaProposals() throws Exception {
+        when(mFakeFeatureFlags.multipleSaProposals()).thenReturn(true);
+        final String apnName = "ims";
+        PersistableBundle bundle = new PersistableBundle();
+
+        int[] aeadAlgos = {
+            SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
+        };
+        int[] aeadAlgosKeyLens = {
+            SaProposal.KEY_LEN_AES_192, SaProposal.KEY_LEN_AES_256,
+        };
+
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY,
+                aeadAlgos);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY,
+                aeadAlgosKeyLens);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY,
+                aeadAlgos);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY,
+                aeadAlgosKeyLens);
+
+        bundle.putBoolean(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL,
+                true);
+        bundle.putBoolean(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL,
+                true);
+
+        setupMockForGetConfig(bundle);
+
+        IkeSessionArgumentCaptors tunnelArgumentCaptors =
+                verifyBringUpTunnelWithDnsQuery(apnName, mMockDefaultNetwork);
+
+        IkeSessionParams ikeTunnelParams = tunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue();
+
+        assertTrue(ikeTunnelParams.getIkeSaProposals().size() > 1);
+
+        List<Pair<Integer, Integer>> ikeAeadAlgos =
+                ikeTunnelParams.getIkeSaProposals().get(0).getEncryptionAlgorithms();
+        assertEquals(
+                "Reorder higher AEAD in  IKE SA mismatch",
+                (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
+                (long) ikeAeadAlgos.get(0).first);
+
+        ChildSessionParams childTunnelParams =
+                tunnelArgumentCaptors.mChildSessionParamsCaptor.getValue();
+
+        assertTrue(childTunnelParams.getChildSaProposals().size() > 1);
+
+        List<Pair<Integer, Integer>> childAeadAlgos =
+                childTunnelParams.getChildSaProposals().get(0).getEncryptionAlgorithms();
+        assertEquals(
+                "Reorder higher AEAD in  Child SA mismatch",
+                (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
+                (long) childAeadAlgos.get(0).first);
+    }
+
+    @Test
+    public void testSaProposalsReorder() throws Exception {
+        when(mFakeFeatureFlags.aeadAlgosEnabled()).thenReturn(true);
+        when(mFakeFeatureFlags.multipleSaProposals()).thenReturn(true);
+        when(mFakeFeatureFlags.highSecureTransformsPrioritized()).thenReturn(true);
+
+        final String apnName = "ims";
+        int[] aeadAlgos = {
+            SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
+        };
+        int[] aeadAlgosKeyLens = {
+            SaProposal.KEY_LEN_AES_128, SaProposal.KEY_LEN_AES_192, SaProposal.KEY_LEN_AES_256,
+        };
+
+        PersistableBundle bundle = new PersistableBundle();
+
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan
+                        .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
+                aeadAlgos);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
+                aeadAlgosKeyLens);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan
+                        .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
+                aeadAlgos);
+        bundle.putIntArray(
+                CarrierConfigManager.Iwlan.KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
+                aeadAlgosKeyLens);
+
+        bundle.putBoolean(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL,
+                true);
+        bundle.putBoolean(
+                CarrierConfigManager.Iwlan.KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL,
+                true);
+
+        setupMockForGetConfig(bundle);
+
+        IkeSessionArgumentCaptors tunnelArgumentCaptors =
+                verifyBringUpTunnelWithDnsQuery(apnName, mMockDefaultNetwork);
+
+        IkeSessionParams ikeTunnelParams = tunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue();
+
+        assertTrue(ikeTunnelParams.getIkeSaProposals().size() > 1);
+
+        List<Pair<Integer, Integer>> ikeEncrAlgos =
+                ikeTunnelParams.getIkeSaProposals().get(0).getEncryptionAlgorithms();
+
+        assertEquals(
+                "Reorder bigger key length in IKE SA mismatch",
+                (long) SaProposal.KEY_LEN_AES_256,
+                (long) ikeEncrAlgos.get(0).second);
+
+        List<Pair<Integer, Integer>> ikeAeadAlgos =
+                ikeTunnelParams.getIkeSaProposals().get(1).getEncryptionAlgorithms();
+        assertEquals(
+                "Reorder higher AEAD in  IKE SA mismatch",
+                (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
+                (long) ikeAeadAlgos.get(0).first);
+
+        ChildSessionParams childTunnelParams =
+                tunnelArgumentCaptors.mChildSessionParamsCaptor.getValue();
+
+        assertTrue(childTunnelParams.getChildSaProposals().size() > 1);
+
+        List<Pair<Integer, Integer>> childEncrAlgos =
+                childTunnelParams.getChildSaProposals().get(0).getEncryptionAlgorithms();
+
+        assertEquals(
+                "Reorder bigger key length in Child SA mismatch",
+                (long) SaProposal.KEY_LEN_AES_256,
+                (long) childEncrAlgos.get(0).second);
+
+        List<Pair<Integer, Integer>> childAeadAlgos =
+                childTunnelParams.getChildSaProposals().get(1).getEncryptionAlgorithms();
+        assertEquals(
+                "Reorder higher AEAD in  Child SA mismatch",
+                (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
+                (long) childAeadAlgos.get(0).first);
+    }
+
+    @Test
     public void testCloseTunnelWithNoTunnelForApn() throws Exception {
         String testApnName = "www.xyz.com";
         doReturn(0L)
@@ -1153,6 +1356,7 @@
         when(mMockTelephonyManager.createForSubscriptionId(DEFAULT_SUBID))
                 .thenReturn(mMockTelephonyManager);
         when(mMockCarrierConfigManager.getConfigForSubId(DEFAULT_SLOT_INDEX)).thenReturn(bundle);
+        when(mMockCarrierConfigManager.getConfigForSubId(anyInt(), anyString())).thenReturn(bundle);
     }
 
     private void setVariable(Object target, String variableName, Object value) throws Exception {