Merge cherrypicks of ['googleplex-android-review.googlesource.com/40550193'] into security-aosp-26Q2-release.

Change-Id: Ieb2c1aba873d73c8db2a6a1a3b19b36c1fa6a604
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
index e805089..d2f2302 100644
--- a/telephony/common/com/google/android/mms/pdu/PduParser.java
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -1431,7 +1431,9 @@
 
                         if (index < PduContentTypes.contentTypes.length) {
                             byte[] type = (PduContentTypes.contentTypes[index]).getBytes();
-                            map.put(PduPart.P_TYPE, type);
+                            if (map != null) {
+                                map.put(PduPart.P_TYPE, type);
+                            }
                         } else {
                             //not support this type, ignore it.
                         }
@@ -1494,14 +1496,16 @@
                             (END_STRING_FLAG == firstValue)) {
                         //Text-String (extension-charset)
                         byte[] charsetStr = parseWapString(pduDataStream, TYPE_TEXT_STRING);
-                        try {
-                            int charsetInt = CharacterSets.getMibEnumValue(
-                                    new String(charsetStr));
-                            map.put(PduPart.P_CHARSET, charsetInt);
-                        } catch (UnsupportedEncodingException e) {
-                            // Not a well-known charset, use "*".
-                            Log.e(LOG_TAG, Arrays.toString(charsetStr), e);
-                            map.put(PduPart.P_CHARSET, CharacterSets.ANY_CHARSET);
+                        if (charsetStr != null && map != null) {
+                            try {
+                                int charsetInt = CharacterSets.getMibEnumValue(
+                                        new String(charsetStr));
+                                map.put(PduPart.P_CHARSET, charsetInt);
+                            } catch (UnsupportedEncodingException e) {
+                                // Not a well-known charset, use "*".
+                                Log.e(LOG_TAG, Arrays.toString(charsetStr), e);
+                                map.put(PduPart.P_CHARSET, CharacterSets.ANY_CHARSET);
+                            }
                         }
                     } else {
                         //Well-known-charset
@@ -1620,8 +1624,15 @@
         } else if (cur <= TEXT_MAX) {
             contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING);
         } else {
-            contentType =
-                (PduContentTypes.contentTypes[parseShortInteger(pduDataStream)]).getBytes();
+            // Parse the content type index from the stream (returns a value 0-127).
+            int index = parseShortInteger(pduDataStream);
+            // Ensure the index is within the bounds of the well-known content types table (0-82).
+            if (index < PduContentTypes.contentTypes.length) {
+                contentType = (PduContentTypes.contentTypes[index]).getBytes();
+            } else {
+                // Fallback to default "*/*" if the index is out of bounds to prevent AIOOBE crash.
+                contentType = (PduContentTypes.contentTypes[0]).getBytes();
+            }
         }
 
         return contentType;
diff --git a/tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java b/tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java
new file mode 100644
index 0000000..387e0b7
--- /dev/null
+++ b/tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2026 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.mms.pdu;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PduParserTest {
+
+    @Test
+    public void testParse_malformedHugeHeaderLength_doesNotOOM() {
+        byte[] pduData = new byte[] {
+            // Headers (Send-Req)
+            (byte) 0x8C, (byte) 0x80, // Message-Type: Send-Req
+            (byte) 0x98, (byte) '1', (byte) '2', (byte) '3', (byte) 0x00, // Transaction-ID: "123"
+            (byte) 0x8D, (byte) 0x90, // MMS-Version: 1.0
+            (byte) 0x89, (byte) 0x01, (byte) 0x81, // From: insert-address-token
+            (byte) 0x84, (byte) 0xA3, // Content-Type: multipart/mixed
+
+            // Body (Multipart)
+            (byte) 0x01, // Part count = 1
+            // Part 1
+            // Part Header Length: 0x7FFFFFFF
+            (byte) 0x87, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x7F,
+            (byte) 0x00, // Part Data Length: 0
+            (byte) 0x83, // Part Content-Type: text/plain
+        };
+
+        PduParser parser = new PduParser(pduData, false);
+        assertNull(parser.parse()); // Should return null instead of throwing OOM
+    }
+
+    @Test
+    @SmallTest
+    public void testParse_invalidContentTypeIndex_doesNotThrowAIOOBE() {
+        byte[] pduData = new byte[] {
+            // Headers (Send-Req)
+            (byte) 0x8C, (byte) 0x80, // Message-Type: Send-Req
+            (byte) 0x98, (byte) '1', (byte) '2', (byte) '3', (byte) 0x00, // Transaction-ID: "123"
+            (byte) 0x8D, (byte) 0x90, // MMS-Version: 1.0
+            (byte) 0x89, (byte) 0x01, (byte) 0x81, // From: insert-address-token
+            (byte) 0x84, (byte) 0xD3, // Content-Type: index 83 (invalid, max is 82)
+        };
+
+        PduParser parser = new PduParser(pduData, false);
+        try {
+            parser.parse();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            org.junit.Assert.fail("Should not throw ArrayIndexOutOfBoundsException");
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void testParse_elementDescriptorWithParams_doesNotThrowNPE() {
+        byte[] pduData = new byte[] {
+            // Headers (Send-Req)
+            (byte) 0x8C, (byte) 0x80, // Message-Type: Send-Req
+            (byte) 0x98, (byte) '1', (byte) '2', (byte) '3', (byte) 0x00, // Transaction-ID: "123"
+            (byte) 0x8D, (byte) 0x90, // MMS-Version: 1.0
+            (byte) 0x89, (byte) 0x01, (byte) 0x81, // From: insert-address-token
+            (byte) 0x84, (byte) 0xA3, // Content-Type: multipart/mixed
+
+            // ELEMENT_DESCRIPTOR (which passes null map)
+            (byte) 0xB2,
+            (byte) 0x03, // Value-length
+            (byte) 0xA3, // Media-type: multipart/mixed
+            (byte) 0x83, // Parameter: P_TYPE
+            (byte) 0x80, // Parameter value: index 0
+        };
+
+        PduParser parser = new PduParser(pduData, false);
+        try {
+            parser.parse();
+        } catch (NullPointerException e) {
+            org.junit.Assert.fail("Should not throw NullPointerException");
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void testParse_emptyCharset_doesNotThrowNPE() {
+        byte[] pduData = new byte[] {
+            // Headers (Send-Req)
+            (byte) 0x8C, (byte) 0x80, // Message-Type: Send-Req
+            (byte) 0x98, (byte) '1', (byte) '2', (byte) '3', (byte) 0x00, // Transaction-ID: "123"
+            (byte) 0x8D, (byte) 0x90, // MMS-Version: 1.0
+            (byte) 0x89, (byte) 0x01, (byte) 0x81, // From: insert-address-token
+            (byte) 0x84, // Content-Type
+            // Value for Content-Type (with parameters)
+            (byte) 0x03, // Value-length
+            (byte) 0xA3, // Media-type: multipart/mixed
+            (byte) 0x81, // Parameter: P_CHARSET
+            (byte) 0x00, // Parameter value: empty string
+        };
+
+        PduParser parser = new PduParser(pduData, false);
+        try {
+            parser.parse();
+        } catch (NullPointerException e) {
+            org.junit.Assert.fail("Should not throw NullPointerException");
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void testPduParserUnderflowOOM() {
+        // CONTENT_TYPE (0x84), LENGTH_QUOTE (0x1F), uintvar for Integer.MIN_VALUE,
+        // well-known type (0x83)
+        byte[] pdu = new byte[] {
+                (byte) 0x84,
+                (byte) 0x1F,
+                (byte) 0x88,
+                (byte) 0x80,
+                (byte) 0x80,
+                (byte) 0x80,
+                (byte) 0x00,
+                (byte) 0x83
+        };
+
+        try {
+            PduParser parser = new PduParser(pdu, false);
+            // This should not crash with OOM.
+            parser.parse();
+        } catch (OutOfMemoryError e) {
+            fail("Triggered OutOfMemoryError due to integer underflow!");
+        }
+    }
+}