Merge "Remove the GenerateRkpKey service"
diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
index e84aea1..b6ea54d 100644
--- a/apct-tests/perftests/packagemanager/Android.bp
+++ b/apct-tests/perftests/packagemanager/Android.bp
@@ -34,6 +34,55 @@
     test_suites: ["device-tests"],
 
     data: [
+        ":QueriesAll4",
+        ":QueriesAll31",
+        ":QueriesAll43",
+        ":QueriesAll15",
+        ":QueriesAll27",
+        ":QueriesAll39",
+        ":QueriesAll11",
+        ":QueriesAll23",
+        ":QueriesAll35",
+        ":QueriesAll47",
+        ":QueriesAll9",
+        ":QueriesAll19",
+        ":QueriesAll1",
+        ":QueriesAll5",
+        ":QueriesAll40",
+        ":QueriesAll20",
+        ":QueriesAll32",
+        ":QueriesAll48",
+        ":QueriesAll16",
+        ":QueriesAll28",
+        ":QueriesAll44",
+        ":QueriesAll12",
+        ":QueriesAll24",
+        ":QueriesAll36",
+        ":QueriesAll6",
+        ":QueriesAll2",
+        ":QueriesAll41",
+        ":QueriesAll21",
+        ":QueriesAll37",
+        ":QueriesAll49",
+        ":QueriesAll17",
+        ":QueriesAll29",
+        ":QueriesAll33",
+        ":QueriesAll45",
+        ":QueriesAll13",
+        ":QueriesAll25",
+        ":QueriesAll7",
+        ":QueriesAll3",
+        ":QueriesAll30",
+        ":QueriesAll42",
+        ":QueriesAll10",
+        ":QueriesAll26",
+        ":QueriesAll38",
+        ":QueriesAll18",
+        ":QueriesAll22",
+        ":QueriesAll34",
+        ":QueriesAll46",
+        ":QueriesAll14",
+        ":QueriesAll8",
         ":QueriesAll0",
         ":perfetto_artifacts",
     ],
diff --git a/boot/OWNERS b/boot/OWNERS
index 0e258d0..3fe1a41 100644
--- a/boot/OWNERS
+++ b/boot/OWNERS
@@ -2,5 +2,5 @@
 file:platform/build/soong:/OWNERS
 
 # art-team@ manages the boot image profiles for frameworks
-per-file boot-* = calin@google.com, yawanng@google.com, ngeoffray@google.com
-per-file preloaded-classes* = calin@google.com, yawanng@google.com, ngeoffray@google.com
+per-file boot-* = islamelbanna@google.com, ngeoffray@google.com, vmarko@google.com
+per-file preloaded-classes* = islamelbanna@google.com, ngeoffray@google.com, vmarko@google.com
diff --git a/config/OWNERS b/config/OWNERS
index 74813bc..6a5df76 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -1,8 +1,8 @@
 include /ZYGOTE_OWNERS
 
 # art-team@ manages the boot image profiles
-per-file boot-* = ngeoffray@google.com, vmarko@google.com
-per-file dirty-image-objects = ngeoffray@google.com, vmarko@google.com
-per-file generate-preloaded-classes.sh = ngeoffray@google.com, vmarko@google.com
-per-file preloaded-classes* = ngeoffray@google.com, vmarko@google.com
+per-file boot-* = islamelbanna@google.com, ngeoffray@google.com, vmarko@google.com
+per-file dirty-image-objects = ishcheikin@google.com, ngeoffray@google.com, vmarko@google.com
+per-file generate-preloaded-classes.sh = islamelbanna@google.com, ngeoffray@google.com, vmarko@google.com
+per-file preloaded-classes* = islamelbanna@google.com, ngeoffray@google.com, vmarko@google.com
 
diff --git a/core/api/current.txt b/core/api/current.txt
index 4c1594b..cf3938a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -41404,6 +41404,7 @@
     field public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool";
     field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
     field public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL = "data_rapid_notification_bool";
+    field public static final String KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG = "data_switch_validation_min_gap_long";
     field public static final String KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG = "data_switch_validation_timeout_long";
     field public static final String KEY_DATA_WARNING_NOTIFICATION_BOOL = "data_warning_notification_bool";
     field public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index d48d566..e6dad27 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -24,12 +24,12 @@
 import android.content.Context;
 import android.icu.text.DateFormatSymbols;
 import android.icu.text.DateTimePatternGenerator;
+import android.icu.util.ULocale;
 import android.os.Build;
 import android.provider.Settings;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.SpannedString;
-import android.text.TextUtils;
 
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -265,11 +265,13 @@
      * @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
      */
     public static String getBestDateTimePattern(Locale locale, String skeleton) {
-        DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(locale);
+        ULocale uLocale = ULocale.forLocale(locale);
+        DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(uLocale);
         boolean allowDuplicateFields = !CompatChanges.isChangeEnabled(
                 DISALLOW_DUPLICATE_FIELD_IN_SKELETON);
-        return dtpg.getBestPattern(skeleton, DateTimePatternGenerator.MATCH_NO_OPTIONS,
+        String pattern = dtpg.getBestPattern(skeleton, DateTimePatternGenerator.MATCH_NO_OPTIONS,
                 allowDuplicateFields);
+        return getCompatibleEnglishPattern(uLocale, pattern);
     }
 
     /**
@@ -303,10 +305,11 @@
      */
     @UnsupportedAppUsage
     public static String getTimeFormatString(Context context, int userHandle) {
-        DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(
-                context.getResources().getConfiguration().locale);
-        return is24HourFormat(context, userHandle) ? dtpg.getBestPattern("Hm")
+        ULocale uLocale = ULocale.forLocale(context.getResources().getConfiguration().locale);
+        DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(uLocale);
+        String pattern = is24HourFormat(context, userHandle) ? dtpg.getBestPattern("Hm")
             : dtpg.getBestPattern("hm");
+        return getCompatibleEnglishPattern(uLocale, pattern);
     }
 
     /**
@@ -713,4 +716,21 @@
     public static DateFormatSymbols getIcuDateFormatSymbols(Locale locale) {
         return new DateFormatSymbols(android.icu.util.GregorianCalendar.class, locale);
     }
+
+    /**
+     * See http://b/266731719. It mirrors the implementation in
+     * {@link libcore.icu.SimpleDateFormatData.DateTimeFormatStringGenerator#postProcessPattern}
+     */
+    private static String getCompatibleEnglishPattern(ULocale locale, String pattern) {
+        if (pattern == null || locale == null || !"en".equals(locale.getLanguage())) {
+            return pattern;
+        }
+
+        String region = locale.getCountry();
+        if (region != null && !region.isEmpty() && !"US".equals(region)) {
+            return pattern;
+        }
+
+        return pattern.replace('\u202f', ' ');
+    }
 }
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 3df09c2..1f0e95e 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -49,15 +49,18 @@
 import java.util.Locale;
 
 /**
- * This widget display an analogic clock with two hands for hours and
- * minutes.
+ * This widget displays an analogic clock with two hands for hours and minutes.
  *
  * @attr ref android.R.styleable#AnalogClock_dial
  * @attr ref android.R.styleable#AnalogClock_hand_hour
  * @attr ref android.R.styleable#AnalogClock_hand_minute
  * @attr ref android.R.styleable#AnalogClock_hand_second
  * @attr ref android.R.styleable#AnalogClock_timeZone
- * @deprecated This widget is no longer supported.
+ * @deprecated This widget is no longer supported; except for
+ * {@link android.widget.RemoteViews} use cases like
+ * <a href="https://developer.android.com/develop/ui/views/appwidgets/overview">
+ * app widgets</a>.
+ *
  */
 @RemoteView
 @Deprecated
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 8459330..212cc44 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -156,8 +156,8 @@
     @DisableCompatChanges({DateFormat.DISALLOW_DUPLICATE_FIELD_IN_SKELETON})
     public void testGetBestDateTimePattern_enableDuplicateField() {
         // en-US uses 12-hour format by default.
-        assertEquals("h:mm\u202fa", DateFormat.getBestDateTimePattern(Locale.US, "jmma"));
-        assertEquals("h:mm\u202fa", DateFormat.getBestDateTimePattern(Locale.US, "ahmma"));
+        assertEquals("h:mm a", DateFormat.getBestDateTimePattern(Locale.US, "jmma"));
+        assertEquals("h:mm a", DateFormat.getBestDateTimePattern(Locale.US, "ahmma"));
     }
 
     private static void assertIllegalArgumentException(Locale l, String skeleton) {
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index 39ed82ef..381c051 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -139,16 +139,16 @@
                 fixedTime, java.text.DateFormat.SHORT, java.text.DateFormat.FULL));
 
         final long hourDuration = 2 * 60 * 60 * 1000;
-        assertEquals("5:30:15\u202fAM Greenwich Mean Time", DateUtils.formatSameDayTime(
+        assertEquals("5:30:15 AM Greenwich Mean Time", DateUtils.formatSameDayTime(
                 fixedTime + hourDuration, fixedTime, java.text.DateFormat.FULL,
                 java.text.DateFormat.FULL));
-        assertEquals("5:30:15\u202fAM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
+        assertEquals("5:30:15 AM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
                 fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.DEFAULT));
-        assertEquals("5:30:15\u202fAM GMT", DateUtils.formatSameDayTime(fixedTime + hourDuration,
+        assertEquals("5:30:15 AM GMT", DateUtils.formatSameDayTime(fixedTime + hourDuration,
                 fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.LONG));
-        assertEquals("5:30:15\u202fAM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
+        assertEquals("5:30:15 AM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
                 fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.MEDIUM));
-        assertEquals("5:30\u202fAM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
+        assertEquals("5:30 AM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
                 fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.SHORT));
     }
 
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index 852edef..f0ed6ee 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
 xutan@google.com
 
 # Give submodule owners in shell resource approval
-per-file res*/*/*.xml = hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
index 926cfb3..deb7c6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
@@ -1,2 +1,3 @@
 # WM shell sub-module desktop owners
+atsjenk@google.com
 madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
index 0c2d5c4..ccbb9cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
@@ -1,2 +1,3 @@
 # WM shell sub-module freeform owners
+atsjenk@google.com
 madym@google.com
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 1c28c3d..64dfc3e 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -7,3 +7,4 @@
 madym@google.com
 hwwang@google.com
 chenghsiuchang@google.com
+atsjenk@google.com
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 60f7735..8f022ac 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -55,6 +55,10 @@
         // GCC false-positives on this warning, and since we -Werror that's
         // a problem
         "-Wno-free-nonheap-object",
+
+        // Do not de-optimise cold code paths in AFDO.
+        // Some code paths might be infrequently executed but critical to latency.
+        "-fno-profile-sample-accurate",
     ],
 
     include_dirs: [
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 23ee505..6e1fec2 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -12,16 +12,16 @@
       ]
     },
     {
-      "name": "GtsMediaTestCases",
+      "name": "WvtsDeviceTestCases",
       "options" : [
         {
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+          "include-filter": "com.google.android.media.wvts.WidevineGenericOpsTests"
         },
         {
-          "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
+          "include-filter": "com.google.android.media.wvts.WidevineH264PlaybackTests"
         }
       ],
       "file_patterns": ["(?i)drm|crypto"]
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 5b0c2a2..b878bcf5 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -43,6 +43,8 @@
 
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 
+#include <android-base/stringprintf.h>
+
 #include <binder/MemoryDealer.h>
 
 #include <cutils/compiler.h>
@@ -1099,7 +1101,8 @@
                     ALOGE("Could not create MediaCodec.BufferInfo.");
                     env->ExceptionClear();
                 }
-                jniThrowException(env, "java/lang/IllegalStateException", NULL);
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Fatal error: could not create MediaCodec.BufferInfo object");
                 return;
             }
 
@@ -1121,7 +1124,8 @@
                     ALOGE("Could not create CodecException object.");
                     env->ExceptionClear();
                 }
-                jniThrowException(env, "java/lang/IllegalStateException", NULL);
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Fatal error: could not create CodecException object");
                 return;
             }
 
@@ -1134,7 +1138,9 @@
             CHECK(msg->findMessage("format", &format));
 
             if (OK != ConvertMessageToMap(env, format, &obj)) {
-                jniThrowException(env, "java/lang/IllegalStateException", NULL);
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Fatal error: failed to convert format "
+                                  "from native to Java object");
                 return;
             }
 
@@ -1166,7 +1172,8 @@
 
     status_t err = ConvertMessageToMap(env, data, &obj);
     if (err != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Fatal error: failed to convert format from native to Java object");
         return;
     }
 
@@ -1187,7 +1194,8 @@
 
     status_t err = ConvertMessageToMap(env, data, &obj);
     if (err != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Fatal error: failed to convert format from native to Java object");
         return;
     }
 
@@ -1198,6 +1206,18 @@
     env->DeleteLocalRef(obj);
 }
 
+std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
+    if (mCodec == nullptr) {
+        return msg ?: "";
+    }
+    std::string prefix = "";
+    if (msg && msg[0] != '\0') {
+        prefix.append(msg);
+        prefix.append("\n");
+    }
+    return prefix + mCodec->getErrorLog().extract();
+}
+
 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatCallbackNotify:
@@ -1347,9 +1367,17 @@
     env->Throw(exception);
 }
 
+static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
+    if (codec == NULL) {
+        return msg ?: "codec is released already";
+    }
+    return codec->getExceptionMessage(msg);
+}
+
 static jint throwExceptionAsNecessary(
         JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
-        const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
+        const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
+        const sp<JMediaCodec> &codec = NULL) {
     switch (err) {
         case OK:
             return 0;
@@ -1364,23 +1392,38 @@
             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
 
         case INVALID_OPERATION:
-            jniThrowException(env, "java/lang/IllegalStateException", msg);
+            jniThrowException(
+                    env, "java/lang/IllegalStateException",
+                    GetExceptionMessage(codec, msg).c_str());
             return 0;
 
         case BAD_VALUE:
-            jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+            jniThrowException(
+                    env, "java/lang/IllegalArgumentException",
+                    GetExceptionMessage(codec, msg).c_str());
             return 0;
 
         default:
             if (isCryptoError(err)) {
-                throwCryptoException(env, err, msg, crypto);
+                throwCryptoException(
+                        env, err,
+                        GetExceptionMessage(codec, msg).c_str(),
+                        crypto);
                 return 0;
             }
-            throwCodecException(env, err, actionCode, msg);
+            throwCodecException(
+                    env, err, actionCode,
+                    GetExceptionMessage(codec, msg).c_str());
             return 0;
     }
 }
 
+static jint throwExceptionAsNecessary(
+        JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
+        int32_t actionCode = ACTION_CODE_FATAL) {
+    return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
+}
+
 static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
         JNIEnv *env,
         jobject thiz,
@@ -1388,13 +1431,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
@@ -1404,13 +1447,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->enableOnFrameRenderedListener(enabled);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_setCallback(
@@ -1420,13 +1463,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->setCallback(cb);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_configure(
@@ -1440,7 +1483,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1478,7 +1521,7 @@
 
     err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_setSurface(
@@ -1488,7 +1531,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1507,7 +1550,7 @@
     }
 
     status_t err = codec->setSurface(bufferProducer);
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
@@ -1611,7 +1654,7 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1625,7 +1668,7 @@
     }
     status_t err = codec->setInputSurface(persistentSurface);
     if (err != NO_ERROR) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 }
 
@@ -1635,7 +1678,7 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -1643,7 +1686,7 @@
     sp<IGraphicBufferProducer> bufferProducer;
     status_t err = codec->createInputSurface(&bufferProducer);
     if (err != NO_ERROR) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
         return NULL;
     }
 
@@ -1658,13 +1701,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->start();
 
-    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -1673,13 +1716,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->stop();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
@@ -1688,7 +1731,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1701,7 +1744,7 @@
         // trigger an IllegalStateException.
         err = UNKNOWN_ERROR;
     }
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
@@ -1710,13 +1753,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->flush();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_queueInputBuffer(
@@ -1732,7 +1775,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1742,7 +1785,8 @@
             index, offset, size, timestampUs, flags, &errorDetailMsg);
 
     throwExceptionAsNecessary(
-            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
 struct NativeCryptoInfo {
@@ -1766,7 +1810,9 @@
         } else if (jmode == gCryptoModes.AesCbc) {
             mMode = CryptoPlugin::kMode_AES_CBC;
         }  else {
-            throwExceptionAsNecessary(env, INVALID_OPERATION);
+            throwExceptionAsNecessary(
+                    env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                    base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
             return;
         }
 
@@ -1902,7 +1948,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1932,7 +1978,9 @@
     } else if (jmode == gCryptoModes.AesCbc) {
         mode = CryptoPlugin::kMode_AES_CBC;
     }  else {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
         return;
     }
 
@@ -2051,8 +2099,8 @@
     subSamples = NULL;
 
     throwExceptionAsNecessary(
-            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
-            codec->getCrypto());
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
 }
 
 static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
@@ -2394,14 +2442,16 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == nullptr || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     sp<AMessage> tunings;
     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
     if (err != OK) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(
+                env, err, ACTION_CODE_FATAL,
+                "error occurred while converting tunings from Java to native");
         return;
     }
 
@@ -2421,15 +2471,23 @@
         }
         env->MonitorExit(lock.get());
     } else {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                "Failed to grab lock for a LinearBlock object");
         return;
     }
 
     AString errorDetailMsg;
     if (codec->hasCryptoOrDescrambler()) {
         if (!memory) {
+            // It means there was an unexpected failure in extractMemoryFromContext above
             ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
-            throwExceptionAsNecessary(env, BAD_VALUE);
+            throwExceptionAsNecessary(
+                    env, BAD_VALUE, ACTION_CODE_FATAL,
+                    "Unexpected error: the input buffer is not compatible with "
+                    "the secure codec, and a fallback logic failed.\n"
+                    "Suggestion: please try including the secure codec when calling "
+                    "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
             return;
         }
         auto cryptoInfo =
@@ -2453,14 +2511,22 @@
         ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
     } else {
         if (!buffer) {
+            // It means there was an unexpected failure in extractBufferFromContext above
             ALOGI("queueLinearBlock: no C2Buffer found");
-            throwExceptionAsNecessary(env, BAD_VALUE);
+            throwExceptionAsNecessary(
+                    env, BAD_VALUE, ACTION_CODE_FATAL,
+                    "Unexpected error: the input buffer is not compatible with "
+                    "the non-secure codec, and a fallback logic failed.\n"
+                    "Suggestion: please do not include the secure codec when calling "
+                    "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
             return;
         }
         err = codec->queueBuffer(
                 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
     }
-    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
 static void android_media_MediaCodec_native_queueHardwareBuffer(
@@ -2471,14 +2537,16 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     sp<AMessage> tunings;
     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
     if (err != OK) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(
+                env, err, ACTION_CODE_FATAL,
+                "error occurred while converting tunings from Java to native");
         return;
     }
 
@@ -2503,7 +2571,9 @@
         ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
         native_handle_close(handle);
         native_handle_delete(handle);
-        throwExceptionAsNecessary(env, BAD_VALUE);
+        throwExceptionAsNecessary(
+                env, BAD_VALUE, ACTION_CODE_FATAL,
+                "HardwareBuffer not recognized");
         return;
     }
     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
@@ -2512,7 +2582,9 @@
     AString errorDetailMsg;
     err = codec->queueBuffer(
             index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
-    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
 static void android_media_MediaCodec_native_getOutputFrame(
@@ -2522,13 +2594,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->getOutputFrame(env, frame, index);
     if (err != OK) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 }
 
@@ -2539,7 +2611,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return -1;
     }
 
@@ -2550,7 +2622,7 @@
         return (jint) index;
     }
 
-    return throwExceptionAsNecessary(env, err);
+    return throwExceptionAsNecessary(env, err, codec);
 }
 
 static jint android_media_MediaCodec_dequeueOutputBuffer(
@@ -2560,7 +2632,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return 0;
     }
 
@@ -2572,7 +2644,7 @@
         return (jint) index;
     }
 
-    return throwExceptionAsNecessary(env, err);
+    return throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_releaseOutputBuffer(
@@ -2583,13 +2655,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
@@ -2598,13 +2670,13 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->signalEndOfInputStream();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static jobject android_media_MediaCodec_getFormatNative(
@@ -2614,7 +2686,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2625,7 +2697,7 @@
         return format;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2637,7 +2709,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2648,7 +2720,7 @@
         return format;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2660,7 +2732,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2673,7 +2745,7 @@
 
     // if we're out of memory, an exception was already thrown
     if (err != NO_MEMORY) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 
     return NULL;
@@ -2686,7 +2758,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2699,7 +2771,7 @@
 
     // if we're out of memory, an exception was already thrown
     if (err != NO_MEMORY) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 
     return NULL;
@@ -2712,7 +2784,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2725,7 +2797,7 @@
 
     // if we're out of memory, an exception was already thrown
     if (err != NO_MEMORY) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 
     return NULL;
@@ -2738,7 +2810,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2749,7 +2821,7 @@
         return name;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2761,7 +2833,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2772,7 +2844,7 @@
         return codecInfoObj;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2784,7 +2856,8 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          GetExceptionMessage(codec, NULL).c_str());
         return 0;
     }
 
@@ -2813,7 +2886,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -2824,7 +2897,7 @@
         err = codec->setParameters(params);
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_setVideoScalingMode(
@@ -2832,13 +2905,14 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          String8::format("Unrecognized mode: %d", mode));
         return;
     }
 
@@ -2850,7 +2924,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -2862,14 +2936,14 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
     jobject ret = NULL;
     status_t status = codec->querySupportedVendorParameters(env, &ret);
     if (status != OK) {
-        throwExceptionAsNecessary(env, status);
+        throwExceptionAsNecessary(env, status, codec);
     }
 
     return ret;
@@ -2880,7 +2954,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2897,13 +2971,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t status = codec->subscribeToVendorParameters(env, names);
     if (status != OK) {
-        throwExceptionAsNecessary(env, status);
+        throwExceptionAsNecessary(env, status, codec);
     }
     return;
 }
@@ -2913,13 +2987,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t status = codec->unsubscribeFromVendorParameters(env, names);
     if (status != OK) {
-        throwExceptionAsNecessary(env, status);
+        throwExceptionAsNecessary(env, status, codec);
     }
     return;
 }
@@ -3310,11 +3384,15 @@
         if (!context->mReadonlyMapping) {
             const C2BufferData data = buffer->data();
             if (data.type() != C2BufferData::LINEAR) {
-                throwExceptionAsNecessary(env, INVALID_OPERATION);
+                throwExceptionAsNecessary(
+                        env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                        "Underlying buffer is not a linear buffer");
                 return nullptr;
             }
             if (data.linearBlocks().size() != 1u) {
-                throwExceptionAsNecessary(env, INVALID_OPERATION);
+                throwExceptionAsNecessary(
+                        env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                        "Underlying buffer contains more than one block");
                 return nullptr;
             }
             C2ConstLinearBlock block = data.linearBlocks().front();
@@ -3362,7 +3440,9 @@
                 false,  // readOnly
                 true /* clearBuffer */);
     }
-    throwExceptionAsNecessary(env, INVALID_OPERATION);
+    throwExceptionAsNecessary(
+            env, INVALID_OPERATION, ACTION_CODE_FATAL,
+            "Underlying buffer is empty");
     return nullptr;
 }
 
@@ -3385,7 +3465,9 @@
         }
         const char *cstr = env->GetStringUTFChars(jstr, nullptr);
         if (cstr == nullptr) {
-            throwExceptionAsNecessary(env, BAD_VALUE);
+            throwExceptionAsNecessary(
+                    env, BAD_VALUE, ACTION_CODE_FATAL,
+                    "Error converting Java string to native");
             return;
         }
         names->emplace_back(cstr);
@@ -3437,6 +3519,7 @@
     }
     status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
     if (err != OK) {
+        // TODO: CodecErrorLog
         throwExceptionAsNecessary(env, err);
     }
     return isCompatible;
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 616c31b..fbaf64f 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -176,6 +176,8 @@
 
     const sp<ICrypto> &getCrypto() { return mCrypto; }
 
+    std::string getExceptionMessage(const char *msg) const;
+
 protected:
     virtual ~JMediaCodec();
 
diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h
index c753020..060abfd 100644
--- a/media/jni/android_media_MediaCodecLinearBlock.h
+++ b/media/jni/android_media_MediaCodecLinearBlock.h
@@ -44,12 +44,19 @@
 
     std::shared_ptr<C2Buffer> toC2Buffer(size_t offset, size_t size) const {
         if (mBuffer) {
+            // TODO: if returned C2Buffer is different from mBuffer, we should
+            // find a way to connect the life cycle between this C2Buffer and
+            // mBuffer.
             if (mBuffer->data().type() != C2BufferData::LINEAR) {
                 return nullptr;
             }
             C2ConstLinearBlock block = mBuffer->data().linearBlocks().front();
             if (offset == 0 && size == block.capacity()) {
-                return mBuffer;
+                // Let C2Buffer be new one to queue to MediaCodec. It will allow
+                // the related input slot to be released by onWorkDone from C2
+                // Component. Currently, the life cycle of mBuffer should be
+                // protected by different flows.
+                return std::make_shared<C2Buffer>(*mBuffer);
             }
 
             std::shared_ptr<C2Buffer> buffer =
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a7c2ddf..66682cc 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7238,6 +7238,7 @@
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HDMI);
     }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b25206d..7e48f68 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -3391,6 +3391,7 @@
          * consistency of the Ikev2VpnRunner fields.
          */
         public void onDefaultNetworkChanged(@NonNull Network network) {
+            mEventChanges.log("[UnderlyingNW] Default network changed to " + network);
             Log.d(TAG, "onDefaultNetworkChanged: " + network);
 
             // If there is a new default network brought up, cancel the retry task to prevent
@@ -3628,6 +3629,7 @@
                 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
                         .setTransportInfo(info)
                         .build();
+                mEventChanges.log("[VPNRunner] Update agent caps " + mNetworkCapabilities);
                 doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
             }
         }
@@ -3664,6 +3666,7 @@
 
         private void startIkeSession(@NonNull Network underlyingNetwork) {
             Log.d(TAG, "Start new IKE session on network " + underlyingNetwork);
+            mEventChanges.log("[IKE] Start IKE session over " + underlyingNetwork);
 
             try {
                 // Clear mInterface to prevent Ikev2VpnRunner being cleared when
@@ -3778,6 +3781,7 @@
         }
 
         public void onValidationStatus(int status) {
+            mEventChanges.log("[Validation] validation status " + status);
             if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
                 // No data stall now. Reset it.
                 mExecutor.execute(() -> {
@@ -3818,6 +3822,7 @@
          * consistency of the Ikev2VpnRunner fields.
          */
         public void onDefaultNetworkLost(@NonNull Network network) {
+            mEventChanges.log("[UnderlyingNW] Network lost " + network);
             // If the default network is torn down, there is no need to call
             // startOrMigrateIkeSession() since it will always check if there is an active network
             // can be used or not.
@@ -3936,6 +3941,8 @@
          * consistency of the Ikev2VpnRunner fields.
          */
         public void onSessionLost(int token, @Nullable Exception exception) {
+            mEventChanges.log("[IKE] Session lost on network " + mActiveNetwork
+                    + (null == exception ? "" : " reason " + exception.getMessage()));
             Log.d(TAG, "onSessionLost() called for token " + token);
 
             if (!isActiveToken(token)) {
@@ -4092,6 +4099,7 @@
          * consistency of the Ikev2VpnRunner fields.
          */
         private void disconnectVpnRunner() {
+            mEventChanges.log("[VPNRunner] Disconnect runner, underlying network" + mActiveNetwork);
             mActiveNetwork = null;
             mUnderlyingNetworkCapabilities = null;
             mUnderlyingLinkProperties = null;
diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
index b4bcd5b..5de1559 100644
--- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
+++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
@@ -61,7 +61,7 @@
     private static final String AVC_PREFIX = "type=" + AUDIT_AVC + " ";
 
     private static final Pattern EXECUTE_NATIVE_AUDIT_PATTERN =
-            Pattern.compile(".*\\bavc: granted \\{ execute(?:_no_trans|) \\} .*"
+            Pattern.compile(".*\\bavc: +granted +\\{ execute(?:_no_trans|) \\} .*"
                     + "\\bpath=(?:\"([^\" ]*)\"|([0-9A-F]+)) .*"
                     + "\\bscontext=u:r:untrusted_app(?:_25|_27)?:.*"
                     + "\\btcontext=u:object_r:app_data_file:.*"
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
index 2d3ede0..f586126 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
@@ -70,12 +70,14 @@
                 Log.i(TAG, "Operation cancelled for client " + mCallback.hashCode());
                 wrapCallback(mCallback::onCancel);
             } else if (e instanceof RkpProxyException) {
-                Log.e(TAG, "RKP error fetching key for client " + mCallback.hashCode(), e);
+                Log.e(TAG, "RKP error fetching key for client " + mCallback.hashCode() + ": "
+                        + e.getMessage());
                 RkpProxyException rkpException = (RkpProxyException) e;
                 wrapCallback(() -> mCallback.onError(toGetKeyError(rkpException),
                         e.getMessage()));
             } else {
-                Log.e(TAG, "Error fetching key for client " + mCallback.hashCode(), e);
+                Log.e(TAG, "Unknown error fetching key for client " + mCallback.hashCode() + ": "
+                        + e.getMessage());
                 wrapCallback(() -> mCallback.onError(IGetKeyCallback.ErrorCode.ERROR_UNKNOWN,
                         e.getMessage()));
             }
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index b4b8cf9..3d8b293 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -147,7 +147,6 @@
 import android.security.metrics.KeystoreAtom;
 import android.security.metrics.KeystoreAtomPayload;
 import android.security.metrics.RkpErrorStats;
-import android.security.metrics.RkpPoolStats;
 import android.security.metrics.StorageStats;
 import android.stats.storage.StorageEnums;
 import android.telephony.ModemActivityInfo;
@@ -714,7 +713,6 @@
                             return pullInstalledIncrementalPackagesLocked(atomTag, data);
                         }
                     case FrameworkStatsLog.KEYSTORE2_STORAGE_STATS:
-                    case FrameworkStatsLog.RKP_POOL_STATS:
                     case FrameworkStatsLog.KEYSTORE2_KEY_CREATION_WITH_GENERAL_INFO:
                     case FrameworkStatsLog.KEYSTORE2_KEY_CREATION_WITH_AUTH_INFO:
                     case FrameworkStatsLog.KEYSTORE2_KEY_CREATION_WITH_PURPOSE_AND_MODES_INFO:
@@ -918,7 +916,6 @@
         registerSettingsStats();
         registerInstalledIncrementalPackages();
         registerKeystoreStorageStats();
-        registerRkpPoolStats();
         registerKeystoreKeyCreationWithGeneralInfo();
         registerKeystoreKeyCreationWithAuthInfo();
         registerKeystoreKeyCreationWithPurposeModesInfo();
@@ -4137,14 +4134,6 @@
                 mStatsCallbackImpl);
     }
 
-    private void registerRkpPoolStats() {
-        mStatsManager.setPullAtomCallback(
-                FrameworkStatsLog.RKP_POOL_STATS,
-                null, // use default PullAtomMetadata values,
-                DIRECT_EXECUTOR,
-                mStatsCallbackImpl);
-    }
-
     private void registerKeystoreKeyCreationWithGeneralInfo() {
         mStatsManager.setPullAtomCallback(
                 FrameworkStatsLog.KEYSTORE2_KEY_CREATION_WITH_GENERAL_INFO,
@@ -4252,19 +4241,6 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    int parseRkpPoolStats(KeystoreAtom[] atoms, List<StatsEvent> pulledData) {
-        for (KeystoreAtom atomWrapper : atoms) {
-            if (atomWrapper.payload.getTag() != KeystoreAtomPayload.rkpPoolStats) {
-                return StatsManager.PULL_SKIP;
-            }
-            RkpPoolStats atom = atomWrapper.payload.getRkpPoolStats();
-            pulledData.add(FrameworkStatsLog.buildStatsEvent(
-                    FrameworkStatsLog.RKP_POOL_STATS, atom.security_level, atom.expiring,
-                    atom.unassigned, atom.attested, atom.total));
-        }
-        return StatsManager.PULL_SUCCESS;
-    }
-
     int parseKeystoreKeyCreationWithGeneralInfo(KeystoreAtom[] atoms, List<StatsEvent> pulledData) {
         for (KeystoreAtom atomWrapper : atoms) {
             if (atomWrapper.payload.getTag()
@@ -4397,8 +4373,6 @@
             switch (atomTag) {
                 case FrameworkStatsLog.KEYSTORE2_STORAGE_STATS:
                     return parseKeystoreStorageStats(atoms, pulledData);
-                case FrameworkStatsLog.RKP_POOL_STATS:
-                    return parseRkpPoolStats(atoms, pulledData);
                 case FrameworkStatsLog.KEYSTORE2_KEY_CREATION_WITH_GENERAL_INFO:
                     return parseKeystoreKeyCreationWithGeneralInfo(atoms, pulledData);
                 case FrameworkStatsLog.KEYSTORE2_KEY_CREATION_WITH_AUTH_INFO:
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 17780af..329849b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4884,11 +4884,32 @@
      * The max acceptable value of this config is 24 hours.
      *
      * @hide
+     * @deprecated Use {@link #KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG} instead.
      */
+    @Deprecated
     public static final String KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG =
             "data_switch_validation_min_gap_long";
 
     /**
+     * Data switch validation minimal interval, in milliseconds.
+     *
+     * If a connection to the default (Internet) PDN for the current subscription is validated on
+     * a given operator within a given tracking area, re-validations to that matching operator will
+     * be skipped if they would occur within the specified interval. Instead, the connection will
+     * automatically considered validated.
+     *
+     * If the network was validated within the interval but the latest validation result was false,
+     * the validation will not be skipped. If not set or set to 0, validation will not be skipped.
+     *
+     * The valid range of value is between 0 millisecond and 24 hours, inclusive in both sides. The
+     * default value is 24 hours.
+     *
+     * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED
+     */
+    public static final String KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG =
+            KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG;
+
+    /**
      * A boolean property indicating whether this subscription should be managed as an opportunistic
      * subscription.
      *
@@ -9335,7 +9356,8 @@
         sDefaults.putInt(KEY_GBA_UA_TLS_CIPHER_SUITE_INT, TlsParams.TLS_NULL_WITH_NULL_NULL);
 
         sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
-        sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1));
+        sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG,
+                TimeUnit.DAYS.toMillis(1));
         sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY,
                 new String[0]);
         sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] {
diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
index 5430dee..afa4ff8 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
@@ -84,7 +84,7 @@
     // avoid flakiness we run these tests multiple times, allowing progressively longer between
     // code loading and checking the logs on each try.)
     private static final int AUDIT_LOG_RETRIES = 10;
-    private static final int RETRY_DELAY_MS = 2_000;
+    private static final int RETRY_DELAY_MS = 500;
 
     private static Context sContext;
     private static int sMyUid;
@@ -245,7 +245,7 @@
                 "/DynamicCodeLoggerNativeExecutable", privateCopyFile);
 
         EventLog.writeEvent(EventLog.getTagCode("auditd"),
-                "type=1400 avc: granted { execute_no_trans } "
+                "type=1400 avc:  granted  { execute_no_trans } "
                         + "path=\"" + privateCopyFile + "\" "
                         + "scontext=u:r:untrusted_app: "
                         + "tcontext=u:object_r:app_data_file: "
diff --git a/tests/OdmApps/Android.bp b/tests/OdmApps/Android.bp
index 5f03aa2..a5c6d65 100644
--- a/tests/OdmApps/Android.bp
+++ b/tests/OdmApps/Android.bp
@@ -28,5 +28,6 @@
     test_suites: ["device-tests"],
     data: [
         ":TestOdmApp",
+        ":TestOdmPrivApp",
     ],
 }