Merge changes from topic "sdk-level"

* changes:
  Add methods to return supported algorithms
  Support getting IPsec algorithm name for a given IKE algorithm ID
diff --git a/Android.bp b/Android.bp
index 3ac8f3e..c5adaf4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -85,8 +85,10 @@
         "com.android.ipsec",
         "test_com.android.ipsec",
     ],
-    static_libs: ["bouncycastle_ike_digests"],
-    sdk_version: "core_current",
+    static_libs: [
+        "bouncycastle_ike_digests",
+        "modules-utils-build",],
+    sdk_version: "module_current",
 }
 
 java_library {
diff --git a/jarjar-rules-shared.txt b/jarjar-rules-shared.txt
index 1548696..7d3bea4 100644
--- a/jarjar-rules-shared.txt
+++ b/jarjar-rules-shared.txt
@@ -3,4 +3,5 @@
 rule android.telephony.Annotation* com.android.internal.net.eap.telephony.Annotation@1
 rule com.android.server.vcn.util.PersistableBundleUtils* com.android.internal.net.vcn.util.PersistableBundleUtils@1
 rule com.android.internal.util.** com.android.internal.net.ipsec.ike.utils.@1
+rule com.android.modules.utils.** com.android.internal.net.utils.@1
 rule org.bouncycastle.** com.android.internal.net.org.bouncycastle.@1
diff --git a/src/java/android/net/ipsec/ike/ChildSaProposal.java b/src/java/android/net/ipsec/ike/ChildSaProposal.java
index 1e3af9a..212c5d4 100644
--- a/src/java/android/net/ipsec/ike/ChildSaProposal.java
+++ b/src/java/android/net/ipsec/ike/ChildSaProposal.java
@@ -20,19 +20,25 @@
 
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
+import android.net.IpSecAlgorithm;
 import android.os.PersistableBundle;
+import android.util.ArraySet;
 
+import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
+import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
 import com.android.internal.net.ipsec.ike.message.IkePayload;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EsnTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
+import com.android.modules.utils.build.SdkLevel;
 import com.android.server.vcn.util.PersistableBundleUtils;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * ChildSaProposal represents a proposed configuration to negotiate a Child SA.
@@ -46,6 +52,25 @@
  *     Protocol Version 2 (IKEv2)</a>
  */
 public final class ChildSaProposal extends SaProposal {
+    // Before SDK S, there is no API in IpSecAlgorithm to retrieve supported algorithms. Thus hard
+    // coded these algorithms here.
+    private static final Set<Integer> SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S;
+    private static final Set<Integer> SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S;
+
+    static {
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S = new ArraySet<>();
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_CBC);
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_GCM_8);
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_GCM_12);
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_GCM_16);
+
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S = new ArraySet<>();
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+    }
+
     private static final String ESN_KEY = "mEsns";
     private final EsnTransform[] mEsns;
 
@@ -139,6 +164,61 @@
     }
 
     /**
+     * Returns supported encryption algorithms for Child SA proposal negotiation.
+     *
+     * <p>Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is
+     * supported before using it.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Set<Integer> getSupportedEncryptionAlgorithms() {
+        if (SdkLevel.isAtLeastS()) {
+            Set<Integer> algoIds = new ArraySet<>();
+            for (int i = 0; i < SUPPORTED_ENCRYPTION_ALGO_TO_STR.size(); i++) {
+                int ikeAlgoId = SUPPORTED_ENCRYPTION_ALGO_TO_STR.keyAt(i);
+                String ipSecAlgoName = IkeCipher.getIpSecAlgorithmName(ikeAlgoId);
+                if (IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName)) {
+                    algoIds.add(ikeAlgoId);
+                }
+            }
+            return algoIds;
+        } else {
+            return SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S;
+        }
+    }
+
+    /**
+     * Returns supported integrity algorithms for Child SA proposal negotiation.
+     *
+     * <p>Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is
+     * supported before using it.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Set<Integer> getSupportedIntegrityAlgorithms() {
+        Set<Integer> algoIds = new ArraySet<>();
+
+        // Although IpSecAlgorithm does not support INTEGRITY_ALGORITHM_NONE, IKE supports
+        // negotiating it and won't build IpSecAlgorithm with it.
+        algoIds.add(INTEGRITY_ALGORITHM_NONE);
+
+        if (SdkLevel.isAtLeastS()) {
+            for (int i = 0; i < SUPPORTED_INTEGRITY_ALGO_TO_STR.size(); i++) {
+                int ikeAlgoId = SUPPORTED_INTEGRITY_ALGO_TO_STR.keyAt(i);
+                String ipSecAlgoName = IkeMacIntegrity.getIpSecAlgorithmName(ikeAlgoId);
+                if (IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName)) {
+                    algoIds.add(ikeAlgoId);
+                }
+            }
+        } else {
+            algoIds.addAll(SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S);
+        }
+        return algoIds;
+    }
+
+    /**
      * Gets all ESN policies.
      *
      * @hide
diff --git a/src/java/android/net/ipsec/ike/IkeSaProposal.java b/src/java/android/net/ipsec/ike/IkeSaProposal.java
index 7b93963..277cdd5 100644
--- a/src/java/android/net/ipsec/ike/IkeSaProposal.java
+++ b/src/java/android/net/ipsec/ike/IkeSaProposal.java
@@ -132,6 +132,36 @@
     }
 
     /**
+     * Returns supported encryption algorithms for IKE SA proposal negotiation.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Set<Integer> getSupportedEncryptionAlgorithms() {
+        return getKeySet(SUPPORTED_ENCRYPTION_ALGO_TO_STR);
+    }
+
+    /**
+     * Returns supported integrity algorithms for IKE SA proposal negotiation.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Set<Integer> getSupportedIntegrityAlgorithms() {
+        return getKeySet(SUPPORTED_INTEGRITY_ALGO_TO_STR);
+    }
+
+    /**
+     * Returns supported pseudorandom functions for IKE SA proposal negotiation.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Set<Integer> getSupportedPseudorandomFunctions() {
+        return getKeySet(SUPPORTED_PRF_TO_STR);
+    }
+
+    /**
      * Gets all proposed Pseudorandom Functions
      *
      * @return A list of the IANA-defined IDs for the proposed Pseudorandom Functions
diff --git a/src/java/android/net/ipsec/ike/SaProposal.java b/src/java/android/net/ipsec/ike/SaProposal.java
index 2669d68..4cc3338 100644
--- a/src/java/android/net/ipsec/ike/SaProposal.java
+++ b/src/java/android/net/ipsec/ike/SaProposal.java
@@ -34,10 +34,12 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * SaProposal represents a proposed configuration to negotiate an IKE or Child SA.
@@ -91,7 +93,8 @@
      */
     public static final int ENCRYPTION_ALGORITHM_CHACHA20_POLY1305 = 28;
 
-    private static final SparseArray<String> SUPPORTED_ENCRYPTION_ALGO_TO_STR;
+    /** @hide */
+    protected static final SparseArray<String> SUPPORTED_ENCRYPTION_ALGO_TO_STR;
 
     static {
         SUPPORTED_ENCRYPTION_ALGO_TO_STR = new SparseArray<>();
@@ -141,7 +144,8 @@
     /** HMAC-SHA2-384 Pseudorandom Function. */
     public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7;
 
-    private static final SparseArray<String> SUPPORTED_PRF_TO_STR;
+    /** @hide */
+    protected static final SparseArray<String> SUPPORTED_PRF_TO_STR;
 
     static {
         SUPPORTED_PRF_TO_STR = new SparseArray<>();
@@ -177,7 +181,8 @@
     /** HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation. */
     public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14;
 
-    private static final SparseArray<String> SUPPORTED_INTEGRITY_ALGO_TO_STR;
+    /** @hide */
+    protected static final SparseArray<String> SUPPORTED_INTEGRITY_ALGO_TO_STR;
 
     static {
         SUPPORTED_INTEGRITY_ALGO_TO_STR = new SparseArray<>();
@@ -586,48 +591,24 @@
                 && Arrays.equals(mDhGroups, other.mDhGroups);
     }
 
-    /**
-     * Check if the provided algorithm is a supported encryption algorithm.
-     *
-     * @param algorithm IKE standard encryption algorithm id.
-     * @return true if the provided algorithm is a supported encryption algorithm.
-     * @hide
-     */
-    public static boolean isSupportedEncryptionAlgorithm(@EncryptionAlgorithm int algorithm) {
-        return SUPPORTED_ENCRYPTION_ALGO_TO_STR.get(algorithm) != null;
+    /** @hide */
+    protected static Set<Integer> getKeySet(SparseArray array) {
+        Set<Integer> result = new HashSet<>();
+        for (int i = 0; i < array.size(); i++) {
+            result.add(array.keyAt(i));
+        }
+
+        return result;
     }
 
     /**
-     * Check if the provided algorithm is a supported pseudorandom function.
+     * Returns supported DH groups for IKE and Child SA proposal negotiation.
      *
-     * @param algorithm IKE standard pseudorandom function id.
-     * @return true if the provided algorithm is a supported pseudorandom function.
      * @hide
      */
-    public static boolean isSupportedPseudorandomFunction(@PseudorandomFunction int algorithm) {
-        return SUPPORTED_PRF_TO_STR.get(algorithm) != null;
-    }
-
-    /**
-     * Check if the provided algorithm is a supported integrity algorithm.
-     *
-     * @param algorithm IKE standard integrity algorithm id.
-     * @return true if the provided algorithm is a supported integrity algorithm.
-     * @hide
-     */
-    public static boolean isSupportedIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
-        return SUPPORTED_INTEGRITY_ALGO_TO_STR.get(algorithm) != null;
-    }
-
-    /**
-     * Check if the provided group number is for a supported Diffie-Hellman Group.
-     *
-     * @param dhGroup IKE standard DH Group id.
-     * @return true if the provided number is for a supported Diffie-Hellman Group.
-     * @hide
-     */
-    public static boolean isSupportedDhGroup(@DhGroup int dhGroup) {
-        return SUPPORTED_DH_GROUP_TO_STR.get(dhGroup) != null;
+    @NonNull
+    public static Set<Integer> getSupportedDhGroups() {
+        return getKeySet(SUPPORTED_DH_GROUP_TO_STR);
     }
 
     /**
@@ -636,7 +617,7 @@
      * @hide
      */
     public static String getEncryptionAlgorithmString(int algorithm) {
-        if (isSupportedEncryptionAlgorithm(algorithm)) {
+        if (SUPPORTED_ENCRYPTION_ALGO_TO_STR.contains(algorithm)) {
             return SUPPORTED_ENCRYPTION_ALGO_TO_STR.get(algorithm);
         }
         return "ENC_Unknown_" + algorithm;
@@ -648,7 +629,7 @@
      * @hide
      */
     public static String getPseudorandomFunctionString(int algorithm) {
-        if (isSupportedPseudorandomFunction(algorithm)) {
+        if (SUPPORTED_PRF_TO_STR.contains(algorithm)) {
             return SUPPORTED_PRF_TO_STR.get(algorithm);
         }
         return "PRF_Unknown_" + algorithm;
@@ -660,7 +641,7 @@
      * @hide
      */
     public static String getIntegrityAlgorithmString(int algorithm) {
-        if (isSupportedIntegrityAlgorithm(algorithm)) {
+        if (SUPPORTED_PRF_TO_STR.contains(algorithm)) {
             return SUPPORTED_INTEGRITY_ALGO_TO_STR.get(algorithm);
         }
         return "AUTH_Unknown_" + algorithm;
@@ -672,7 +653,7 @@
      * @hide
      */
     public static String getDhGroupString(int dhGroup) {
-        if (isSupportedDhGroup(dhGroup)) {
+        if (SUPPORTED_DH_GROUP_TO_STR.contains(dhGroup)) {
             return SUPPORTED_DH_GROUP_TO_STR.get(dhGroup);
         }
         return "DH_Unknown_" + dhGroup;
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
index d0e55af..23220be 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
@@ -16,8 +16,10 @@
 
 package com.android.internal.net.ipsec.ike.crypto;
 
+import android.annotation.Nullable;
 import android.net.IpSecAlgorithm;
 import android.net.ipsec.ike.SaProposal;
+import android.util.SparseArray;
 
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
 
@@ -52,6 +54,26 @@
     protected static final int SALT_LEN_NOT_INCLUDED = 0;
     protected static final int BLOCK_SIZE_NOT_SPECIFIED = 0;
 
+    // Map IKE algorithm numbers to IPsec algorithm names
+    private static final SparseArray<String> IKE_ALGO_TO_IPSEC_ALGO;
+
+    static {
+        IKE_ALGO_TO_IPSEC_ALGO = new SparseArray<>();
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, IpSecAlgorithm.CRYPT_AES_CBC);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_CTR, IpSecAlgorithm.CRYPT_AES_CTR);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16, IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305,
+                IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305);
+    }
+
     private final boolean mIsAead;
     private final int mIvLen;
     private final int mBlockSize;
@@ -188,6 +210,19 @@
     }
 
     /**
+     * Returns the IPsec algorithm name defined in {@link IpSecAlgorithm} given the IKE algorithm
+     * ID.
+     *
+     * <p>Returns null if there is no corresponding IPsec algorithm given the IKE algorithm ID.
+     */
+    @Nullable
+    public static String getIpSecAlgorithmName(int ikeAlgoId) {
+        return IKE_ALGO_TO_IPSEC_ALGO.get(ikeAlgoId);
+    }
+
+    protected abstract IpSecAlgorithm buildIpSecAlgorithmWithKeyImpl(byte[] key);
+
+    /**
      * Build IpSecAlgorithm from this IkeCipher.
      *
      * <p>Build IpSecAlgorithm that represents the same encryption algorithm with this IkeCipher
@@ -196,7 +231,14 @@
      * @param key the encryption key in byte array.
      * @return the IpSecAlgorithm.
      */
-    public abstract IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key);
+    public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
+        validateKeyLenOrThrow(key);
+        if (getIpSecAlgorithmName(getAlgorithmId()) == null) {
+            throw new IllegalStateException(
+                    "Unsupported algorithm " + getAlgorithmId() + " in IPsec");
+        }
+        return buildIpSecAlgorithmWithKeyImpl(key);
+    }
 
     /**
      * Returns algorithm type as a String.
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
index 3a27752..a59e566 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
@@ -202,21 +202,7 @@
     }
 
     @Override
-    public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
-        validateKeyLenOrThrow(key);
-        switch (getAlgorithmId()) {
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8:
-                // Fall through
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12:
-                // Fall through
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16:
-                return new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, key, mChecksumLen * 8);
-            case SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, key, mChecksumLen * 8);
-            default:
-                throw new IllegalArgumentException(
-                        "Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
-        }
+    protected IpSecAlgorithm buildIpSecAlgorithmWithKeyImpl(byte[] key) {
+        return new IpSecAlgorithm(getIpSecAlgorithmName(getAlgorithmId()), key, mChecksumLen * 8);
     }
 }
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
index cb2aca7..16a5309 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
@@ -18,8 +18,10 @@
 
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
 
+import android.annotation.Nullable;
 import android.net.IpSecAlgorithm;
 import android.net.ipsec.ike.SaProposal;
+import android.util.SparseArray;
 
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
 
@@ -39,7 +41,23 @@
  * Exchange Protocol Version 2 (IKEv2)</a>
  */
 public class IkeMacIntegrity extends IkeMac {
-    // STOPSHIP: b/130190639 Catch unchecked exceptions, notify users and close the IKE session.
+    // Map IKE algorithm numbers to IPsec algorithm names
+    private static final SparseArray<String> IKE_ALGO_TO_IPSEC_ALGO;
+
+    static {
+        IKE_ALGO_TO_IPSEC_ALGO = new SparseArray<>();
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, IpSecAlgorithm.AUTH_HMAC_SHA1);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96, IpSecAlgorithm.AUTH_AES_XCBC);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, IpSecAlgorithm.AUTH_HMAC_SHA256);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, IpSecAlgorithm.AUTH_HMAC_SHA384);
+        IKE_ALGO_TO_IPSEC_ALGO.put(
+                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, IpSecAlgorithm.AUTH_HMAC_SHA512);
+    }
+
     private final int mChecksumLength;
 
     private IkeMacIntegrity(
@@ -149,6 +167,17 @@
     }
 
     /**
+     * Returns the IPsec algorithm name defined in {@link IpSecAlgorithm} given the IKE algorithm
+     * ID.
+     *
+     * <p>Returns null if there is no corresponding IPsec algorithm given the IKE algorithm ID.
+     */
+    @Nullable
+    public static String getIpSecAlgorithmName(int ikeAlgoId) {
+        return IKE_ALGO_TO_IPSEC_ALGO.get(ikeAlgoId);
+    }
+
+    /**
      * Build IpSecAlgorithm from this IkeMacIntegrity.
      *
      * <p>Build IpSecAlgorithm that represents the same integrity algorithm with this
@@ -165,25 +194,12 @@
                             + " Received key with length of : "
                             + key.length);
         }
-
-        switch (getAlgorithmId()) {
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96:
-                return new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96:
-                return new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_XCBC, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_HMAC_SHA256, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_HMAC_SHA384, key, mChecksumLength * 8);
-            case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256:
-                return new IpSecAlgorithm(
-                        IpSecAlgorithm.AUTH_HMAC_SHA512, key, mChecksumLength * 8);
-            default:
-                throw new IllegalArgumentException(
-                        "Unrecognized Integrity Algorithm ID: " + getAlgorithmId());
+        if (getIpSecAlgorithmName(getAlgorithmId()) == null) {
+            throw new IllegalStateException(
+                    "Unsupported algorithm " + getAlgorithmId() + " in IPsec");
         }
+        return new IpSecAlgorithm(
+                getIpSecAlgorithmName(getAlgorithmId()), key, mChecksumLength * 8);
     }
 
     /**
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
index f932e14..7fc18ed 100644
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
+++ b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
@@ -130,21 +130,8 @@
     }
 
     @Override
-    public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
-        validateKeyLenOrThrow(key);
-
-        switch (getAlgorithmId()) {
-            case SaProposal.ENCRYPTION_ALGORITHM_3DES:
-                // TODO: Consider supporting 3DES in IpSecTransform.
-                throw new UnsupportedOperationException("Do not support 3Des encryption.");
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC:
-                return new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, key);
-            case SaProposal.ENCRYPTION_ALGORITHM_AES_CTR:
-                return new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CTR, key);
-            default:
-                throw new IllegalArgumentException(
-                        "Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
-        }
+    protected IpSecAlgorithm buildIpSecAlgorithmWithKeyImpl(byte[] key) {
+        return new IpSecAlgorithm(getIpSecAlgorithmName(getAlgorithmId()), key);
     }
 
     private static byte[] concatenateByteArray(byte[] left, byte[] right) {
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
index 277d248..7f3529a 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
+++ b/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
@@ -1224,7 +1224,8 @@
 
         @Override
         protected boolean isSupportedTransformId(int id) {
-            return SaProposal.isSupportedEncryptionAlgorithm(id);
+            return IkeSaProposal.getSupportedEncryptionAlgorithms().contains(id)
+                    || ChildSaProposal.getSupportedEncryptionAlgorithms().contains(id);
         }
 
         @Override
@@ -1374,7 +1375,7 @@
 
         @Override
         protected boolean isSupportedTransformId(int id) {
-            return SaProposal.isSupportedPseudorandomFunction(id);
+            return IkeSaProposal.getSupportedPseudorandomFunctions().contains(id);
         }
 
         @Override
@@ -1455,7 +1456,8 @@
 
         @Override
         protected boolean isSupportedTransformId(int id) {
-            return SaProposal.isSupportedIntegrityAlgorithm(id);
+            return IkeSaProposal.getSupportedIntegrityAlgorithms().contains(id)
+                    || ChildSaProposal.getSupportedIntegrityAlgorithms().contains(id);
         }
 
         @Override
@@ -1536,7 +1538,7 @@
 
         @Override
         protected boolean isSupportedTransformId(int id) {
-            return SaProposal.isSupportedDhGroup(id);
+            return SaProposal.getSupportedDhGroups().contains(id);
         }
 
         @Override
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java b/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java
index 89d7343..1e91d5e 100644
--- a/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java
+++ b/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java
@@ -17,32 +17,58 @@
 package android.net.ipsec.ike;
 
 import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_1536_BIT_MODP;
 import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_3072_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_4096_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE;
 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
 import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED;
 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
 
+import android.net.IpSecAlgorithm;
 import android.os.PersistableBundle;
 
+import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
+import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
 import com.android.internal.net.ipsec.ike.message.IkePayload;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
+import com.android.internal.net.utils.build.SdkLevel;
 
 import org.junit.Test;
 
+import java.util.HashSet;
+import java.util.Set;
+
 public final class SaProposalTest {
     private final EncryptionTransform mEncryption3DesTransform;
     private final EncryptionTransform mEncryptionAesGcm8Transform;
@@ -52,6 +78,23 @@
     private final PrfTransform mPrfAes128XCbcTransform;
     private final DhGroupTransform mDhGroup1024Transform;
 
+    private static final Set<Integer> SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S;
+    private static final Set<Integer> SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S;
+
+    static {
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S = new HashSet<>();
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_CBC);
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_GCM_8);
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_GCM_12);
+        SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S.add(ENCRYPTION_ALGORITHM_AES_GCM_16);
+
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S = new HashSet<>();
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+        SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+    }
+
     public SaProposalTest() {
         mEncryption3DesTransform =
                 new EncryptionTransform(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED);
@@ -387,4 +430,112 @@
 
         assertTrue(respProposal.isNegotiatedFrom(reqProposal));
     }
+
+    @Test
+    public void testGetChildSupportedEncryptionAlgorithmsBeforeSdkS() {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        assertEquals(
+                SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S,
+                ChildSaProposal.getSupportedEncryptionAlgorithms());
+    }
+
+    @Test
+    public void testGetChildSupportedEncryptionAlgorithmsAtLeastSdkS() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        // It is not feasible to have a hard coded expected supported algorithm set because
+        // supported IPsec algorithms vary on different devices
+        for (int ikeAlgoId : ChildSaProposal.getSupportedEncryptionAlgorithms()) {
+            String ipSecAlgoName = IkeCipher.getIpSecAlgorithmName(ikeAlgoId);
+            assertTrue(IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName));
+        }
+
+        assertTrue(
+                ChildSaProposal.getSupportedEncryptionAlgorithms()
+                        .containsAll(SUPPORTED_IPSEC_ENCRYPTION_BEFORE_SDK_S));
+    }
+
+    @Test
+    public void testGetChildSupportedIntegrityAlgorithmsBeforeSdkS() {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        assertEquals(
+                SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S,
+                ChildSaProposal.getSupportedIntegrityAlgorithms());
+    }
+
+    @Test
+    public void testGetChildSupportedIntegrityAlgorithmsAtLeastSdkS() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        // It is not feasible to have a hard coded expected supported algorithm set because
+        // supported IPsec algorithms vary on different devices
+        for (int ikeAlgoId : ChildSaProposal.getSupportedIntegrityAlgorithms()) {
+            if (ikeAlgoId != INTEGRITY_ALGORITHM_NONE) {
+                String ipSecAlgoName = IkeMacIntegrity.getIpSecAlgorithmName(ikeAlgoId);
+                assertTrue(IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName));
+            }
+        }
+
+        assertTrue(
+                ChildSaProposal.getSupportedIntegrityAlgorithms()
+                        .containsAll(SUPPORTED_IPSEC_INTEGRITY_BEFORE_SDK_S));
+    }
+
+    @Test
+    public void testGetIkeSupportedEncryptionAlgorithms() {
+        HashSet<Integer> expectedSet = new HashSet<>();
+        expectedSet = new HashSet<>();
+        expectedSet.add(ENCRYPTION_ALGORITHM_3DES);
+        expectedSet.add(ENCRYPTION_ALGORITHM_AES_CBC);
+        expectedSet.add(ENCRYPTION_ALGORITHM_AES_CTR);
+        expectedSet.add(ENCRYPTION_ALGORITHM_AES_GCM_8);
+        expectedSet.add(ENCRYPTION_ALGORITHM_AES_GCM_12);
+        expectedSet.add(ENCRYPTION_ALGORITHM_AES_GCM_16);
+        expectedSet.add(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305);
+
+        assertEquals(expectedSet, IkeSaProposal.getSupportedEncryptionAlgorithms());
+    }
+
+    @Test
+    public void testGetIkeSupportedIntegrityAlgorithms() {
+        HashSet<Integer> expectedSet = new HashSet<>();
+        expectedSet = new HashSet<>();
+        expectedSet.add(INTEGRITY_ALGORITHM_NONE);
+        expectedSet.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+        expectedSet.add(INTEGRITY_ALGORITHM_AES_XCBC_96);
+        expectedSet.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+        expectedSet.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+        expectedSet.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+
+        assertEquals(expectedSet, IkeSaProposal.getSupportedIntegrityAlgorithms());
+    }
+
+    @Test
+    public void testGetIkeSupportedPrfs() {
+        HashSet<Integer> expectedSet = new HashSet<>();
+        expectedSet = new HashSet<>();
+        expectedSet.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
+        expectedSet.add(PSEUDORANDOM_FUNCTION_AES128_XCBC);
+        expectedSet.add(PSEUDORANDOM_FUNCTION_SHA2_256);
+        expectedSet.add(PSEUDORANDOM_FUNCTION_SHA2_384);
+        expectedSet.add(PSEUDORANDOM_FUNCTION_SHA2_512);
+
+        assertEquals(expectedSet, IkeSaProposal.getSupportedPseudorandomFunctions());
+    }
+
+    @Test
+    public void testGetSupportedDhGroups() {
+        HashSet<Integer> expectedSet = new HashSet<>();
+        expectedSet = new HashSet<>();
+        expectedSet.add(DH_GROUP_NONE);
+        expectedSet.add(DH_GROUP_1024_BIT_MODP);
+        expectedSet.add(DH_GROUP_1536_BIT_MODP);
+        expectedSet.add(DH_GROUP_2048_BIT_MODP);
+        expectedSet.add(DH_GROUP_3072_BIT_MODP);
+        expectedSet.add(DH_GROUP_4096_BIT_MODP);
+
+        assertEquals(expectedSet, IkeSaProposal.getSupportedDhGroups());
+    }
 }
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
index fc322bb..946d844 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -185,4 +186,27 @@
             }
         }
     }
+
+    @Test
+    public void testGetIpSecAlgorithmName() throws Exception {
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA1,
+                IkeMacIntegrity.getIpSecAlgorithmName(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96));
+        assertEquals(
+                IpSecAlgorithm.AUTH_AES_XCBC,
+                IkeMacIntegrity.getIpSecAlgorithmName(SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96));
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA256,
+                IkeMacIntegrity.getIpSecAlgorithmName(
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128));
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA384,
+                IkeMacIntegrity.getIpSecAlgorithmName(
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192));
+        assertEquals(
+                IpSecAlgorithm.AUTH_HMAC_SHA512,
+                IkeMacIntegrity.getIpSecAlgorithmName(
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256));
+        assertNull(IkeMacIntegrity.getIpSecAlgorithmName(SaProposal.INTEGRITY_ALGORITHM_NONE));
+    }
 }
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
index 9837ac7..15d0092 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -184,7 +185,7 @@
     }
 
     @Test
-    public void buildIpSecAlgorithmWithInvalidKey() throws Exception {
+    public void testBuildIpSecAlgorithmWithInvalidKey() throws Exception {
         byte[] encryptionKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP + "00");
 
         try {
@@ -195,4 +196,27 @@
 
         }
     }
+
+    @Test
+    public void testGetIpSecAlgorithmName() throws Exception {
+        assertEquals(
+                IpSecAlgorithm.CRYPT_AES_CBC,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_CBC));
+        assertEquals(
+                IpSecAlgorithm.CRYPT_AES_CTR,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_CTR));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16));
+        assertEquals(
+                IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305,
+                IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305));
+        assertNull(IkeCipher.getIpSecAlgorithmName(SaProposal.ENCRYPTION_ALGORITHM_3DES));
+    }
 }