Merge "Camera: add default secure camera size key" into sc-dev
diff --git a/METADATA b/METADATA
index 1fbda08..aabda36 100644
--- a/METADATA
+++ b/METADATA
@@ -2,6 +2,22 @@
 #     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
 #     DEPENDING ON IT IN YOUR PROJECT. ***
 third_party {
-  # would be NOTICE save for drm/mediadrm/plugins/clearkey/hidl/
+  # would be NOTICE save for Widevine Master License Agreement in:
+  #   drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
+  #   drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
+  #   drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
+  #   drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto
+  #   drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
+  # and patent disclaimers in:
+  #   media/codec2/components/aac/patent_disclaimer.txt
+  #   media/codec2/components/amr_nb_wb/patent_disclaimer.txt
+  #   media/codec2/components/mp3/patent_disclaimer.txt
+  #   media/codec2/components/mpeg4_h263/patent_disclaimer.txt
+  #   media/codecs/amrnb/patent_disclaimer.txt
+  #   media/codecs/amrwb/dec/patent_disclaimer.txt
+  #   media/codecs/amrwb/enc/patent_disclaimer.txt
+  #   media/codecs/m4v_h263/patent_disclaimer.txt
+  #   media/codecs/mp3dec/patent_disclaimer.txt
+  #   media/libstagefright/codecs/aacenc/patent_disclaimer.txt
   license_type: BY_EXCEPTION_ONLY
 }
diff --git a/MainlineFiles.cfg b/MainlineFiles.cfg
index 37d714c..f694a41 100644
--- a/MainlineFiles.cfg
+++ b/MainlineFiles.cfg
@@ -24,11 +24,4 @@
 media/codec2/components/
 media/codecs/
 media/extractors/
-media/libstagefright/codecs/amrnb/
-media/libstagefright/codecs/amrwb/
-media/libstagefright/codecs/amrwbenc/
-media/libstagefright/codecs/common/
-media/libstagefright/codecs/flac/
-media/libstagefright/codecs/m4v_h263/
-media/libstagefright/codecs/mp3dec/
 media/libstagefright/mpeg2ts
diff --git a/apex/TEST_MAPPING b/apex/TEST_MAPPING
index 09c46d6..4b7c019 100644
--- a/apex/TEST_MAPPING
+++ b/apex/TEST_MAPPING
@@ -16,7 +16,7 @@
           "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
         },
         {
-          "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
+          "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
         }
       ]
     }
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
index aa8a7d8..3642898 100644
--- a/drm/TEST_MAPPING
+++ b/drm/TEST_MAPPING
@@ -11,7 +11,7 @@
           "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
         },
         {
-          "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
+          "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
         }
       ]
     }
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index b49ec75..b042c27 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -64,6 +64,7 @@
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
         "android.hardware.drm@1.2",
+        "android.hardware.drm@1.4",
     ],
 
     cflags: [
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 18772e0..9d39f83 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -28,6 +28,7 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 #include <mediadrm/CryptoHal.h>
+#include <mediadrm/DrmUtils.h>
 
 using drm::V1_0::BufferType;
 using drm::V1_0::DestinationBuffer;
@@ -39,6 +40,7 @@
 using drm::V1_0::Status;
 using drm::V1_0::SubSample;
 
+using ::android::DrmUtils::toStatusT;
 using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_memory;
@@ -53,42 +55,6 @@
 
 namespace android {
 
-static status_t toStatusT(Status status) {
-    switch (status) {
-    case Status::OK:
-        return OK;
-    case Status::ERROR_DRM_NO_LICENSE:
-        return ERROR_DRM_NO_LICENSE;
-    case Status::ERROR_DRM_LICENSE_EXPIRED:
-        return ERROR_DRM_LICENSE_EXPIRED;
-    case Status::ERROR_DRM_RESOURCE_BUSY:
-        return ERROR_DRM_RESOURCE_BUSY;
-    case Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
-        return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
-    case Status::ERROR_DRM_SESSION_NOT_OPENED:
-        return ERROR_DRM_SESSION_NOT_OPENED;
-    case Status::ERROR_DRM_CANNOT_HANDLE:
-        return ERROR_DRM_CANNOT_HANDLE;
-    case Status::ERROR_DRM_DECRYPT:
-        return ERROR_DRM_DECRYPT;
-    default:
-        return UNKNOWN_ERROR;
-    }
-}
-
-static status_t toStatusT_1_2(Status_V1_2 status) {
-    switch (status) {
-    case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE:
-        return ERROR_DRM_SESSION_LOST_STATE;;
-    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
-        return ERROR_DRM_FRAME_TOO_LARGE;
-    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
-        return ERROR_DRM_INSUFFICIENT_SECURITY;
-    default:
-        return toStatusT(static_cast<Status>(status));
-    }
-}
-
 static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
     hidl_vec<uint8_t> vec;
     vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
@@ -384,7 +350,7 @@
                         bytesWritten = hBytesWritten;
                         *errorDetailMsg = toString8(hDetailedError);
                     }
-                    err = toStatusT_1_2(status);
+                    err = toStatusT(status);
                 }
             );
     } else {
@@ -427,4 +393,8 @@
     return toStatusT(mPlugin->setMediaDrmSession(toHidlVec(sessionId)));
 }
 
+status_t CryptoHal::getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const {
+    Mutex::Autolock autoLock(mLock);
+    return DrmUtils::GetLogMessages<drm::V1_4::ICryptoPlugin>(mPlugin, logs);
+}
 }  // namespace android
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 501471c..f8f2bc6 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -55,6 +55,7 @@
 using drm::V1_1::SecurityLevel;
 using drm::V1_2::KeySetId;
 using drm::V1_2::KeyStatusType;
+using ::android::DrmUtils::toStatusT;
 using ::android::hardware::drm::V1_1::DrmMetricGroup;
 using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_string;
@@ -235,58 +236,6 @@
     return keySetIds;
 }
 
-static status_t toStatusT(Status status) {
-    switch (status) {
-    case Status::OK:
-        return OK;
-        break;
-    case Status::ERROR_DRM_NO_LICENSE:
-        return ERROR_DRM_NO_LICENSE;
-        break;
-    case Status::ERROR_DRM_LICENSE_EXPIRED:
-        return ERROR_DRM_LICENSE_EXPIRED;
-        break;
-    case Status::ERROR_DRM_SESSION_NOT_OPENED:
-        return ERROR_DRM_SESSION_NOT_OPENED;
-        break;
-    case Status::ERROR_DRM_CANNOT_HANDLE:
-        return ERROR_DRM_CANNOT_HANDLE;
-        break;
-    case Status::ERROR_DRM_INVALID_STATE:
-        return ERROR_DRM_INVALID_STATE;
-        break;
-    case Status::BAD_VALUE:
-        return BAD_VALUE;
-        break;
-    case Status::ERROR_DRM_NOT_PROVISIONED:
-        return ERROR_DRM_NOT_PROVISIONED;
-        break;
-    case Status::ERROR_DRM_RESOURCE_BUSY:
-        return ERROR_DRM_RESOURCE_BUSY;
-        break;
-    case Status::ERROR_DRM_DEVICE_REVOKED:
-        return ERROR_DRM_DEVICE_REVOKED;
-        break;
-    case Status::ERROR_DRM_UNKNOWN:
-    default:
-        return ERROR_DRM_UNKNOWN;
-        break;
-    }
-}
-
-static status_t toStatusT_1_2(Status_V1_2 status) {
-    switch (status) {
-    case Status_V1_2::ERROR_DRM_RESOURCE_CONTENTION:
-        return ERROR_DRM_RESOURCE_CONTENTION;
-    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
-        return ERROR_DRM_FRAME_TOO_LARGE;
-    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
-        return ERROR_DRM_INSUFFICIENT_SECURITY;
-    default:
-        return toStatusT(static_cast<Status>(status));
-    }
-}
-
 Mutex DrmHal::mLock;
 
 struct DrmHal::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
@@ -825,7 +774,7 @@
                         defaultUrl = toString8(hDefaultUrl);
                         *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
                     }
-                    err = toStatusT_1_2(status);
+                    err = toStatusT(status);
                 });
     } else if (mPluginV1_1 != NULL) {
         hResult = mPluginV1_1->getKeyRequest_1_1(
@@ -947,7 +896,7 @@
                         request = toVector(hRequest);
                         defaultUrl = toString8(hDefaultUrl);
                     }
-                    err = toStatusT_1_2(status);
+                    err = toStatusT(status);
                 }
             );
     } else {
@@ -1119,7 +1068,7 @@
                         *connected = toHdcpLevel(hConnected);
                         *max = toHdcpLevel(hMax);
                     }
-                    err = toStatusT_1_2(status);
+                    err = toStatusT(status);
                 });
     } else if (mPluginV1_1 != NULL) {
         hResult = mPluginV1_1->getHdcpLevels(
@@ -1596,4 +1545,9 @@
     return toStatusT(err);
 }
 
+status_t DrmHal::getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const {
+    Mutex::Autolock autoLock(mLock);
+    return DrmUtils::GetLogMessages<drm::V1_4::IDrmPlugin>(mPlugin, logs);
+}
+
 }  // namespace android
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index d85fa61..82eadd9 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -177,5 +177,93 @@
     return plugins;
 }
 
+status_t toStatusT_1_4(::V1_4::Status status) {
+    switch (status) {
+    case ::V1_4::Status::OK:
+        return OK;
+    case ::V1_4::Status::BAD_VALUE:
+        return BAD_VALUE;
+    case ::V1_4::Status::ERROR_DRM_CANNOT_HANDLE:
+        return ERROR_DRM_CANNOT_HANDLE;
+    case ::V1_4::Status::ERROR_DRM_DECRYPT:
+        return ERROR_DRM_DECRYPT;
+    case ::V1_4::Status::ERROR_DRM_DEVICE_REVOKED:
+        return ERROR_DRM_DEVICE_REVOKED;
+    case ::V1_4::Status::ERROR_DRM_FRAME_TOO_LARGE:
+        return ERROR_DRM_FRAME_TOO_LARGE;
+    case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+        return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
+    case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
+        return ERROR_DRM_INSUFFICIENT_SECURITY;
+    case ::V1_4::Status::ERROR_DRM_INVALID_STATE:
+        return ERROR_DRM_INVALID_STATE;
+    case ::V1_4::Status::ERROR_DRM_LICENSE_EXPIRED:
+        return ERROR_DRM_LICENSE_EXPIRED;
+    case ::V1_4::Status::ERROR_DRM_NO_LICENSE:
+        return ERROR_DRM_NO_LICENSE;
+    case ::V1_4::Status::ERROR_DRM_NOT_PROVISIONED:
+        return ERROR_DRM_NOT_PROVISIONED;
+    case ::V1_4::Status::ERROR_DRM_RESOURCE_BUSY:
+        return ERROR_DRM_RESOURCE_BUSY;
+    case ::V1_4::Status::ERROR_DRM_RESOURCE_CONTENTION:
+        return ERROR_DRM_RESOURCE_CONTENTION;
+    case ::V1_4::Status::ERROR_DRM_SESSION_LOST_STATE:
+        return ERROR_DRM_SESSION_LOST_STATE;
+    case ::V1_4::Status::ERROR_DRM_SESSION_NOT_OPENED:
+        return ERROR_DRM_SESSION_NOT_OPENED;
+
+    // New in S / drm@1.4:
+    case ::V1_4::Status::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
+        return ERROR_DRM_ZERO_SUBSAMPLES;
+    case ::V1_4::Status::CRYPTO_LIBRARY_ERROR:
+        return ERROR_DRM_CRYPTO_LIBRARY;
+    case ::V1_4::Status::GENERAL_OEM_ERROR:
+        return ERROR_DRM_GENERIC_OEM;
+    case ::V1_4::Status::GENERAL_PLUGIN_ERROR:
+        return ERROR_DRM_GENERIC_PLUGIN;
+    case ::V1_4::Status::INIT_DATA_INVALID:
+        return ERROR_DRM_INIT_DATA;
+    case ::V1_4::Status::KEY_NOT_LOADED:
+        return ERROR_DRM_KEY_NOT_LOADED;
+    case ::V1_4::Status::LICENSE_PARSE_ERROR:
+        return ERROR_DRM_LICENSE_PARSE;
+    case ::V1_4::Status::LICENSE_POLICY_ERROR:
+        return ERROR_DRM_LICENSE_POLICY;
+    case ::V1_4::Status::LICENSE_RELEASE_ERROR:
+        return ERROR_DRM_LICENSE_RELEASE;
+    case ::V1_4::Status::LICENSE_REQUEST_REJECTED:
+        return ERROR_DRM_LICENSE_REQUEST_REJECTED;
+    case ::V1_4::Status::LICENSE_RESTORE_ERROR:
+        return ERROR_DRM_LICENSE_RESTORE;
+    case ::V1_4::Status::LICENSE_STATE_ERROR:
+        return ERROR_DRM_LICENSE_STATE;
+    case ::V1_4::Status::MALFORMED_CERTIFICATE:
+        return ERROR_DRM_CERTIFICATE_MALFORMED;
+    case ::V1_4::Status::MEDIA_FRAMEWORK_ERROR:
+        return ERROR_DRM_MEDIA_FRAMEWORK;
+    case ::V1_4::Status::MISSING_CERTIFICATE:
+        return ERROR_DRM_CERTIFICATE_MISSING;
+    case ::V1_4::Status::PROVISIONING_CERTIFICATE_ERROR:
+        return ERROR_DRM_PROVISIONING_CERTIFICATE;
+    case ::V1_4::Status::PROVISIONING_CONFIGURATION_ERROR:
+        return ERROR_DRM_PROVISIONING_CONFIG;
+    case ::V1_4::Status::PROVISIONING_PARSE_ERROR:
+        return ERROR_DRM_PROVISIONING_PARSE;
+    case ::V1_4::Status::RETRYABLE_PROVISIONING_ERROR:
+        return ERROR_DRM_PROVISIONING_RETRY;
+    case ::V1_4::Status::SECURE_STOP_RELEASE_ERROR:
+        return ERROR_DRM_SECURE_STOP_RELEASE;
+    case ::V1_4::Status::STORAGE_READ_FAILURE:
+        return ERROR_DRM_STORAGE_READ;
+    case ::V1_4::Status::STORAGE_WRITE_FAILURE:
+        return ERROR_DRM_STORAGE_WRITE;
+
+    case ::V1_4::Status::ERROR_DRM_UNKNOWN:
+    default:
+        return ERROR_DRM_UNKNOWN;
+    }
+    return ERROR_DRM_UNKNOWN;
+}
+
 }  // namespace DrmUtils
 }  // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index c9fda67..5fd39e6 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -22,6 +22,7 @@
 #include <android/hardware/drm/1.0/ICryptoPlugin.h>
 #include <android/hardware/drm/1.1/ICryptoFactory.h>
 #include <android/hardware/drm/1.2/ICryptoPlugin.h>
+#include <android/hardware/drm/1.4/ICryptoPlugin.h>
 
 #include <mediadrm/ICrypto.h>
 #include <utils/KeyedVector.h>
@@ -71,6 +72,8 @@
     }
     virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
 
+    virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
+
 private:
     mutable Mutex mLock;
 
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index 2fd4d81..a0aac30 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -26,6 +26,7 @@
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmPluginListener.h>
 #include <android/hardware/drm/1.4/IDrmPlugin.h>
+#include <android/hardware/drm/1.4/types.h>
 
 #include <media/drm/DrmAPI.h>
 #include <mediadrm/DrmMetrics.h>
@@ -188,6 +189,8 @@
             Vector<uint8_t> const &sessionId,
             const char *playbackId);
 
+    virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
+
     // Methods of IDrmPluginListener
     Return<void> sendEvent(EventType eventType,
             const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
diff --git a/drm/libmediadrm/include/mediadrm/IDrm.h b/drm/libmediadrm/include/mediadrm/IDrm.h
index ed71eee..b5bc73d 100644
--- a/drm/libmediadrm/include/mediadrm/IDrm.h
+++ b/drm/libmediadrm/include/mediadrm/IDrm.h
@@ -24,6 +24,15 @@
 #define ANDROID_IDRM_H_
 
 namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_4 {
+struct LogMessage;
+}  // namespace V1_4
+}  // namespace drm
+}  // namespace hardware
+
+namespace drm = ::android::hardware::drm;
 
 struct AString;
 
@@ -153,9 +162,12 @@
             DrmPlugin::SecurityLevel securityLevel) const = 0;
 
     virtual status_t setPlaybackId(
+
             Vector<uint8_t> const &sessionId,
             const char *playbackId) = 0;
 
+    virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const = 0;
+
 protected:
     IDrm() {}
 
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index 20b3fe9..10b7207 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -19,11 +19,18 @@
 
 #include <android/hardware/drm/1.0/ICryptoFactory.h>
 #include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.4/IDrmPlugin.h>
+#include <android/hardware/drm/1.4/types.h>
+#include <media/stagefright/MediaErrors.h>
 #include <utils/Errors.h>  // for status_t
+#include <utils/Vector.h>
 #include <utils/StrongPointer.h>
 #include <vector>
 
+
 using namespace ::android::hardware::drm;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
 
 namespace android {
 
@@ -91,8 +98,46 @@
 std::vector<sp<::V1_0::ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16],
                                                          const void *initData, size_t initDataSize);
 
+status_t toStatusT_1_4(::V1_4::Status status);
+
+template<typename S>
+inline status_t toStatusT(S status) {
+    auto err = static_cast<::V1_4::Status>(status);
+    return toStatusT_1_4(err);
+}
+
+template<typename T>
+inline status_t toStatusT(const android::hardware::Return<T> &status) {
+    auto t = static_cast<T>(status);
+    auto err = static_cast<::V1_4::Status>(t);
+    return toStatusT_1_4(err);
+}
+
+template<typename T, typename U>
+status_t GetLogMessages(const sp<U> &obj, Vector<::V1_4::LogMessage> &logs) {
+    sp<T> plugin = T::castFrom(obj);
+    if (plugin == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    ::V1_4::Status err{};
+    ::V1_4::IDrmPlugin::getLogMessages_cb cb = [&](
+            ::V1_4::Status status,
+            hidl_vec<::V1_4::LogMessage> hLogs) {
+        if (::V1_4::Status::OK == status) {
+            err = status;
+            return;
+        }
+        logs.appendArray(hLogs.data(), hLogs.size());
+    };
+
+    Return<void> hResult = plugin->getLogMessages(cb);
+    if (!hResult.isOk()) {
+        return DEAD_OBJECT;
+    }
+    return toStatusT(err);
+}
+
 } // namespace DrmUtils
-
 } // namespace android
-
 #endif // ANDROID_DRMUTILS_H
diff --git a/drm/libmediadrm/interface/mediadrm/ICrypto.h b/drm/libmediadrm/interface/mediadrm/ICrypto.h
index df980ae..2c4df60 100644
--- a/drm/libmediadrm/interface/mediadrm/ICrypto.h
+++ b/drm/libmediadrm/interface/mediadrm/ICrypto.h
@@ -32,6 +32,10 @@
 struct SharedBuffer;
 struct DestinationBuffer;
 }  // namespace V1_0
+
+namespace V1_4 {
+struct LogMessage;
+}  // namespace V1_4
 }  // namespace drm
 }  // namespace hardware
 }  // namespace android
@@ -83,6 +87,8 @@
     virtual int32_t setHeap(const sp<hardware::HidlMemory>& heap) = 0;
     virtual void unsetHeap(int32_t seqNum) = 0;
 
+    virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const = 0;
+
 protected:
     ICrypto() {}
 
diff --git a/include/drm/TEST_MAPPING b/include/drm/TEST_MAPPING
index 512e844..74fa50d 100644
--- a/include/drm/TEST_MAPPING
+++ b/include/drm/TEST_MAPPING
@@ -10,7 +10,7 @@
           "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
         },
         {
-          "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
+          "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
         }
       ]
     }
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 80e0924..5bc7262 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -30,7 +30,7 @@
                     "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
                 },
                 {
-                    "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
+                    "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
                 }
             ]
         }
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index f3341ab..3e6b0ff 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -877,10 +877,14 @@
             work->worklets.front()->output.configUpdate.push_back(
                     C2Param::Copy(currentBoostFactor));
 
-            C2StreamDrcCompressionModeTuning::input currentCompressMode(0u,
-                    (C2Config::drc_compression_mode_t) compressMode);
-            work->worklets.front()->output.configUpdate.push_back(
-                    C2Param::Copy(currentCompressMode));
+            if (android_get_device_api_level() < __ANDROID_API_S__) {
+                // We used to report DRC compression mode in the output format
+                // in Q and R, but stopped doing that in S
+                C2StreamDrcCompressionModeTuning::input currentCompressMode(0u,
+                        (C2Config::drc_compression_mode_t) compressMode);
+                work->worklets.front()->output.configUpdate.push_back(
+                        C2Param::Copy(currentCompressMode));
+            }
 
             C2StreamDrcEncodedTargetLevelTuning::input currentEncodedTargetLevel(0u,
                     (C2FloatValue) (encTargetLevel*-0.25));
diff --git a/media/codec2/fuzzer/C2Fuzzer.cpp b/media/codec2/fuzzer/C2Fuzzer.cpp
index 71956a2..51e1013 100644
--- a/media/codec2/fuzzer/C2Fuzzer.cpp
+++ b/media/codec2/fuzzer/C2Fuzzer.cpp
@@ -148,9 +148,8 @@
   std::vector<std::tuple<C2String, C2ComponentFactory::CreateCodec2FactoryFunc,
         C2ComponentFactory::DestroyCodec2FactoryFunc>> codec2FactoryFunc;
 
-  codec2FactoryFunc.emplace_back(std::make_tuple(C2COMPONENTNAME,
-                                                &CreateCodec2Factory,
-                                                &DestroyCodec2Factory));
+  codec2FactoryFunc.emplace_back(
+      std::make_tuple(C2COMPONENTNAME, &CreateCodec2Factory, &DestroyCodec2Factory));
 
   std::shared_ptr<C2ComponentStore> componentStore = GetTestComponentStore(codec2FactoryFunc);
   if (!componentStore) {
diff --git a/media/codec2/fuzzer/C2Fuzzer.h b/media/codec2/fuzzer/C2Fuzzer.h
index 2efad50..d5ac81a 100644
--- a/media/codec2/fuzzer/C2Fuzzer.h
+++ b/media/codec2/fuzzer/C2Fuzzer.h
@@ -59,8 +59,9 @@
  private:
   class BufferSource {
    public:
-    BufferSource(const uint8_t* data, size_t size)
-        : mData(data), mSize(size), mReadIndex(size - kMarkerSize) {}
+    BufferSource(const uint8_t* data, size_t size) : mData(data), mSize(size) {
+      mReadIndex = (size <= kMarkerSize) ? 0 : (size - kMarkerSize);
+    }
     ~BufferSource() {
       mData = nullptr;
       mSize = 0;
@@ -72,10 +73,20 @@
     FrameData getFrame();
 
    private:
-    bool isMarker() { return (memcmp(&mData[mReadIndex], kMarker, kMarkerSize) == 0); }
+    bool isMarker() {
+      if ((kMarkerSize < mSize) && (mReadIndex < mSize - kMarkerSize)) {
+        return (memcmp(&mData[mReadIndex], kMarker, kMarkerSize) == 0);
+      } else {
+        return false;
+      }
+    }
 
     bool isCSDMarker(size_t position) {
-      return (memcmp(&mData[position], kCsdMarkerSuffix, kMarkerSuffixSize) == 0);
+      if ((kMarkerSuffixSize < mSize) && (position < mSize - kMarkerSuffixSize)) {
+        return (memcmp(&mData[position], kCsdMarkerSuffix, kMarkerSuffixSize) == 0);
+      } else {
+        return false;
+      }
     }
 
     bool searchForMarker();
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 5de4d7f..4fd0341 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -487,6 +487,31 @@
     }
 };
 
+void RevertOutputFormatIfNeeded(
+        const sp<AMessage> &oldFormat, sp<AMessage> &currentFormat) {
+    // We used to not report changes to these keys to the client.
+    const static std::set<std::string> sIgnoredKeys({
+            KEY_BIT_RATE,
+            KEY_MAX_BIT_RATE,
+            "csd-0",
+            "csd-1",
+            "csd-2",
+    });
+    if (currentFormat == oldFormat) {
+        return;
+    }
+    sp<AMessage> diff = currentFormat->changesFrom(oldFormat);
+    AMessage::Type type;
+    for (size_t i = diff->countEntries(); i > 0; --i) {
+        if (sIgnoredKeys.count(diff->getEntryNameAt(i - 1, &type)) > 0) {
+            diff->removeEntryAt(i - 1);
+        }
+    }
+    if (diff->countEntries() == 0) {
+        currentFormat = oldFormat;
+    }
+}
+
 }  // namespace
 
 // CCodec::ClientListener
@@ -518,9 +543,24 @@
     virtual void onError(
             const std::weak_ptr<Codec2Client::Component>& component,
             uint32_t errorCode) override {
-        // TODO
-        (void)component;
-        (void)errorCode;
+        {
+            // Component is only used for reporting as we use a separate listener for each instance
+            std::shared_ptr<Codec2Client::Component> comp = component.lock();
+            if (!comp) {
+                ALOGD("Component died with error: 0x%x", errorCode);
+            } else {
+                ALOGD("Component \"%s\" returned error: 0x%x", comp->getName().c_str(), errorCode);
+            }
+        }
+
+        // Report to MediaCodec
+        // Note: for now we do not propagate the error code to MediaCodec as we would need
+        // to translate to a MediaCodec error.
+        sp<CCodec> codec(mCodec.promote());
+        if (!codec || !codec->mCallback) {
+            return;
+        }
+        codec->mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
     }
 
     virtual void onDeath(
@@ -884,19 +924,84 @@
         /*
          * Handle desired color format.
          */
+        int32_t defaultColorFormat = COLOR_FormatYUV420Flexible;
         if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
-            int32_t format = -1;
+            int32_t format = 0;
+            // Query vendor format for Flexible YUV
+            std::vector<std::unique_ptr<C2Param>> heapParams;
+            C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr;
+            if (mClient->query(
+                        {},
+                        {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
+                        C2_MAY_BLOCK,
+                        &heapParams) == C2_OK
+                    && heapParams.size() == 1u) {
+                pixelFormatInfo = C2StoreFlexiblePixelFormatDescriptorsInfo::From(
+                        heapParams[0].get());
+            } else {
+                pixelFormatInfo = nullptr;
+            }
+            std::optional<uint32_t> flexPixelFormat{};
+            std::optional<uint32_t> flexPlanarPixelFormat{};
+            std::optional<uint32_t> flexSemiPlanarPixelFormat{};
+            if (pixelFormatInfo && *pixelFormatInfo) {
+                for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
+                    const C2FlexiblePixelFormatDescriptorStruct &desc =
+                        pixelFormatInfo->m.values[i];
+                    if (desc.bitDepth != 8
+                            || desc.subsampling != C2Color::YUV_420
+                            // TODO(b/180076105): some device report wrong layout
+                            // || desc.layout == C2Color::INTERLEAVED_PACKED
+                            // || desc.layout == C2Color::INTERLEAVED_ALIGNED
+                            || desc.layout == C2Color::UNKNOWN_LAYOUT) {
+                        continue;
+                    }
+                    if (!flexPixelFormat) {
+                        flexPixelFormat = desc.pixelFormat;
+                    }
+                    if (desc.layout == C2Color::PLANAR_PACKED && !flexPlanarPixelFormat) {
+                        flexPlanarPixelFormat = desc.pixelFormat;
+                    }
+                    if (desc.layout == C2Color::SEMIPLANAR_PACKED && !flexSemiPlanarPixelFormat) {
+                        flexSemiPlanarPixelFormat = desc.pixelFormat;
+                    }
+                }
+            }
             if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) {
-                /*
-                 * Also handle default color format (encoders require color format, so this is only
-                 * needed for decoders.
-                 */
+                // Also handle default color format (encoders require color format, so this is only
+                // needed for decoders.
                 if (!(config->mDomain & Config::IS_ENCODER)) {
-                    format = (surface == nullptr) ? COLOR_FormatYUV420Planar : COLOR_FormatSurface;
+                    if (surface == nullptr) {
+                        format = flexPixelFormat.value_or(COLOR_FormatYUV420Flexible);
+                    } else {
+                        format = COLOR_FormatSurface;
+                    }
+                    defaultColorFormat = format;
+                }
+            } else {
+                if ((config->mDomain & Config::IS_ENCODER) || !surface) {
+                    switch (format) {
+                        case COLOR_FormatYUV420Flexible:
+                            format = flexPixelFormat.value_or(COLOR_FormatYUV420Planar);
+                            break;
+                        case COLOR_FormatYUV420Planar:
+                        case COLOR_FormatYUV420PackedPlanar:
+                            format = flexPlanarPixelFormat.value_or(
+                                    flexPixelFormat.value_or(format));
+                            break;
+                        case COLOR_FormatYUV420SemiPlanar:
+                        case COLOR_FormatYUV420PackedSemiPlanar:
+                            format = flexSemiPlanarPixelFormat.value_or(
+                                    flexPixelFormat.value_or(format));
+                            break;
+                        default:
+                            // No-op
+                            break;
+                    }
                 }
             }
 
-            if (format >= 0) {
+            if (format != 0) {
                 msg->setInt32("android._color-format", format);
             }
         }
@@ -1049,12 +1154,16 @@
 
             // Set desired color format from configuration parameter
             int32_t format;
-            if (msg->findInt32("android._color-format", &format)) {
-                if (config->mDomain & Config::IS_ENCODER) {
-                    config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format);
-                } else {
-                    config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format);
+            if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) {
+                format = defaultColorFormat;
+            }
+            if (config->mDomain & Config::IS_ENCODER) {
+                config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format);
+                if (msg->findInt32("android._color-format", &format)) {
+                    config->mInputFormat->setInt32("android._color-format", format);
                 }
+            } else {
+                config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format);
             }
         }
 
@@ -1687,7 +1796,9 @@
                     || comp->getName().find("c2.android.") == 0)) {
         mChannel->setParameters(configUpdate);
     } else {
+        sp<AMessage> outputFormat = config->mOutputFormat;
         (void)config->setParameters(comp, configUpdate, C2_MAY_BLOCK);
+        RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
     }
 }
 
@@ -1812,7 +1923,6 @@
             // handle configuration changes in work done
             Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
             const std::unique_ptr<Config> &config = *configLocked;
-            bool changed = false;
             Config::Watcher<C2StreamInitDataInfo::output> initData =
                 config->watch<C2StreamInitDataInfo::output>();
             if (!work->worklets.empty()
@@ -1847,9 +1957,9 @@
                     ++stream;
                 }
 
-                if (config->updateConfiguration(updates, config->mOutputDomain)) {
-                    changed = true;
-                }
+                sp<AMessage> outputFormat = config->mOutputFormat;
+                config->updateConfiguration(updates, config->mOutputDomain);
+                RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
 
                 // copy standard infos to graphic buffers if not already present (otherwise, we
                 // may overwrite the actual intermediate value with a final value)
@@ -1883,7 +1993,7 @@
                 config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
             }
             mChannel->onWorkDone(
-                    std::move(work), changed ? config->mOutputFormat->dup() : nullptr,
+                    std::move(work), config->mOutputFormat,
                     initData.hasChanged() ? initData.update().get() : nullptr);
             break;
         }
@@ -2012,7 +2122,7 @@
             }
             if (param->type() == C2PortAllocatorsTuning::input::PARAM_TYPE) {
                 mInputAllocators.reset(
-                        C2PortAllocatorsTuning::input::From(params[0].get()));
+                        C2PortAllocatorsTuning::input::From(param));
             }
         }
         mInitStatus = OK;
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index d656350..2025da2 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -27,6 +27,7 @@
 #include <mediadrm/ICrypto.h>
 
 #include "CCodecBuffers.h"
+#include "Codec2Mapper.h"
 
 namespace android {
 
@@ -161,8 +162,7 @@
     setSkipCutBuffer(delay, padding);
 }
 
-void OutputBuffers::updateSkipCutBuffer(
-        const sp<AMessage> &format, bool notify) {
+void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
     AString mediaType;
     if (format->findString(KEY_MIME, &mediaType)
             && mediaType == MIMETYPE_AUDIO_RAW) {
@@ -173,9 +173,6 @@
             updateSkipCutBuffer(sampleRate, channelCount);
         }
     }
-    if (notify) {
-        mUnreportedFormat = nullptr;
-    }
 }
 
 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
@@ -199,7 +196,6 @@
     mReorderStash.clear();
     mDepth = 0;
     mKey = C2Config::ORDINAL;
-    mUnreportedFormat = nullptr;
 }
 
 void OutputBuffers::flushStash() {
@@ -275,25 +271,25 @@
     *c2Buffer = entry.buffer;
     sp<AMessage> outputFormat = entry.format;
 
-    // The output format can be processed without a registered slot.
-    if (outputFormat) {
-        updateSkipCutBuffer(outputFormat, entry.notify);
-    }
-
-    if (entry.notify) {
-        if (outputFormat) {
-            setFormat(outputFormat);
-        } else if (mUnreportedFormat) {
-            outputFormat = mUnreportedFormat;
-            setFormat(outputFormat);
+    if (entry.notify && mFormat != outputFormat) {
+        updateSkipCutBuffer(outputFormat);
+        sp<ABuffer> imageData;
+        if (mFormat->findBuffer("image-data", &imageData)) {
+            outputFormat->setBuffer("image-data", imageData);
         }
-        mUnreportedFormat = nullptr;
-    } else {
-        if (outputFormat) {
-            mUnreportedFormat = outputFormat;
-        } else if (!mUnreportedFormat) {
-            mUnreportedFormat = mFormat;
+        int32_t stride;
+        if (mFormat->findInt32(KEY_STRIDE, &stride)) {
+            outputFormat->setInt32(KEY_STRIDE, stride);
         }
+        int32_t sliceHeight;
+        if (mFormat->findInt32(KEY_SLICE_HEIGHT, &sliceHeight)) {
+            outputFormat->setInt32(KEY_SLICE_HEIGHT, sliceHeight);
+        }
+        ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
+                mName, mFormat.get(), outputFormat.get());
+        ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
+                mName, outputFormat->debugString().c_str());
+        setFormat(outputFormat);
     }
 
     // Flushing mReorderStash because no other buffers should come after output
@@ -304,10 +300,6 @@
     }
 
     if (!entry.notify) {
-        if (outputFormat) {
-            ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
-                    mName, outputFormat->debugString().c_str());
-        }
         mPending.pop_front();
         return DISCARD;
     }
@@ -325,10 +317,6 @@
     (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
     (*outBuffer)->meta()->setInt32("flags", entry.flags);
     (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
-    if (outputFormat) {
-        ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
-                mName, outputFormat->debugString().c_str());
-    }
     ALOGV("[%s] popFromStashAndRegister: "
           "out buffer index = %zu [%p] => %p + %zu (%lld)",
           mName, *index, outBuffer->get(),
@@ -1021,18 +1009,32 @@
     // track of the flushed work.
 }
 
+static uint32_t extractPixelFormat(const sp<AMessage> &format) {
+    int32_t frameworkColorFormat = 0;
+    if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
+        return PIXEL_FORMAT_UNKNOWN;
+    }
+    uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
+    if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
+        return pixelFormat;
+    }
+    return PIXEL_FORMAT_UNKNOWN;
+}
+
 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
     std::unique_ptr<InputBuffersArray> array(
             new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
     array->setPool(mPool);
     array->setFormat(mFormat);
+    uint32_t pixelFormat = extractPixelFormat(mFormat);
     array->initialize(
             mImpl,
             size,
-            [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
+            [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
+                    -> sp<Codec2Buffer> {
                 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
                 return AllocateGraphicBuffer(
-                        pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
+                        pool, format, pixelFormat, usage, lbp);
             });
     return std::move(array);
 }
@@ -1046,7 +1048,7 @@
     (void)mFormat->findInt64("android._C2MemoryUsage", &usageValue);
     C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
     return AllocateGraphicBuffer(
-            mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
+            mPool, mFormat, extractPixelFormat(mFormat), usage, mLocalBufferPool);
 }
 
 // OutputBuffersArray
@@ -1182,7 +1184,6 @@
 void OutputBuffersArray::transferFrom(OutputBuffers* source) {
     mFormat = source->mFormat;
     mSkipCutBuffer = source->mSkipCutBuffer;
-    mUnreportedFormat = source->mUnreportedFormat;
     mPending = std::move(source->mPending);
     mReorderStash = std::move(source->mReorderStash);
     mDepth = source->mDepth;
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index c383a7c..7c4e7b1 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -215,10 +215,8 @@
 
     /**
      * Update SkipCutBuffer from format. The @p format must not be null.
-     * @p notify determines whether the format comes with a buffer that should
-     * be reported to the client or not.
      */
-    void updateSkipCutBuffer(const sp<AMessage> &format, bool notify = true);
+    void updateSkipCutBuffer(const sp<AMessage> &format);
 
     /**
      * Output Stash
@@ -392,9 +390,6 @@
 
     // Output stash
 
-    // Output format that has not been made available to the client.
-    sp<AMessage> mUnreportedFormat;
-
     // Struct for an entry in the output stash (mPending and mReorderStash)
     struct StashEntry {
         inline StashEntry()
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 79c6227..5decb99 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -765,21 +765,13 @@
 
     // convert to compression type and add default
     add(ConfigMapper(KEY_AAC_DRC_HEAVY_COMPRESSION, C2_PARAMKEY_DRC_COMPRESSION_MODE, "value")
-        .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
-        .withMappers([](C2Value v) -> C2Value {
+        .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM))
+        .withMapper([](C2Value v) -> C2Value {
             int32_t value;
             if (!v.get(&value) || value < 0) {
                 value = property_get_int32(PROP_DRC_OVERRIDE_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY);
             }
             return value == 1 ? C2Config::DRC_COMPRESSION_HEAVY : C2Config::DRC_COMPRESSION_LIGHT;
-        },[](C2Value v) -> C2Value {
-            int32_t value;
-            if (v.get(&value)) {
-              return value;
-            }
-            else {
-              return C2Value();
-            }
         }));
 
     // convert to dBFS and add default
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 5072323..fc4ee51 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -212,21 +212,24 @@
      * Creates a C2GraphicView <=> MediaImage converter
      *
      * \param view C2GraphicView object
-     * \param colorFormat desired SDK color format for the MediaImage (if this is a flexible format,
-     *        an attempt is made to simply represent the graphic view as a flexible SDK format
-     *        without a memcpy)
+     * \param format buffer format
      * \param copy whether the converter is used for copy or not
      */
     GraphicView2MediaImageConverter(
-            const C2GraphicView &view, int32_t colorFormat, bool copy)
+            const C2GraphicView &view, const sp<AMessage> &format, bool copy)
         : mInitCheck(NO_INIT),
           mView(view),
           mWidth(view.width()),
           mHeight(view.height()),
-          mColorFormat(colorFormat),
           mAllocatedDepth(0),
           mBackBufferSize(0),
           mMediaImage(new ABuffer(sizeof(MediaImage2))) {
+        if (!format->findInt32(KEY_COLOR_FORMAT, &mClientColorFormat)) {
+            mClientColorFormat = COLOR_FormatYUV420Flexible;
+        }
+        if (!format->findInt32("android._color-format", &mComponentColorFormat)) {
+            mComponentColorFormat = COLOR_FormatYUV420Flexible;
+        }
         if (view.error() != C2_OK) {
             ALOGD("Converter: view.error() = %d", view.error());
             mInitCheck = BAD_VALUE;
@@ -247,70 +250,57 @@
         uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
         uint32_t vStride = align(view.crop().height, 2);
 
+        bool tryWrapping = !copy;
+
         switch (layout.type) {
-            case C2PlanarLayout::TYPE_YUV:
+            case C2PlanarLayout::TYPE_YUV: {
                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
                 if (layout.numPlanes != 3) {
                     ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
                     mInitCheck = BAD_VALUE;
                     return;
                 }
-                if (layout.planes[0].channel != C2PlaneInfo::CHANNEL_Y
-                        || layout.planes[1].channel != C2PlaneInfo::CHANNEL_CB
-                        || layout.planes[2].channel != C2PlaneInfo::CHANNEL_CR
-                        || layout.planes[0].colSampling != 1
-                        || layout.planes[0].rowSampling != 1
-                        || layout.planes[1].colSampling != 2
-                        || layout.planes[1].rowSampling != 2
-                        || layout.planes[2].colSampling != 2
-                        || layout.planes[2].rowSampling != 2) {
-                    ALOGD("Converter: not YUV420 for YUV layout");
+                C2PlaneInfo yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
+                C2PlaneInfo uPlane = layout.planes[C2PlanarLayout::PLANE_U];
+                C2PlaneInfo vPlane = layout.planes[C2PlanarLayout::PLANE_V];
+                if (yPlane.channel != C2PlaneInfo::CHANNEL_Y
+                        || uPlane.channel != C2PlaneInfo::CHANNEL_CB
+                        || vPlane.channel != C2PlaneInfo::CHANNEL_CR) {
+                    ALOGD("Converter: not YUV layout");
                     mInitCheck = BAD_VALUE;
                     return;
                 }
-                switch (mColorFormat) {
-                    case COLOR_FormatYUV420Flexible:
-                        if (!copy) {
-                            // try to map directly. check if the planes are near one another
-                            const uint8_t *minPtr = mView.data()[0];
-                            const uint8_t *maxPtr = mView.data()[0];
-                            int32_t planeSize = 0;
-                            for (uint32_t i = 0; i < layout.numPlanes; ++i) {
-                                const C2PlaneInfo &plane = layout.planes[i];
-                                int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
-                                ssize_t minOffset = plane.minOffset(
-                                        mWidth / plane.colSampling, mHeight / plane.rowSampling);
-                                ssize_t maxOffset = plane.maxOffset(
-                                        mWidth / plane.colSampling, mHeight / plane.rowSampling);
-                                if (minPtr > mView.data()[i] + minOffset) {
-                                    minPtr = mView.data()[i] + minOffset;
-                                }
-                                if (maxPtr < mView.data()[i] + maxOffset) {
-                                    maxPtr = mView.data()[i] + maxOffset;
-                                }
-                                planeSize += planeStride * divUp(mAllocatedDepth, 8u)
-                                        * align(mHeight, 64) / plane.rowSampling;
-                            }
-
-                            if (minPtr == mView.data()[0] && (maxPtr - minPtr + 1) <= planeSize) {
-                                // FIXME: this is risky as reading/writing data out of bound results
-                                //        in an undefined behavior, but gralloc does assume a
-                                //        contiguous mapping
-                                for (uint32_t i = 0; i < layout.numPlanes; ++i) {
-                                    const C2PlaneInfo &plane = layout.planes[i];
-                                    mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
-                                    mediaImage->mPlane[i].mColInc = plane.colInc;
-                                    mediaImage->mPlane[i].mRowInc = plane.rowInc;
-                                    mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
-                                    mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
-                                }
-                                mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
-                                                       maxPtr - minPtr + 1);
-                                break;
-                            }
+                bool yuv420888 = yPlane.rowSampling == 1 && yPlane.colSampling == 1
+                        && uPlane.rowSampling == 2 && uPlane.colSampling == 2
+                        && vPlane.rowSampling == 2 && vPlane.colSampling == 2;
+                if (yuv420888) {
+                    for (uint32_t i = 0; i < 3; ++i) {
+                        const C2PlaneInfo &plane = layout.planes[i];
+                        if (plane.allocatedDepth != 8 || plane.bitDepth != 8) {
+                            yuv420888 = false;
+                            break;
                         }
-                        [[fallthrough]];
-
+                    }
+                    yuv420888 = yuv420888 && yPlane.colInc == 1 && uPlane.rowInc == vPlane.rowInc;
+                }
+                int32_t copyFormat = mClientColorFormat;
+                if (yuv420888 && mClientColorFormat == COLOR_FormatYUV420Flexible) {
+                    if (uPlane.colInc == 2 && vPlane.colInc == 2
+                            && yPlane.rowInc == uPlane.rowInc) {
+                        copyFormat = COLOR_FormatYUV420PackedSemiPlanar;
+                    } else if (uPlane.colInc == 1 && vPlane.colInc == 1
+                            && yPlane.rowInc == uPlane.rowInc * 2) {
+                        copyFormat = COLOR_FormatYUV420PackedPlanar;
+                    }
+                }
+                ALOGV("client_fmt=0x%x y:{colInc=%d rowInc=%d} u:{colInc=%d rowInc=%d} "
+                        "v:{colInc=%d rowInc=%d}",
+                        mClientColorFormat,
+                        yPlane.colInc, yPlane.rowInc,
+                        uPlane.colInc, uPlane.rowInc,
+                        vPlane.colInc, vPlane.rowInc);
+                switch (copyFormat) {
+                    case COLOR_FormatYUV420Flexible:
                     case COLOR_FormatYUV420Planar:
                     case COLOR_FormatYUV420PackedPlanar:
                         mediaImage->mPlane[mediaImage->Y].mOffset = 0;
@@ -330,6 +320,13 @@
                         mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
+
+                        if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
+                            tryWrapping = yuv420888 && uPlane.colInc == 1 && vPlane.colInc == 1
+                                    && yPlane.rowInc == uPlane.rowInc * 2
+                                    && view.data()[0] < view.data()[1]
+                                    && view.data()[1] < view.data()[2];
+                        }
                         break;
 
                     case COLOR_FormatYUV420SemiPlanar:
@@ -351,64 +348,165 @@
                         mediaImage->mPlane[mediaImage->V].mRowInc = stride;
                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
+
+                        if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
+                            tryWrapping = yuv420888 && uPlane.colInc == 2 && vPlane.colInc == 2
+                                    && yPlane.rowInc == uPlane.rowInc
+                                    && view.data()[0] < view.data()[1]
+                                    && view.data()[1] < view.data()[2];
+                        }
                         break;
 
-                    default:
-                        ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
-                        mInitCheck = BAD_VALUE;
-                        return;
+                    case COLOR_FormatYUVP010:
+                        mediaImage->mPlane[mediaImage->Y].mOffset = 0;
+                        mediaImage->mPlane[mediaImage->Y].mColInc = 2;
+                        mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
+                        mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
+                        mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
+
+                        mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
+                        mediaImage->mPlane[mediaImage->U].mColInc = 4;
+                        mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
+                        mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
+                        mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
+
+                        mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
+                        mediaImage->mPlane[mediaImage->V].mColInc = 4;
+                        mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
+                        mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
+                        mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
+                        if (tryWrapping) {
+                            tryWrapping = yPlane.allocatedDepth == 16
+                                    && uPlane.allocatedDepth == 16
+                                    && vPlane.allocatedDepth == 16
+                                    && yPlane.bitDepth == 10
+                                    && uPlane.bitDepth == 10
+                                    && vPlane.bitDepth == 10
+                                    && yPlane.rightShift == 6
+                                    && uPlane.rightShift == 6
+                                    && vPlane.rightShift == 6
+                                    && yPlane.rowSampling == 1 && yPlane.colSampling == 1
+                                    && uPlane.rowSampling == 2 && uPlane.colSampling == 2
+                                    && vPlane.rowSampling == 2 && vPlane.colSampling == 2
+                                    && yPlane.colInc == 2
+                                    && uPlane.colInc == 4
+                                    && vPlane.colInc == 4
+                                    && yPlane.rowInc == uPlane.rowInc
+                                    && yPlane.rowInc == vPlane.rowInc;
+                        }
+                        break;
+
+                    default: {
+                        // default to fully planar format --- this will be overridden if wrapping
+                        // TODO: keep interleaved format
+                        int32_t colInc = divUp(mAllocatedDepth, 8u);
+                        int32_t rowInc = stride * colInc / yPlane.colSampling;
+                        mediaImage->mPlane[mediaImage->Y].mOffset = 0;
+                        mediaImage->mPlane[mediaImage->Y].mColInc = colInc;
+                        mediaImage->mPlane[mediaImage->Y].mRowInc = rowInc;
+                        mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = yPlane.colSampling;
+                        mediaImage->mPlane[mediaImage->Y].mVertSubsampling = yPlane.rowSampling;
+                        int32_t offset = rowInc * vStride / yPlane.rowSampling;
+
+                        rowInc = stride * colInc / uPlane.colSampling;
+                        mediaImage->mPlane[mediaImage->U].mOffset = offset;
+                        mediaImage->mPlane[mediaImage->U].mColInc = colInc;
+                        mediaImage->mPlane[mediaImage->U].mRowInc = rowInc;
+                        mediaImage->mPlane[mediaImage->U].mHorizSubsampling = uPlane.colSampling;
+                        mediaImage->mPlane[mediaImage->U].mVertSubsampling = uPlane.rowSampling;
+                        offset += rowInc * vStride / uPlane.rowSampling;
+
+                        rowInc = stride * colInc / vPlane.colSampling;
+                        mediaImage->mPlane[mediaImage->V].mOffset = offset;
+                        mediaImage->mPlane[mediaImage->V].mColInc = colInc;
+                        mediaImage->mPlane[mediaImage->V].mRowInc = rowInc;
+                        mediaImage->mPlane[mediaImage->V].mHorizSubsampling = vPlane.colSampling;
+                        mediaImage->mPlane[mediaImage->V].mVertSubsampling = vPlane.rowSampling;
+                        break;
+                    }
                 }
                 break;
+            }
+
             case C2PlanarLayout::TYPE_YUVA:
-                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
-                // We don't have an SDK YUVA format
-                ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
-                mInitCheck = BAD_VALUE;
+                ALOGD("Converter: unrecognized color format "
+                        "(client %d component %d) for YUVA layout",
+                        mClientColorFormat, mComponentColorFormat);
+                mInitCheck = NO_INIT;
                 return;
             case C2PlanarLayout::TYPE_RGB:
-                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
-                switch (mColorFormat) {
-                    // TODO media image
-                    case COLOR_FormatRGBFlexible:
-                    case COLOR_Format24bitBGR888:
-                    case COLOR_Format24bitRGB888:
-                        break;
-                    default:
-                        ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
-                        mInitCheck = BAD_VALUE;
-                        return;
-                }
-                if (layout.numPlanes != 3) {
-                    ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
-                    mInitCheck = BAD_VALUE;
-                    return;
-                }
-                break;
+                ALOGD("Converter: unrecognized color format "
+                        "(client %d component %d) for RGB layout",
+                        mClientColorFormat, mComponentColorFormat);
+                mInitCheck = NO_INIT;
+                // TODO: support MediaImage layout
+                return;
             case C2PlanarLayout::TYPE_RGBA:
-                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
-                switch (mColorFormat) {
-                    // TODO media image
-                    case COLOR_FormatRGBAFlexible:
-                    case COLOR_Format32bitABGR8888:
-                    case COLOR_Format32bitARGB8888:
-                    case COLOR_Format32bitBGRA8888:
-                        break;
-                    default:
-                        ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
-                        mInitCheck = BAD_VALUE;
-                        return;
-                }
-                if (layout.numPlanes != 4) {
-                    ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
-                    mInitCheck = BAD_VALUE;
-                    return;
-                }
-                break;
+                ALOGD("Converter: unrecognized color format "
+                        "(client %d component %d) for RGBA layout",
+                        mClientColorFormat, mComponentColorFormat);
+                mInitCheck = NO_INIT;
+                // TODO: support MediaImage layout
+                return;
             default:
                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
-                ALOGD("Unknown layout");
-                mInitCheck = BAD_VALUE;
-                return;
+                if (layout.numPlanes == 1) {
+                    const C2PlaneInfo &plane = layout.planes[0];
+                    if (plane.colInc < 0 || plane.rowInc < 0) {
+                        // Copy-only if we have negative colInc/rowInc
+                        tryWrapping = false;
+                    }
+                    mediaImage->mPlane[0].mOffset = 0;
+                    mediaImage->mPlane[0].mColInc = std::abs(plane.colInc);
+                    mediaImage->mPlane[0].mRowInc = std::abs(plane.rowInc);
+                    mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
+                    mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
+                } else {
+                    ALOGD("Converter: unrecognized layout: color format (client %d component %d)",
+                            mClientColorFormat, mComponentColorFormat);
+                    mInitCheck = NO_INIT;
+                    return;
+                }
+                break;
+        }
+        if (tryWrapping) {
+            // try to map directly. check if the planes are near one another
+            const uint8_t *minPtr = mView.data()[0];
+            const uint8_t *maxPtr = mView.data()[0];
+            int32_t planeSize = 0;
+            for (uint32_t i = 0; i < layout.numPlanes; ++i) {
+                const C2PlaneInfo &plane = layout.planes[i];
+                int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
+                ssize_t minOffset = plane.minOffset(
+                        mWidth / plane.colSampling, mHeight / plane.rowSampling);
+                ssize_t maxOffset = plane.maxOffset(
+                        mWidth / plane.colSampling, mHeight / plane.rowSampling);
+                if (minPtr > mView.data()[i] + minOffset) {
+                    minPtr = mView.data()[i] + minOffset;
+                }
+                if (maxPtr < mView.data()[i] + maxOffset) {
+                    maxPtr = mView.data()[i] + maxOffset;
+                }
+                planeSize += planeStride * divUp(mAllocatedDepth, 8u)
+                        * align(mHeight, 64) / plane.rowSampling;
+            }
+
+            if ((maxPtr - minPtr + 1) <= planeSize) {
+                // FIXME: this is risky as reading/writing data out of bound results
+                //        in an undefined behavior, but gralloc does assume a
+                //        contiguous mapping
+                for (uint32_t i = 0; i < layout.numPlanes; ++i) {
+                    const C2PlaneInfo &plane = layout.planes[i];
+                    mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
+                    mediaImage->mPlane[i].mColInc = plane.colInc;
+                    mediaImage->mPlane[i].mRowInc = plane.rowInc;
+                    mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
+                    mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
+                }
+                mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
+                                       maxPtr - minPtr + 1);
+                ALOGV("Converter: wrapped (capacity=%zu)", mWrapped->capacity());
+            }
         }
         mediaImage->mNumPlanes = layout.numPlanes;
         mediaImage->mWidth = view.crop().width;
@@ -431,12 +529,12 @@
                 return;
             }
             if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
-                ALOGV("different allocatedDepth/bitDepth per plane unsupported");
+                ALOGD("different allocatedDepth/bitDepth per plane unsupported");
                 mInitCheck = BAD_VALUE;
                 return;
             }
             bufferSize += stride * vStride
-                    / plane.rowSampling / plane.colSampling;
+                    / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
         }
 
         mBackBufferSize = bufferSize;
@@ -491,7 +589,8 @@
     const C2GraphicView mView;
     uint32_t mWidth;
     uint32_t mHeight;
-    int32_t mColorFormat;  ///< SDK color format for MediaImage
+    int32_t mClientColorFormat;  ///< SDK color format for MediaImage
+    int32_t mComponentColorFormat;  ///< SDK color format from component
     sp<ABuffer> mWrapped;  ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
     uint32_t mAllocatedDepth;
     uint32_t mBackBufferSize;
@@ -520,10 +619,7 @@
         return nullptr;
     }
 
-    int32_t colorFormat = COLOR_FormatYUV420Flexible;
-    (void)format->findInt32("color-format", &colorFormat);
-
-    GraphicView2MediaImageConverter converter(view, colorFormat, false /* copy */);
+    GraphicView2MediaImageConverter converter(view, format, false /* copy */);
     if (converter.initCheck() != OK) {
         ALOGD("Converter init failed: %d", converter.initCheck());
         return nullptr;
@@ -649,10 +745,7 @@
             buffer->data().graphicBlocks()[0].map().get()));
     std::unique_ptr<const C2GraphicView> holder;
 
-    int32_t colorFormat = COLOR_FormatYUV420Flexible;
-    (void)format->findInt32("color-format", &colorFormat);
-
-    GraphicView2MediaImageConverter converter(*view, colorFormat, false /* copy */);
+    GraphicView2MediaImageConverter converter(*view, format, false /* copy */);
     if (converter.initCheck() != OK) {
         ALOGD("Converter init failed: %d", converter.initCheck());
         return nullptr;
@@ -744,12 +837,11 @@
         return false;
     }
 
-    int32_t colorFormat = COLOR_FormatYUV420Flexible;
-    // FIXME: format() is not const, but we cannot change it, so do a const cast here
-    const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
-
     GraphicView2MediaImageConverter converter(
-            buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
+            buffer->data().graphicBlocks()[0].map().get(),
+            // FIXME: format() is not const, but we cannot change it, so do a const cast here
+            const_cast<ConstGraphicBlockBuffer *>(this)->format(),
+            true /* copy */);
     if (converter.initCheck() != OK) {
         ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
         return false;
@@ -767,11 +859,9 @@
         setRange(0, 0);
         return true;
     }
-    int32_t colorFormat = COLOR_FormatYUV420Flexible;
-    format()->findInt32("color-format", &colorFormat);
 
     GraphicView2MediaImageConverter converter(
-            buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
+            buffer->data().graphicBlocks()[0].map().get(), format(), true /* copy */);
     if (converter.initCheck() != OK) {
         ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
         return false;
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index b112249..a26f89e 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -103,11 +103,16 @@
     c2_status_t err1 = intf->querySupportedParams(&paramDescs);
     if (err1 == C2_OK) {
         for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
-            switch ((uint32_t)desc->index()) {
-            case C2StreamHdr10PlusInfo::output::PARAM_TYPE:
+            C2Param::Type type = desc->index();
+            // only consider supported parameters on raw ports
+            if (!(encoder ? type.forInput() : type.forOutput())) {
+                continue;
+            }
+            switch (type.coreIndex()) {
+            case C2StreamHdr10PlusInfo::CORE_INDEX:
                 supportsHdr10Plus = true;
                 break;
-            case C2StreamHdrStaticInfo::output::PARAM_TYPE:
+            case C2StreamHdrStaticInfo::CORE_INDEX:
                 supportsHdr = true;
                 break;
             default:
diff --git a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
index ad8f6e5..66b7622 100644
--- a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
+++ b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
@@ -18,11 +18,12 @@
 
 #include <gtest/gtest.h>
 
-#include <media/stagefright/foundation/AString.h>
+#include <codec2/hidl/client.h>
 #include <media/stagefright/MediaCodecConstants.h>
 
 #include <C2BlockInternal.h>
 #include <C2PlatformSupport.h>
+#include <Codec2Mapper.h>
 
 namespace android {
 
@@ -105,6 +106,318 @@
     }
 }
 
+TEST(RawGraphicOutputBuffersTest, FlexYuvColorFormat) {
+    constexpr int32_t kWidth = 320;
+    constexpr int32_t kHeight = 240;
+
+    std::vector<uint32_t> flexPixelFormats({HAL_PIXEL_FORMAT_YCbCr_420_888});
+    std::shared_ptr<Codec2Client> client = Codec2Client::CreateFromService("default");
+    if (client) {
+        // Query vendor format for Flexible YUV
+        std::vector<std::unique_ptr<C2Param>> heapParams;
+        C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr;
+        if (client->query(
+                    {},
+                    {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
+                    C2_MAY_BLOCK,
+                    &heapParams) == C2_OK
+                && heapParams.size() == 1u) {
+            pixelFormatInfo = C2StoreFlexiblePixelFormatDescriptorsInfo::From(
+                    heapParams[0].get());
+        } else {
+            pixelFormatInfo = nullptr;
+        }
+        if (pixelFormatInfo && *pixelFormatInfo) {
+            for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
+                const C2FlexiblePixelFormatDescriptorStruct &desc =
+                    pixelFormatInfo->m.values[i];
+                if (desc.bitDepth != 8
+                        || desc.subsampling != C2Color::YUV_420
+                        // TODO(b/180076105): some devices report wrong layouts
+                        // || desc.layout == C2Color::INTERLEAVED_PACKED
+                        // || desc.layout == C2Color::INTERLEAVED_ALIGNED
+                        || desc.layout == C2Color::UNKNOWN_LAYOUT) {
+                    continue;
+                }
+                flexPixelFormats.push_back(desc.pixelFormat);
+            }
+        }
+    }
+
+    for (uint32_t pixelFormat : flexPixelFormats) {
+        std::shared_ptr<RawGraphicOutputBuffers> buffers =
+            std::make_shared<RawGraphicOutputBuffers>(
+                    AStringPrintf("test pixel format 0x%x", pixelFormat).c_str());
+
+        sp<AMessage> format{new AMessage};
+        format->setInt32(KEY_WIDTH, kWidth);
+        format->setInt32(KEY_HEIGHT, kHeight);
+        format->setInt32(KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
+        int32_t fwkPixelFormat = 0;
+        if (C2Mapper::mapPixelFormatCodecToFramework(pixelFormat, &fwkPixelFormat)) {
+            format->setInt32("android._color-format", fwkPixelFormat);
+        }
+        buffers->setFormat(format);
+
+        std::shared_ptr<C2BlockPool> pool;
+        ASSERT_EQ(OK, GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool));
+
+        std::shared_ptr<C2GraphicBlock> block;
+        ASSERT_EQ(OK, pool->fetchGraphicBlock(
+                kWidth, kHeight, pixelFormat,
+                C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
+
+        {
+            C2GraphicView view = block->map().get();
+            C2PlanarLayout layout = view.layout();
+
+            // Verify the block is in YUV420 format
+            ASSERT_EQ(C2PlanarLayout::TYPE_YUV, layout.type);
+            ASSERT_EQ(3u, layout.numPlanes);
+            const C2PlaneInfo& yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
+            const C2PlaneInfo& uPlane = layout.planes[C2PlanarLayout::PLANE_U];
+            const C2PlaneInfo& vPlane = layout.planes[C2PlanarLayout::PLANE_V];
+
+            // Y plane
+            ASSERT_EQ(1u, yPlane.colSampling);
+            ASSERT_EQ(1u, yPlane.rowSampling);
+            ASSERT_EQ(8u, yPlane.allocatedDepth);
+            ASSERT_EQ(8u, yPlane.bitDepth);
+            ASSERT_EQ(0u, yPlane.rightShift);
+
+            // U plane
+            ASSERT_EQ(2u, uPlane.colSampling);
+            ASSERT_EQ(2u, uPlane.rowSampling);
+            ASSERT_EQ(8u, uPlane.allocatedDepth);
+            ASSERT_EQ(8u, uPlane.bitDepth);
+            ASSERT_EQ(0u, uPlane.rightShift);
+
+            // V plane
+            ASSERT_EQ(2u, vPlane.colSampling);
+            ASSERT_EQ(2u, vPlane.rowSampling);
+            ASSERT_EQ(8u, vPlane.allocatedDepth);
+            ASSERT_EQ(8u, vPlane.bitDepth);
+            ASSERT_EQ(0u, vPlane.rightShift);
+
+            uint8_t *yRowPtr = view.data()[C2PlanarLayout::PLANE_Y];
+            uint8_t *uRowPtr = view.data()[C2PlanarLayout::PLANE_U];
+            uint8_t *vRowPtr = view.data()[C2PlanarLayout::PLANE_V];
+            for (int32_t row = 0; row < kHeight; ++row) {
+                uint8_t *yPtr = yRowPtr;
+                uint8_t *uPtr = uRowPtr;
+                uint8_t *vPtr = vRowPtr;
+                for (int32_t col = 0; col < kWidth; ++col) {
+                    *yPtr = ((row + col) & 0xFF);
+                    yPtr += yPlane.colInc;
+
+                    if (row < kHeight / 2 && col < kWidth / 2) {
+                        *uPtr = ((row + col + 1) & 0xFF);
+                        *vPtr = ((row + col + 2) & 0xFF);
+                        uPtr += uPlane.colInc;
+                        vPtr += vPlane.colInc;
+                    }
+                }
+                yRowPtr += yPlane.rowInc;
+                if (row < kHeight / 2) {
+                    uRowPtr += uPlane.rowInc;
+                    vRowPtr += vPlane.rowInc;
+                }
+            }
+        }
+
+        std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateGraphicBuffer(block->share(
+                block->crop(), C2Fence{}));
+        size_t index;
+        sp<MediaCodecBuffer> clientBuffer;
+        ASSERT_EQ(OK, buffers->registerBuffer(c2Buffer, &index, &clientBuffer));
+        ASSERT_NE(nullptr, clientBuffer);
+        sp<ABuffer> imageData;
+        ASSERT_TRUE(clientBuffer->format()->findBuffer("image-data", &imageData));
+        MediaImage2 *img = (MediaImage2 *)imageData->data();
+        ASSERT_EQ(MediaImage2::MEDIA_IMAGE_TYPE_YUV, img->mType);
+        ASSERT_EQ(3u, img->mNumPlanes);
+        ASSERT_EQ(kWidth, img->mWidth);
+        ASSERT_EQ(kHeight, img->mHeight);
+        ASSERT_EQ(8u, img->mBitDepth);
+        ASSERT_EQ(8u, img->mBitDepthAllocated);
+        const MediaImage2::PlaneInfo &yPlane = img->mPlane[MediaImage2::Y];
+        const MediaImage2::PlaneInfo &uPlane = img->mPlane[MediaImage2::U];
+        const MediaImage2::PlaneInfo &vPlane = img->mPlane[MediaImage2::V];
+        ASSERT_EQ(1u, yPlane.mHorizSubsampling);
+        ASSERT_EQ(1u, yPlane.mVertSubsampling);
+        ASSERT_EQ(2u, uPlane.mHorizSubsampling);
+        ASSERT_EQ(2u, uPlane.mVertSubsampling);
+        ASSERT_EQ(2u, vPlane.mHorizSubsampling);
+        ASSERT_EQ(2u, vPlane.mVertSubsampling);
+
+        uint8_t *yRowPtr = clientBuffer->data() + yPlane.mOffset;
+        uint8_t *uRowPtr = clientBuffer->data() + uPlane.mOffset;
+        uint8_t *vRowPtr = clientBuffer->data() + vPlane.mOffset;
+        for (int32_t row = 0; row < kHeight; ++row) {
+            uint8_t *yPtr = yRowPtr;
+            uint8_t *uPtr = uRowPtr;
+            uint8_t *vPtr = vRowPtr;
+            for (int32_t col = 0; col < kWidth; ++col) {
+                ASSERT_EQ((row + col) & 0xFF, *yPtr);
+                yPtr += yPlane.mColInc;
+                if (row < kHeight / 2 && col < kWidth / 2) {
+                    ASSERT_EQ((row + col + 1) & 0xFF, *uPtr);
+                    ASSERT_EQ((row + col + 2) & 0xFF, *vPtr);
+                    uPtr += uPlane.mColInc;
+                    vPtr += vPlane.mColInc;
+                }
+            }
+            yRowPtr += yPlane.mRowInc;
+            if (row < kHeight / 2) {
+                uRowPtr += uPlane.mRowInc;
+                vRowPtr += vPlane.mRowInc;
+            }
+        }
+    }
+}
+
+TEST(RawGraphicOutputBuffersTest, P010ColorFormat) {
+    constexpr int32_t kWidth = 320;
+    constexpr int32_t kHeight = 240;
+
+    std::shared_ptr<RawGraphicOutputBuffers> buffers =
+        std::make_shared<RawGraphicOutputBuffers>("test P010");
+
+    sp<AMessage> format{new AMessage};
+    format->setInt32(KEY_WIDTH, kWidth);
+    format->setInt32(KEY_HEIGHT, kHeight);
+    format->setInt32(KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+    int32_t fwkPixelFormat = 0;
+    if (C2Mapper::mapPixelFormatCodecToFramework(HAL_PIXEL_FORMAT_YCBCR_P010, &fwkPixelFormat)) {
+        format->setInt32("android._color-format", fwkPixelFormat);
+    }
+    buffers->setFormat(format);
+
+    std::shared_ptr<C2BlockPool> pool;
+    ASSERT_EQ(OK, GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool));
+
+    std::shared_ptr<C2GraphicBlock> block;
+    c2_status_t err = pool->fetchGraphicBlock(
+            kWidth, kHeight, HAL_PIXEL_FORMAT_YCBCR_P010,
+            C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+    if (err != C2_OK) {
+        GTEST_SKIP();
+    }
+
+    {
+        C2GraphicView view = block->map().get();
+        C2PlanarLayout layout = view.layout();
+
+        // Verify the block is in YUV420 format
+        ASSERT_EQ(C2PlanarLayout::TYPE_YUV, layout.type);
+        ASSERT_EQ(3u, layout.numPlanes);
+        const C2PlaneInfo& yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
+        const C2PlaneInfo& uPlane = layout.planes[C2PlanarLayout::PLANE_U];
+        const C2PlaneInfo& vPlane = layout.planes[C2PlanarLayout::PLANE_V];
+
+        // Y plane
+        ASSERT_EQ(1u, yPlane.colSampling);
+        ASSERT_EQ(1u, yPlane.rowSampling);
+        ASSERT_EQ(16u, yPlane.allocatedDepth);
+        ASSERT_EQ(10u, yPlane.bitDepth);
+        ASSERT_EQ(6u, yPlane.rightShift);
+
+        // U plane
+        ASSERT_EQ(2u, uPlane.colSampling);
+        ASSERT_EQ(2u, uPlane.rowSampling);
+        ASSERT_EQ(16u, uPlane.allocatedDepth);
+        ASSERT_EQ(10u, uPlane.bitDepth);
+        ASSERT_EQ(6u, uPlane.rightShift);
+
+        // V plane
+        ASSERT_EQ(2u, vPlane.colSampling);
+        ASSERT_EQ(2u, vPlane.rowSampling);
+        ASSERT_EQ(16u, vPlane.allocatedDepth);
+        ASSERT_EQ(10u, vPlane.bitDepth);
+        ASSERT_EQ(6u, vPlane.rightShift);
+
+        uint8_t *yRowPtr = view.data()[C2PlanarLayout::PLANE_Y];
+        uint8_t *uRowPtr = view.data()[C2PlanarLayout::PLANE_U];
+        uint8_t *vRowPtr = view.data()[C2PlanarLayout::PLANE_V];
+        for (int32_t row = 0; row < kHeight; ++row) {
+            uint8_t *yPtr = yRowPtr;
+            uint8_t *uPtr = uRowPtr;
+            uint8_t *vPtr = vRowPtr;
+            for (int32_t col = 0; col < kWidth; ++col) {
+                yPtr[0] = ((row + col) & 0x3) << 6;
+                yPtr[1] = ((row + col) & 0x3FC) >> 2;
+                yPtr += yPlane.colInc;
+
+                if (row < kHeight / 2 && col < kWidth / 2) {
+                    uPtr[0] = ((row + col + 1) & 0x3) << 6;
+                    uPtr[1] = ((row + col + 1) & 0x3FC) >> 2;
+                    vPtr[0] = ((row + col + 2) & 0x3) << 6;
+                    vPtr[1] = ((row + col + 2) & 0x3FC) >> 2;
+                    uPtr += uPlane.colInc;
+                    vPtr += vPlane.colInc;
+                }
+            }
+            yRowPtr += yPlane.rowInc;
+            if (row < kHeight / 2) {
+                uRowPtr += uPlane.rowInc;
+                vRowPtr += vPlane.rowInc;
+            }
+        }
+    }
+
+    std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateGraphicBuffer(block->share(
+            block->crop(), C2Fence{}));
+    size_t index;
+    sp<MediaCodecBuffer> clientBuffer;
+    ASSERT_EQ(OK, buffers->registerBuffer(c2Buffer, &index, &clientBuffer));
+    ASSERT_NE(nullptr, clientBuffer);
+    sp<ABuffer> imageData;
+    ASSERT_TRUE(clientBuffer->format()->findBuffer("image-data", &imageData));
+    MediaImage2 *img = (MediaImage2 *)imageData->data();
+    ASSERT_EQ(MediaImage2::MEDIA_IMAGE_TYPE_YUV, img->mType);
+    ASSERT_EQ(3u, img->mNumPlanes);
+    ASSERT_EQ(kWidth, img->mWidth);
+    ASSERT_EQ(kHeight, img->mHeight);
+    ASSERT_EQ(10u, img->mBitDepth);
+    ASSERT_EQ(16u, img->mBitDepthAllocated);
+    const MediaImage2::PlaneInfo &yPlane = img->mPlane[MediaImage2::Y];
+    const MediaImage2::PlaneInfo &uPlane = img->mPlane[MediaImage2::U];
+    const MediaImage2::PlaneInfo &vPlane = img->mPlane[MediaImage2::V];
+    ASSERT_EQ(1u, yPlane.mHorizSubsampling);
+    ASSERT_EQ(1u, yPlane.mVertSubsampling);
+    ASSERT_EQ(2u, uPlane.mHorizSubsampling);
+    ASSERT_EQ(2u, uPlane.mVertSubsampling);
+    ASSERT_EQ(2u, vPlane.mHorizSubsampling);
+    ASSERT_EQ(2u, vPlane.mVertSubsampling);
+
+    uint8_t *yRowPtr = clientBuffer->data() + yPlane.mOffset;
+    uint8_t *uRowPtr = clientBuffer->data() + uPlane.mOffset;
+    uint8_t *vRowPtr = clientBuffer->data() + vPlane.mOffset;
+    for (int32_t row = 0; row < kHeight; ++row) {
+        uint8_t *yPtr = yRowPtr;
+        uint8_t *uPtr = uRowPtr;
+        uint8_t *vPtr = vRowPtr;
+        for (int32_t col = 0; col < kWidth; ++col) {
+            ASSERT_EQ(((row + col) & 0x3) << 6, yPtr[0]);
+            ASSERT_EQ(((row + col) & 0x3FC) >> 2, yPtr[1]);
+            yPtr += yPlane.mColInc;
+            if (row < kHeight / 2 && col < kWidth / 2) {
+                ASSERT_EQ(((row + col + 1) & 0x3) << 6, uPtr[0]);
+                ASSERT_EQ(((row + col + 1) & 0x3FC) >> 2, uPtr[1]);
+                ASSERT_EQ(((row + col + 2) & 0x3) << 6, vPtr[0]);
+                ASSERT_EQ(((row + col + 2) & 0x3FC) >> 2, vPtr[1]);
+                uPtr += uPlane.mColInc;
+                vPtr += vPlane.mColInc;
+            }
+        }
+        yRowPtr += yPlane.mRowInc;
+        if (row < kHeight / 2) {
+            uRowPtr += uPlane.mRowInc;
+            vRowPtr += vPlane.mRowInc;
+        }
+    }
+}
+
 class TestGraphicAllocation : public C2GraphicAllocation {
 public:
     TestGraphicAllocation(
@@ -407,7 +720,6 @@
                 }
             }
         }
-
         size_t yPlaneSize = stride * kHeight;
         size_t uvPlaneSize = stride * kHeight / 4;
         size_t capacity = yPlaneSize + uvPlaneSize * 2;
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 903db6c..1390642 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -958,17 +958,16 @@
             *c2Value = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
             return true;
         case COLOR_FormatYUV420Flexible:
-            *c2Value = HAL_PIXEL_FORMAT_YCBCR_420_888;
-            return true;
         case COLOR_FormatYUV420Planar:
         case COLOR_FormatYUV420SemiPlanar:
         case COLOR_FormatYUV420PackedPlanar:
         case COLOR_FormatYUV420PackedSemiPlanar:
-            *c2Value = HAL_PIXEL_FORMAT_YV12;
+            *c2Value = HAL_PIXEL_FORMAT_YCBCR_420_888;
             return true;
         default:
-            // TODO: support some sort of passthrough
-            return false;
+            // Passthrough
+            *c2Value = uint32_t(frameworkValue);
+            return true;
     }
 }
 
@@ -979,11 +978,16 @@
         case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
             *frameworkValue = COLOR_FormatSurface;
             return true;
-        case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_YCBCR_422_SP:
+        case HAL_PIXEL_FORMAT_YCRCB_420_SP:
+        case HAL_PIXEL_FORMAT_YCBCR_422_I:
         case HAL_PIXEL_FORMAT_YCBCR_420_888:
+        case HAL_PIXEL_FORMAT_YV12:
             *frameworkValue = COLOR_FormatYUV420Flexible;
             return true;
         default:
-            return false;
+            // Passthrough
+            *frameworkValue = int32_t(c2Value);
+            return true;
     }
 }
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 59471a2..8e59df1 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -532,11 +532,15 @@
             break;
         }
 
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
+            // fall-through
         case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
             // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YV12):
-            // fall-through
-        default: {
+        case static_cast<uint32_t>(PixelFormat4::YV12): {
             android_ycbcr ycbcrLayout;
 
             status_t err = GraphicBufferMapper::get().lockYCbCr(
@@ -604,6 +608,158 @@
             }
             break;
         }
+
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
+            void *pointer = nullptr;
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(YCBCR_P010)");
+                return C2_CORRUPTED;
+            }
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + mStride * 2 * rect.height();
+            addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
+            layout->type = C2PlanarLayout::TYPE_YUV;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                2,                              // colInc
+                static_cast<int32_t>(2 * mStride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,        // channel
+                4,                              // colInc
+                static_cast<int32_t>(2 * mStride), // rowInc
+                2,                              // mColSampling
+                2,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_U,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,        // channel
+                4,                              // colInc
+                static_cast<int32_t>(2 * mStride), // rowInc
+                2,                              // mColSampling
+                2,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_U,        // rootIx
+                2,                              // offset
+            };
+            break;
+        }
+
+        default: {
+            // We don't know what it is, but let's try to lock it.
+            android_ycbcr ycbcrLayout;
+
+            status_t err = GraphicBufferMapper::get().lockYCbCr(
+                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
+            if (err == OK) {
+                addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+                addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+                addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+                layout->type = C2PlanarLayout::TYPE_YUV;
+                layout->numPlanes = 3;
+                layout->rootPlanes = 3;
+                layout->planes[C2PlanarLayout::PLANE_Y] = {
+                    C2PlaneInfo::CHANNEL_Y,         // channel
+                    1,                              // colInc
+                    (int32_t)ycbcrLayout.ystride,   // rowInc
+                    1,                              // mColSampling
+                    1,                              // mRowSampling
+                    8,                              // allocatedDepth
+                    8,                              // bitDepth
+                    0,                              // rightShift
+                    C2PlaneInfo::NATIVE,            // endianness
+                    C2PlanarLayout::PLANE_Y,        // rootIx
+                    0,                              // offset
+                };
+                layout->planes[C2PlanarLayout::PLANE_U] = {
+                    C2PlaneInfo::CHANNEL_CB,          // channel
+                    (int32_t)ycbcrLayout.chroma_step, // colInc
+                    (int32_t)ycbcrLayout.cstride,     // rowInc
+                    2,                                // mColSampling
+                    2,                                // mRowSampling
+                    8,                                // allocatedDepth
+                    8,                                // bitDepth
+                    0,                                // rightShift
+                    C2PlaneInfo::NATIVE,              // endianness
+                    C2PlanarLayout::PLANE_U,          // rootIx
+                    0,                                // offset
+                };
+                layout->planes[C2PlanarLayout::PLANE_V] = {
+                    C2PlaneInfo::CHANNEL_CR,          // channel
+                    (int32_t)ycbcrLayout.chroma_step, // colInc
+                    (int32_t)ycbcrLayout.cstride,     // rowInc
+                    2,                                // mColSampling
+                    2,                                // mRowSampling
+                    8,                                // allocatedDepth
+                    8,                                // bitDepth
+                    0,                                // rightShift
+                    C2PlaneInfo::NATIVE,              // endianness
+                    C2PlanarLayout::PLANE_V,          // rootIx
+                    0,                                // offset
+                };
+                // handle interleaved formats
+                intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+                if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chroma_step) {
+                    layout->rootPlanes = 2;
+                    layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+                    layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+                } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chroma_step) {
+                    layout->rootPlanes = 2;
+                    layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+                    layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+                }
+                break;
+            }
+
+            // We really don't know what this is; lock the buffer and pass it through ---
+            // the client may know how to interpret it.
+            void *pointer = nullptr;
+            err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(??? %x)", mFormat);
+                return C2_CORRUPTED;
+            }
+            addr[0] = (uint8_t *)pointer;
+            layout->type = C2PlanarLayout::TYPE_UNKNOWN;
+            layout->numPlanes = 1;
+            layout->rootPlanes = 1;
+            layout->planes[0] = {
+                // TODO: CHANNEL_UNKNOWN?
+                C2PlaneInfo::channel_t(0xFF),   // channel
+                1,                              // colInc
+                int32_t(mStride),               // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                0,                              // rootIx
+                0,                              // offset
+            };
+            break;
+        }
     }
     mLocked = true;
 
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 74ef9ea..c07c09e 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -445,7 +445,7 @@
 
     c2_status_t _createBlockPool(
             C2PlatformAllocatorStore::id_t allocatorId,
-            std::shared_ptr<const C2Component> component,
+            std::vector<std::shared_ptr<const C2Component>> components,
             C2BlockPool::local_id_t poolId,
             std::shared_ptr<C2BlockPool> *pool) {
         std::shared_ptr<C2AllocatorStore> allocatorStore =
@@ -466,7 +466,9 @@
                                     allocator, poolId);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
-                    mComponents[poolId] = component;
+                    mComponents[poolId].insert(
+                           mComponents[poolId].end(),
+                           components.begin(), components.end());
                 }
                 break;
             case C2PlatformAllocatorStore::BLOB:
@@ -478,7 +480,9 @@
                                     allocator, poolId);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
-                    mComponents[poolId] = component;
+                    mComponents[poolId].insert(
+                           mComponents[poolId].end(),
+                           components.begin(), components.end());
                 }
                 break;
             case C2PlatformAllocatorStore::GRALLOC:
@@ -490,7 +494,9 @@
                         std::make_shared<C2PooledBlockPool>(allocator, poolId);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
-                    mComponents[poolId] = component;
+                    mComponents[poolId].insert(
+                           mComponents[poolId].end(),
+                           components.begin(), components.end());
                 }
                 break;
             case C2PlatformAllocatorStore::BUFFERQUEUE:
@@ -502,7 +508,9 @@
                                     allocator, poolId);
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
-                    mComponents[poolId] = component;
+                    mComponents[poolId].insert(
+                           mComponents[poolId].end(),
+                           components.begin(), components.end());
                 }
                 break;
             default:
@@ -513,7 +521,9 @@
                 if (res == C2_OK) {
                     *pool = ptr;
                     mBlockPools[poolId] = ptr;
-                    mComponents[poolId] = component;
+                    mComponents[poolId].insert(
+                           mComponents[poolId].end(),
+                           components.begin(), components.end());
                 }
                 break;
         }
@@ -522,9 +532,9 @@
 
     c2_status_t createBlockPool(
             C2PlatformAllocatorStore::id_t allocatorId,
-            std::shared_ptr<const C2Component> component,
+            std::vector<std::shared_ptr<const C2Component>> components,
             std::shared_ptr<C2BlockPool> *pool) {
-        return _createBlockPool(allocatorId, component, mBlockPoolSeqId++, pool);
+        return _createBlockPool(allocatorId, components, mBlockPoolSeqId++, pool);
     }
 
     bool getBlockPool(
@@ -540,8 +550,13 @@
                 mBlockPools.erase(it);
                 mComponents.erase(blockPoolId);
             } else {
-                auto found = mComponents.find(blockPoolId);
-                if (component == found->second.lock()) {
+                auto found = std::find_if(
+                        mComponents[blockPoolId].begin(),
+                        mComponents[blockPoolId].end(),
+                        [component](const std::weak_ptr<const C2Component> &ptr) {
+                            return component == ptr.lock();
+                        });
+                if (found != mComponents[blockPoolId].end()) {
                     *pool = ptr;
                     return true;
                 }
@@ -554,7 +569,7 @@
     C2BlockPool::local_id_t mBlockPoolSeqId;
 
     std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
-    std::map<C2BlockPool::local_id_t, std::weak_ptr<const C2Component>> mComponents;
+    std::map<C2BlockPool::local_id_t, std::vector<std::weak_ptr<const C2Component>>> mComponents;
 };
 
 static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
@@ -594,7 +609,7 @@
     // TODO: remove this. this is temporary
     case C2BlockPool::PLATFORM_START:
         res = sBlockPoolCache->_createBlockPool(
-                C2PlatformAllocatorStore::BUFFERQUEUE, component, id, pool);
+                C2PlatformAllocatorStore::BUFFERQUEUE, {component}, id, pool);
         break;
     default:
         break;
@@ -604,12 +619,22 @@
 
 c2_status_t CreateCodec2BlockPool(
         C2PlatformAllocatorStore::id_t allocatorId,
+        const std::vector<std::shared_ptr<const C2Component>> &components,
+        std::shared_ptr<C2BlockPool> *pool) {
+    pool->reset();
+
+    std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
+    return sBlockPoolCache->createBlockPool(allocatorId, components, pool);
+}
+
+c2_status_t CreateCodec2BlockPool(
+        C2PlatformAllocatorStore::id_t allocatorId,
         std::shared_ptr<const C2Component> component,
         std::shared_ptr<C2BlockPool> *pool) {
     pool->reset();
 
     std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
-    return sBlockPoolCache->createBlockPool(allocatorId, component, pool);
+    return sBlockPoolCache->createBlockPool(allocatorId, {component}, pool);
 }
 
 class C2PlatformComponentStore : public C2ComponentStore {
@@ -957,58 +982,10 @@
 
     std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
     if (traits) {
-        traits->name = intf->getName();
-
-        C2ComponentKindSetting kind;
-        C2ComponentDomainSetting domain;
-        res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
-        bool fixDomain = res != C2_OK;
-        if (res == C2_OK) {
-            traits->kind = kind.value;
-            traits->domain = domain.value;
-        } else {
-            // TODO: remove this fall-back
-            ALOGD("failed to query interface for kind and domain: %d", res);
-
-            traits->kind =
-                (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
-                (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
-                C2Component::KIND_OTHER;
-        }
-
-        uint32_t mediaTypeIndex =
-                traits->kind == C2Component::KIND_ENCODER ? C2PortMediaTypeSetting::output::PARAM_TYPE
-                : C2PortMediaTypeSetting::input::PARAM_TYPE;
-        std::vector<std::unique_ptr<C2Param>> params;
-        res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
-        if (res != C2_OK) {
-            ALOGD("failed to query interface: %d", res);
+        if (!C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf)) {
+            ALOGD("Failed to fill traits from interface");
             return mInit;
         }
-        if (params.size() != 1u) {
-            ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
-            return mInit;
-        }
-        C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
-        if (mediaTypeConfig == nullptr) {
-            ALOGD("failed to query media type");
-            return mInit;
-        }
-        traits->mediaType =
-            std::string(mediaTypeConfig->m.value,
-                        strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
-
-        if (fixDomain) {
-            if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
-                traits->domain = C2Component::DOMAIN_AUDIO;
-            } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
-                traits->domain = C2Component::DOMAIN_VIDEO;
-            } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
-                traits->domain = C2Component::DOMAIN_IMAGE;
-            } else {
-                traits->domain = C2Component::DOMAIN_OTHER;
-            }
-        }
 
         // TODO: get this properly from the store during emplace
         switch (traits->domain) {
@@ -1018,26 +995,6 @@
         default:
             traits->rank = 512;
         }
-
-        params.clear();
-        res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, &params);
-        if (res == C2_OK && params.size() == 1u) {
-            C2ComponentAliasesSetting *aliasesSetting =
-                C2ComponentAliasesSetting::From(params[0].get());
-            if (aliasesSetting) {
-                // Split aliases on ','
-                // This looks simpler in plain C and even std::string would still make a copy.
-                char *aliases = ::strndup(aliasesSetting->m.value, aliasesSetting->flexCount());
-                ALOGD("'%s' has aliases: '%s'", intf->getName().c_str(), aliases);
-
-                for (char *tok, *ptr, *str = aliases; (tok = ::strtok_r(str, ",", &ptr));
-                        str = nullptr) {
-                    traits->aliases.push_back(tok);
-                    ALOGD("adding alias: '%s'", tok);
-                }
-                free(aliases);
-            }
-        }
     }
     mTraits = traits;
 
diff --git a/media/codec2/vndk/include/C2PlatformSupport.h b/media/codec2/vndk/include/C2PlatformSupport.h
index 6d351c2..dc82e82 100644
--- a/media/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/codec2/vndk/include/C2PlatformSupport.h
@@ -138,6 +138,23 @@
         std::shared_ptr<C2BlockPool> *pool);
 
 /**
+ * Creates a block pool.
+ * \param allocatorId  the allocator ID which is used to allocate blocks
+ * \param components    the components using the block pool
+ * \param pool          pointer to where the created block pool shall be store on success.
+ *                      nullptr will be stored here on failure
+ *
+ * \retval C2_OK        the operation was successful
+ * \retval C2_BAD_VALUE the component is null
+ * \retval C2_NOT_FOUND if the allocator does not exist
+ * \retval C2_NO_MEMORY not enough memory to create a block pool
+ */
+c2_status_t CreateCodec2BlockPool(
+        C2PlatformAllocatorStore::id_t allocatorId,
+        const std::vector<std::shared_ptr<const C2Component>> &components,
+        std::shared_ptr<C2BlockPool> *pool);
+
+/**
  * Returns the platform component store.
  * \retval nullptr if the platform component store could not be obtained
  */
diff --git a/media/codec2/vndk/include/util/C2InterfaceUtils.h b/media/codec2/vndk/include/util/C2InterfaceUtils.h
index e9037e5..13bdac3 100644
--- a/media/codec2/vndk/include/util/C2InterfaceUtils.h
+++ b/media/codec2/vndk/include/util/C2InterfaceUtils.h
@@ -17,6 +17,7 @@
 #ifndef C2UTILS_INTERFACE_UTILS_H_
 #define C2UTILS_INTERFACE_UTILS_H_
 
+#include <C2Component.h>
 #include <C2Param.h>
 #include <C2Work.h>
 
@@ -1130,6 +1131,19 @@
 
 };
 
+/**
+ * Utility class for C2ComponentInterface
+ */
+struct C2InterfaceUtils {
+    /**
+     * Create traits from C2ComponentInterface. Note that rank cannot be queried from interfaces,
+     * so left untouched.
+     */
+    static bool FillTraitsFromInterface(
+            C2Component::Traits *traits,
+            const std::shared_ptr<C2ComponentInterface> &intf);
+};
+
 #include <util/C2Debug-interface.h>
 
 #endif  // C2UTILS_INTERFACE_UTILS_H_
diff --git a/media/codec2/vndk/util/C2InterfaceHelper.cpp b/media/codec2/vndk/util/C2InterfaceHelper.cpp
index 9eb52d2..19d2295 100644
--- a/media/codec2/vndk/util/C2InterfaceHelper.cpp
+++ b/media/codec2/vndk/util/C2InterfaceHelper.cpp
@@ -645,6 +645,7 @@
                     lateReadParams.emplace_back(p);
                     std::unique_ptr<C2Param> request(C2Param::CopyAsRequest(*p));
                     p = request.get();
+                    paramIx = p->index();
                     paramRequests.emplace_back(std::move(request));
                 }
             }
diff --git a/media/codec2/vndk/util/C2InterfaceUtils.cpp b/media/codec2/vndk/util/C2InterfaceUtils.cpp
index 0c1729b..b5bc691 100644
--- a/media/codec2/vndk/util/C2InterfaceUtils.cpp
+++ b/media/codec2/vndk/util/C2InterfaceUtils.cpp
@@ -21,6 +21,7 @@
 
 #define C2_LOG_VERBOSE
 
+#include <C2Config.h>
 #include <C2Debug.h>
 #include <C2Param.h>
 #include <C2ParamDef.h>
@@ -30,6 +31,7 @@
 #include <cmath>
 #include <limits>
 #include <map>
+#include <sstream>
 #include <type_traits>
 
 #include <android-base/stringprintf.h>
@@ -1304,3 +1306,81 @@
     return std::vector<Info>(location.begin(), location.end());
 }
 
+//static
+bool C2InterfaceUtils::FillTraitsFromInterface(
+        C2Component::Traits *traits,
+        const std::shared_ptr<C2ComponentInterface> &intf) {
+    if (!traits) {
+        return false;
+    }
+    traits->name = intf->getName();
+
+    C2ComponentKindSetting kind;
+    C2ComponentDomainSetting domain;
+    c2_status_t res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
+    bool fixDomain = res != C2_OK;
+    if (res == C2_OK) {
+        traits->kind = kind.value;
+        traits->domain = domain.value;
+    } else {
+        // TODO: remove this fall-back
+        C2_LOG(DEBUG) << "failed to query interface for kind and domain: " << res;
+
+        traits->kind =
+            (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
+            (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
+            C2Component::KIND_OTHER;
+    }
+
+    uint32_t mediaTypeIndex = traits->kind == C2Component::KIND_ENCODER
+            ? C2PortMediaTypeSetting::output::PARAM_TYPE
+            : C2PortMediaTypeSetting::input::PARAM_TYPE;
+    std::vector<std::unique_ptr<C2Param>> params;
+    res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
+    if (res != C2_OK) {
+        C2_LOG(DEBUG) << "failed to query interface: " << res;
+        return false;
+    }
+    if (params.size() != 1u) {
+        C2_LOG(DEBUG) << "failed to query interface: unexpected vector size: " << params.size();
+        return false;
+    }
+    C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
+    if (mediaTypeConfig == nullptr) {
+        C2_LOG(DEBUG) << "failed to query media type";
+        return false;
+    }
+    traits->mediaType =
+        std::string(mediaTypeConfig->m.value,
+                    strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
+
+    if (fixDomain) {
+        if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
+            traits->domain = C2Component::DOMAIN_AUDIO;
+        } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
+            traits->domain = C2Component::DOMAIN_VIDEO;
+        } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
+            traits->domain = C2Component::DOMAIN_IMAGE;
+        } else {
+            traits->domain = C2Component::DOMAIN_OTHER;
+        }
+    }
+
+    params.clear();
+    res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, &params);
+    if (res == C2_OK && params.size() == 1u) {
+        C2ComponentAliasesSetting *aliasesSetting =
+            C2ComponentAliasesSetting::From(params[0].get());
+        if (aliasesSetting) {
+            std::istringstream iss(
+                    std::string(aliasesSetting->m.value, aliasesSetting->flexCount()));
+            C2_LOG(DEBUG) << intf->getName() << " has aliases: " << iss.str();
+
+            for (std::string tok; std::getline(iss, tok, ','); ) {
+                traits->aliases.push_back(tok);
+                C2_LOG(DEBUG) << "adding alias: " << tok;
+            }
+        }
+    }
+    return true;
+}
diff --git a/media/codecs/amrnb/enc/src/pitch_fr.cpp b/media/codecs/amrnb/enc/src/pitch_fr.cpp
index 5a846fa..584f79b 100644
--- a/media/codecs/amrnb/enc/src/pitch_fr.cpp
+++ b/media/codecs/amrnb/enc/src/pitch_fr.cpp
@@ -570,12 +570,14 @@
     Word16 corr[],     /* i   : normalized correlation  */
     Word16 flag3,      /* i   : subsample resolution
                                 (3: =1 / 6: =0)         */
-    Flag   *pOverflow
+    Flag   *pOverflow,
+    enum Mode mode
 )
 {
     Word16 i;
     Word16 max;
     Word16 corr_int;
+    Word16 minPitch;
 
     /* Test the fractions around T0 and choose the one which maximizes   */
     /* the interpolated normalized correlation.                          */
@@ -593,14 +595,22 @@
         }
     }
 
+    minPitch = (mode == MR122) ? PIT_MIN_MR122 : PIT_MIN;
     if (flag3 == 0)
     {
         /* Limit the fraction value in the interval [-2,-1,0,1,2,3] */
 
         if (*frac == -3)
         {
-            *frac = 3;
-            (*lag)--;
+            if (*lag > minPitch)
+            {
+                *frac = 3;
+                (*lag)--;
+            }
+            else
+            {
+                *frac = -2;
+            }
         }
     }
     else
@@ -609,13 +619,27 @@
 
         if (*frac == -2)
         {
-            *frac = 1;
-            (*lag)--;
+            if (*lag > minPitch)
+            {
+                *frac = 1;
+                (*lag)--;
+            }
+            else
+            {
+                *frac = -1;
+            }
         }
-        if (*frac == 2)
+        else if (*frac == 2)
         {
-            *frac = -1;
-            (*lag)++;
+            if (*lag < PIT_MAX)
+            {
+                *frac = -1;
+                (*lag)++;
+            }
+            else
+            {
+                *frac = 1;
+            }
         }
     }
 }
@@ -1533,20 +1557,20 @@
 
                 /* normal search in fractions around T0 */
 
-                searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow);
+                searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode);
 
             }
             else if (lag == (tmp_lag - 2))
             {
                 /* limit search around T0 to the right side */
                 frac = 0;
-                searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow);
+                searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode);
             }
             else if (lag == (tmp_lag + 1))
             {
                 /* limit search around T0 to the left side */
                 last_frac = 0;
-                searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow);
+                searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode);
             }
             else
             {
@@ -1556,7 +1580,7 @@
         }
         else
             /* test the fractions around T0 */
-            searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow);
+            searchFrac(&lag, &frac, last_frac, corr, flag3, pOverflow, mode);
     }
 
     /*-----------------------------------------------------------------------*
diff --git a/media/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/codecs/mp3dec/src/pvmp3_framedecoder.cpp
index 15d2feb..5cf1ed3 100644
--- a/media/codecs/mp3dec/src/pvmp3_framedecoder.cpp
+++ b/media/codecs/mp3dec/src/pvmp3_framedecoder.cpp
@@ -598,18 +598,10 @@
         }
         else
         {
-            int32 tmp1 = *(ptr++);
-            for (int32 nBytes = temp >> 1; nBytes != 0; nBytes--)  /* read main data. */
+            for (int32 nBytes = temp; nBytes != 0; nBytes--)  /* read main data. */
             {
-                int32 tmp2 = *(ptr++);
-                fillDataBuf(&pVars->mainDataStream, tmp1);
-                fillDataBuf(&pVars->mainDataStream, tmp2);
-                tmp1 = *(ptr++);
-            }
-
-            if (temp&1)
-            {
-                fillDataBuf(&pVars->mainDataStream, tmp1);
+                int32 tmp = *(ptr++);
+                fillDataBuf(&pVars->mainDataStream, tmp);
             }
 
             /* adjust circular buffer counter */
@@ -618,14 +610,9 @@
     }
     else
     {
-        for (int32 nBytes = temp >> 1; nBytes != 0; nBytes--)  /* read main data. */
+        for (int32 nBytes = temp; nBytes != 0; nBytes--)  /* read main data. */
         {
             fillDataBuf(&pVars->mainDataStream, *(pVars->inputStream.pBuffer + module(offset++  , BUFSIZE)));
-            fillDataBuf(&pVars->mainDataStream, *(pVars->inputStream.pBuffer + module(offset++  , BUFSIZE)));
-        }
-        if (temp&1)
-        {
-            fillDataBuf(&pVars->mainDataStream, *(pVars->inputStream.pBuffer + module(offset  , BUFSIZE)));
         }
     }
 
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 2593000..d1f92c1 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -1,6 +1,6 @@
 cc_library {
     name: "libflacextractor",
-    defaults: ["extractor-defaults"],
+    defaults: ["extractor-defaults", "libbinder_ndk_host_user"],
 
     srcs: ["FLACExtractor.cpp"],
 
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 85d4cce..6a0ef22 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -1,7 +1,7 @@
 cc_library {
     name: "libwavextractor",
 
-    defaults: ["extractor-defaults"],
+    defaults: ["extractor-defaults", "libbinder_ndk_host_user"],
 
     srcs: ["WAVExtractor.cpp"],
 
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 14578d6..74258a1 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1849,19 +1849,22 @@
 
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-
     media::Int numSurroundFormatsAidl;
     numSurroundFormatsAidl.value =
             VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*numSurroundFormats));
     std::vector<media::audio::common::AudioFormat> surroundFormatsAidl;
+    std::vector<bool> surroundFormatsEnabledAidl;
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            aps->getSurroundFormats(reported, &numSurroundFormatsAidl, &surroundFormatsAidl,
-                                    surroundFormatsEnabled)));
+            aps->getSurroundFormats(reported, &numSurroundFormatsAidl,
+                                    &surroundFormatsAidl, &surroundFormatsEnabledAidl)));
+
     *numSurroundFormats = VALUE_OR_RETURN_STATUS(
             convertIntegral<unsigned int>(numSurroundFormatsAidl.value));
     RETURN_STATUS_IF_ERROR(
             convertRange(surroundFormatsAidl.begin(), surroundFormatsAidl.end(), surroundFormats,
                          aidl2legacy_AudioFormat_audio_format_t));
+    std::copy(surroundFormatsEnabledAidl.begin(), surroundFormatsEnabledAidl.end(),
+            surroundFormatsEnabled);
     return OK;
 }
 
@@ -1994,7 +1997,8 @@
 }
 
 status_t AudioSystem::getProductStrategyFromAudioAttributes(const AudioAttributes& aa,
-                                                            product_strategy_t& productStrategy) {
+                                                            product_strategy_t& productStrategy,
+                                                            bool fallbackOnDefault) {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
 
@@ -2003,7 +2007,8 @@
     int32_t productStrategyAidl;
 
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            aps->getProductStrategyFromAudioAttributes(aaAidl, &productStrategyAidl)));
+            aps->getProductStrategyFromAudioAttributes(aaAidl, fallbackOnDefault,
+            &productStrategyAidl)));
     productStrategy = VALUE_OR_RETURN_STATUS(
             aidl2legacy_int32_t_product_strategy_t(productStrategyAidl));
     return OK;
@@ -2022,7 +2027,8 @@
 }
 
 status_t AudioSystem::getVolumeGroupFromAudioAttributes(const AudioAttributes& aa,
-                                                        volume_group_t& volumeGroup) {
+                                                        volume_group_t& volumeGroup,
+                                                        bool fallbackOnDefault) {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
 
@@ -2030,7 +2036,7 @@
             legacy2aidl_AudioAttributes_AudioAttributesEx(aa));
     int32_t volumeGroupAidl;
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
-            aps->getVolumeGroupFromAudioAttributes(aaAidl, &volumeGroupAidl)));
+            aps->getVolumeGroupFromAudioAttributes(aaAidl, fallbackOnDefault, &volumeGroupAidl)));
     volumeGroup = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_volume_group_t(volumeGroupAidl));
     return OK;
 }
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 75dfc36..89fad5a 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -272,16 +272,17 @@
     float getStreamVolumeDB(AudioStreamType stream, int index, int /* audio_devices_t */ device);
 
     /**
-     * Returns whether surround formats are enabled.
+     * Populates supported surround formats and their enabled state in formats and formatsEnabled.
      *
      * On input, count represents the maximum length of the returned array.
      * On output, count is the total number of elements, which may be larger than the array size.
      * Passing '0' on input and inspecting the value on output is a common way of determining the
      * number of elements without actually retrieving them.
      */
-    boolean getSurroundFormats(boolean reported,
-                               inout Int count,
-                               out AudioFormat[] formats);
+    void getSurroundFormats(boolean reported,
+                            inout Int count,
+                            out AudioFormat[] formats,
+                            out boolean[] formatsEnabled);
 
     AudioFormat[] getHwOffloadEncodingFormatsSupportedForA2DP();
 
@@ -296,10 +297,12 @@
     boolean isHapticPlaybackSupported();
 
     AudioProductStrategy[] listAudioProductStrategies();
-    int /* product_strategy_t */ getProductStrategyFromAudioAttributes(in AudioAttributesEx aa);
+    int /* product_strategy_t */ getProductStrategyFromAudioAttributes(in AudioAttributesEx aa,
+                                                                       boolean fallbackOnDefault);
 
     AudioVolumeGroup[] listAudioVolumeGroups();
-    int /* volume_group_t */ getVolumeGroupFromAudioAttributes(in AudioAttributesEx aa);
+    int /* volume_group_t */ getVolumeGroupFromAudioAttributes(in AudioAttributesEx aa,
+                                                               boolean fallbackOnDefault);
 
     void setRttEnabled(boolean enabled);
 
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index edfc5a5..a8eb385 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -21,7 +21,7 @@
     ],
     static_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "effect-aidl-unstable-cpp",
+        "effect-aidl-cpp",
         "libaudioclient",
         "libbase",
         "libcgrouprc",
@@ -33,16 +33,16 @@
         "libmediametricsservice",
         "libmedia_helper",
         "libprocessgroup",
-        "shared-file-region-aidl-unstable-cpp",
+        "shared-file-region-aidl-cpp",
     ],
     shared_libs: [
         "android.hardware.audio.common-util",
-        "audioclient-types-aidl-unstable-cpp",
-        "audioflinger-aidl-unstable-cpp",
-        "audiopolicy-aidl-unstable-cpp",
-        "audiopolicy-types-aidl-unstable-cpp",
-        "av-types-aidl-unstable-cpp",
-        "capture_state_listener-aidl-unstable-cpp",
+        "audioclient-types-aidl-cpp",
+        "audioflinger-aidl-cpp",
+        "audiopolicy-aidl-cpp",
+        "audiopolicy-types-aidl-cpp",
+        "av-types-aidl-cpp",
+        "capture_state_listener-aidl-cpp",
         "libaudioclient_aidl_conversion",
         "libaudioflinger",
         "libaudiofoundation",
@@ -55,7 +55,7 @@
         "libnblog",
         "libutils",
         "libxml2",
-        "mediametricsservice-aidl-unstable-cpp",
+        "mediametricsservice-aidl-cpp",
     ],
     header_libs: [
         "libaudiofoundation_headers",
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index db4c28f..694f2d0 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -428,16 +428,17 @@
     static bool     isHapticPlaybackSupported();
 
     static status_t listAudioProductStrategies(AudioProductStrategyVector &strategies);
-    static status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
-                                                        product_strategy_t &productStrategy);
+    static status_t getProductStrategyFromAudioAttributes(
+            const AudioAttributes &aa, product_strategy_t &productStrategy,
+            bool fallbackOnDefault = true);
 
     static audio_attributes_t streamTypeToAttributes(audio_stream_type_t stream);
     static audio_stream_type_t attributesToStreamType(const audio_attributes_t &attr);
 
     static status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups);
 
-    static status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
-                                                      volume_group_t &volumeGroup);
+    static status_t getVolumeGroupFromAudioAttributes(
+            const AudioAttributes &aa, volume_group_t &volumeGroup, bool fallbackOnDefault = true);
 
     static status_t setRttEnabled(bool enabled);
 
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index a8fbe58..b9a3e29 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -265,6 +265,10 @@
     (void)outputDevice;
     (void)outputDeviceAddress;
 #else
+#if MAJOR_VERSION >= 7
+    (void)HidlUtils::audioChannelMaskFromHal(
+            AUDIO_CHANNEL_NONE, true /*isInput*/, &sinkMetadata.tracks[0].channelMask);
+#endif
     if (outputDevice != AUDIO_DEVICE_NONE) {
         DeviceAddress hidlOutputDevice;
         if (status_t status = CoreUtils::deviceAddressFromHal(
diff --git a/media/libeffects/lvm/benchmarks/Android.bp b/media/libeffects/lvm/benchmarks/Android.bp
index 930292f..4f11a8a 100644
--- a/media/libeffects/lvm/benchmarks/Android.bp
+++ b/media/libeffects/lvm/benchmarks/Android.bp
@@ -1,6 +1,7 @@
 cc_benchmark {
     name: "lvm_benchmark",
     vendor: true,
+    host_supported: true,
     srcs: ["lvm_benchmark.cpp"],
     static_libs: [
         "libbundlewrapper",
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index 0ac9aa3..73c913b 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -9,6 +9,7 @@
     },
 
     vendor: true,
+    host_supported: true,
     srcs: [
         "StereoWidening/src/LVCS_BypassMix.cpp",
         "StereoWidening/src/LVCS_Control.cpp",
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index f96928b..bcbe3e6 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -9,6 +9,7 @@
     },
 
     vendor: true,
+    host_supported: true,
     srcs: ["Bundle/EffectBundle.cpp"],
 
     cppflags: [
@@ -25,7 +26,6 @@
     shared_libs: [
         "libaudioutils",
         "libcutils",
-        "libdl",
         "liblog",
     ],
 
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 865baad..c9d41ba 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -166,8 +166,8 @@
 
 /* Effect Library Interface Implementation */
 
-extern "C" int EffectCreate(const effect_uuid_t* uuid, int32_t sessionId, int32_t ioId __unused,
-                            effect_handle_t* pHandle) {
+extern "C" int EffectCreate(const effect_uuid_t* uuid, int32_t sessionId,
+                            int32_t /* ioId __unused */, effect_handle_t* pHandle) {
     int ret = 0;
     int sessionNo = -1;
     int i;
@@ -1354,7 +1354,8 @@
 //
 //----------------------------------------------------------------------------
 void VirtualizerGetSpeakerAngles(audio_channel_mask_t channelMask,
-                                 audio_devices_t deviceType __unused, int32_t* pSpeakerAngles) {
+                                 audio_devices_t /* deviceType __unused */,
+                                 int32_t* pSpeakerAngles) {
     // the channel count is guaranteed to be 1 or 2
     // the device is guaranteed to be of type headphone
     // this virtualizer is always using 2 virtual speakers at -90 and 90deg of azimuth, 0deg of
@@ -1495,8 +1496,8 @@
 //  pLow:       lower band range
 //  pLow:       upper band range
 //----------------------------------------------------------------------------
-int32_t EqualizerGetBandFreqRange(EffectContext* pContext __unused, int32_t band, uint32_t* pLow,
-                                  uint32_t* pHi) {
+int32_t EqualizerGetBandFreqRange(EffectContext* /* pContext __unused */, int32_t band,
+                                  uint32_t* pLow, uint32_t* pHi) {
     *pLow = bandFreqRange[band][0];
     *pHi = bandFreqRange[band][1];
     return 0;
@@ -1519,7 +1520,7 @@
 //  pLow:       lower band range
 //  pLow:       upper band range
 //----------------------------------------------------------------------------
-int32_t EqualizerGetBand(EffectContext* pContext __unused, uint32_t targetFreq) {
+int32_t EqualizerGetBand(EffectContext* /* pContext __unused */, uint32_t targetFreq) {
     int band = 0;
 
     if (targetFreq < bandFreqRange[0][0]) {
diff --git a/media/libeffects/preprocessing/tests/Android.bp b/media/libeffects/preprocessing/tests/Android.bp
index 5e8255a..ff897e8 100644
--- a/media/libeffects/preprocessing/tests/Android.bp
+++ b/media/libeffects/preprocessing/tests/Android.bp
@@ -18,6 +18,7 @@
         "libaudioeffects",
         "libhardware_headers",
     ],
+    gtest: false,
 }
 
 cc_test {
@@ -29,4 +30,5 @@
         "-Werror",
         "-Wextra",
     ],
+    gtest: false,
 }
diff --git a/media/libeffects/preprocessing/tests/correlation.cpp b/media/libeffects/preprocessing/tests/correlation.cpp
index b13dcc7..eb56fc3 100644
--- a/media/libeffects/preprocessing/tests/correlation.cpp
+++ b/media/libeffects/preprocessing/tests/correlation.cpp
@@ -107,12 +107,19 @@
         return EXIT_FAILURE;
     }
 
-    int numFrames = fileSize1 / sizeof(int16_t);
+    size_t numFrames = fileSize1 / sizeof(int16_t);
     std::unique_ptr<int16_t[]> inBuffer1(new int16_t[numFrames]());
     std::unique_ptr<int16_t[]> inBuffer2(new int16_t[numFrames]());
 
-    fread(inBuffer1.get(), sizeof(int16_t), numFrames, fInput1.get());
-    fread(inBuffer2.get(), sizeof(int16_t), numFrames, fInput2.get());
+    if (numFrames != fread(inBuffer1.get(), sizeof(int16_t), numFrames, fInput1.get())) {
+        printf("\nError: Unable to read %zu samples from file %s\n", numFrames, argv[1]);
+        return EXIT_FAILURE;
+    }
+
+    if (numFrames != fread(inBuffer2.get(), sizeof(int16_t), numFrames, fInput2.get())) {
+        printf("\nError: Unable to read %zu samples from file %s\n", numFrames, argv[2]);
+        return EXIT_FAILURE;
+    }
 
     auto pairAutoCorr1 = correlation(inBuffer1.get(), inBuffer1.get(), numFrames, enableCrossCorr);
     auto pairAutoCorr2 = correlation(inBuffer2.get(), inBuffer2.get(), numFrames, enableCrossCorr);
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index e8839ba..1705c97 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -121,6 +121,11 @@
     {"1080p", CAMCORDER_QUALITY_1080P},
     {"2160p", CAMCORDER_QUALITY_2160P},
     {"qvga", CAMCORDER_QUALITY_QVGA},
+    {"vga", CAMCORDER_QUALITY_VGA},
+    {"4kdci", CAMCORDER_QUALITY_4KDCI},
+    {"qhd", CAMCORDER_QUALITY_QHD},
+    {"2k", CAMCORDER_QUALITY_2K},
+    {"8kuhd", CAMCORDER_QUALITY_8KUHD},
 
     {"timelapselow",  CAMCORDER_QUALITY_TIME_LAPSE_LOW},
     {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
@@ -131,6 +136,10 @@
     {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
     {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P},
     {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
+    {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA},
+    {"timelapse4kdci", CAMCORDER_QUALITY_TIME_LAPSE_4KDCI},
+    {"timelapseqhd", CAMCORDER_QUALITY_TIME_LAPSE_QHD},
+    {"timelapse2k", CAMCORDER_QUALITY_TIME_LAPSE_2K},
 
     {"highspeedlow",  CAMCORDER_QUALITY_HIGH_SPEED_LOW},
     {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH},
@@ -138,19 +147,11 @@
     {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
     {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
     {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
-
-    // Vendor-specific profiles
-    {"vga", CAMCORDER_QUALITY_VGA},
-    {"4kdci", CAMCORDER_QUALITY_4KDCI},
-    {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA},
-    {"timelapse4kdci", CAMCORDER_QUALITY_TIME_LAPSE_4KDCI},
     {"highspeedcif", CAMCORDER_QUALITY_HIGH_SPEED_CIF},
     {"highspeedvga", CAMCORDER_QUALITY_HIGH_SPEED_VGA},
     {"highspeed4kdci", CAMCORDER_QUALITY_HIGH_SPEED_4KDCI},
-    {"qhd", CAMCORDER_QUALITY_QHD},
-    {"2k", CAMCORDER_QUALITY_2k},
-    {"timelapseqhd", CAMCORDER_QUALITY_TIME_LAPSE_QHD},
-    {"timelapse2k", CAMCORDER_QUALITY_TIME_LAPSE_2k},
+
+    // Vendor-specific profiles
 };
 
 #if LOG_NDEBUG
diff --git a/media/libmedia/include/media/MediaProfiles.h b/media/libmedia/include/media/MediaProfiles.h
index 4cc5b95..7f0b99d 100644
--- a/media/libmedia/include/media/MediaProfiles.h
+++ b/media/libmedia/include/media/MediaProfiles.h
@@ -37,8 +37,9 @@
     CAMCORDER_QUALITY_VGA = 9,
     CAMCORDER_QUALITY_4KDCI = 10,
     CAMCORDER_QUALITY_QHD = 11,
-    CAMCORDER_QUALITY_2k = 12,
-    CAMCORDER_QUALITY_LIST_END = 12,
+    CAMCORDER_QUALITY_2K = 12,
+    CAMCORDER_QUALITY_8KUHD = 13,
+    CAMCORDER_QUALITY_LIST_END = 13,
 
     CAMCORDER_QUALITY_TIME_LAPSE_LIST_START = 1000,
     CAMCORDER_QUALITY_TIME_LAPSE_LOW  = 1000,
@@ -53,8 +54,9 @@
     CAMCORDER_QUALITY_TIME_LAPSE_VGA = 1009,
     CAMCORDER_QUALITY_TIME_LAPSE_4KDCI = 1010,
     CAMCORDER_QUALITY_TIME_LAPSE_QHD = 1011,
-    CAMCORDER_QUALITY_TIME_LAPSE_2k = 1012,
-    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1012,
+    CAMCORDER_QUALITY_TIME_LAPSE_2K = 1012,
+    CAMCORDER_QUALITY_TIME_LAPSE_8KUHD = 1013,
+    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1013,
 
     CAMCORDER_QUALITY_HIGH_SPEED_LIST_START = 2000,
     CAMCORDER_QUALITY_HIGH_SPEED_LOW  = 2000,
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
index 3dfd850..06e67ad 100644
--- a/media/libmediametrics/Android.bp
+++ b/media/libmediametrics/Android.bp
@@ -16,7 +16,7 @@
         "libcutils",
         "liblog",
         "libutils",
-        "mediametricsservice-aidl-unstable-cpp",
+        "mediametricsservice-aidl-cpp",
     ],
 
     export_include_dirs: ["include"],
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index f4371fd..a8350ea 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -285,6 +285,7 @@
     status_t status = writeToByteString(&str, &size);
     if (status == NO_ERROR) {
         status = submitBuffer(str, size);
+        free(str);
     }
     if (status != NO_ERROR) {
         ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index ab6863f..45f2f97 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: [
         "ActivityManager.cpp",
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
index d08c66d..04477c6 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
@@ -23,26 +23,47 @@
     ],
 
     include_dirs: [
-        "system/media/audio/include",
-        "frameworks/av/include",
-        "frameworks/av/camera/include",
         "frameworks/av/media/libmediaplayerservice",
-        "frameworks/av/media/libmediametrics/include",
-        "frameworks/av/media/ndk/include",
+    ],
+
+    static_libs: [
+        "libmediaplayerservice",
+        "libstagefright_httplive",
+        "libstagefright_rtsp",
     ],
 
     shared_libs: [
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.omx@1.0",
+        "libbase",
+        "libandroid_net",
+        "libaudioclient",
+        "libbinder",
+        "libcamera_client",
+        "libcodec2_client",
+        "libcrypto",
+        "libcutils",
+        "libdatasource",
+        "libdl",
+        "libdrmframework",
+        "libgui",
+        "libhidlbase",
         "liblog",
         "libmedia",
-        "libbinder",
-        "libutils",
-        "libmediaplayerservice",
-        "libstagefright",
+        "libmedia_codeclist",
+        "libmedia_omx",
+        "libmediadrm",
         "libmediandk",
+        "libmediametrics",
+        "libmediautils",
+        "libmemunreachable",
+        "libnetd_client",
+        "libpowermanager",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libutils",
     ],
 
-    compile_multilib: "prefer32",
-
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/AndroidTest.xml b/media/libmediaplayerservice/tests/stagefrightRecorder/AndroidTest.xml
new file mode 100644
index 0000000..427026d
--- /dev/null
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<configuration description="Test module config for StagefrightRecorder unit tests">
+    <option name="test-suite-tag" value="StagefrightRecorderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+        <option name="force-root" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push"
+                value="StagefrightRecorderTest->/data/local/tmp/StagefrightRecorderTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="StagefrightRecorderTest" />
+    </test>
+</configuration>
diff --git a/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp b/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp
index 1a6e7ed..8d36e31 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp
@@ -98,6 +98,9 @@
         mTrackCursors[mExtractorTrackIndex].next.reset();
     }
 
+    // Update the extractor's sample index even if this track reaches EOS, so that the other tracks
+    // are not given an incorrect extractor position.
+    mExtractorSampleIndex++;
     if (!AMediaExtractor_advance(mExtractor)) {
         LOG(DEBUG) << "  EOS in advanceExtractor_l";
         mEosReached = true;
@@ -108,7 +111,6 @@
     }
 
     mExtractorTrackIndex = AMediaExtractor_getSampleTrackIndex(mExtractor);
-    mExtractorSampleIndex++;
 
     SampleCursor& cursor = mTrackCursors[mExtractorTrackIndex];
     if (mExtractorSampleIndex > cursor.previous.index) {
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 3d4ff15..d58d88d 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -234,7 +234,6 @@
     lseek(fd, 0, SEEK_SET);
 
     mSampleReader = MediaSampleReaderNDK::createFromFd(fd, 0 /* offset */, fileSize);
-
     if (mSampleReader == nullptr) {
         LOG(ERROR) << "Unable to parse source fd: " << fd;
         return AMEDIA_ERROR_UNSUPPORTED;
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index a7b79dc..f5c9594 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -40,6 +40,9 @@
 const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
 const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES = "max-bframes";
 
+/* TODO(lnilsson): Finalize value or adopt AMediaFormat key once available. */
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
+
 namespace AMediaFormatUtils {
 
 #define DEFINE_FORMAT_VALUE_COPY_FUNC(_type, _typeName)                                      \
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 994695f..04a513e 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -51,6 +51,32 @@
 // Default frame rate.
 static constexpr int32_t kDefaultFrameRate = 30;
 
+// Determines whether a track format describes HDR video content or not. The
+// logic is based on isHdr() in libstagefright/Utils.cpp.
+static bool isHdr(AMediaFormat* format) {
+    // If VUI signals HDR content, this internal flag is set by the extractor.
+    int32_t isHdr;
+    if (AMediaFormat_getInt32(format, "android._is-hdr", &isHdr)) {
+        return isHdr;
+    }
+
+    // If container supplied HDR static info without transfer set, assume HDR.
+    const char* hdrInfo;
+    int32_t transfer;
+    if ((AMediaFormat_getString(format, AMEDIAFORMAT_KEY_HDR_STATIC_INFO, &hdrInfo) ||
+         AMediaFormat_getString(format, "hdr10-plus-info", &hdrInfo)) &&
+        !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
+        return true;
+    }
+
+    // Otherwise, check if an HDR transfer function is set.
+    if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
+        return transfer == COLOR_TRANSFER_ST2084 || transfer == COLOR_TRANSFER_HLG;
+    }
+
+    return false;
+}
+
 template <typename T>
 void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
     {
@@ -320,6 +346,14 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
+    // Request decoder to convert HDR content to SDR.
+    const bool sourceIsHdr = isHdr(mSourceFormat.get());
+    if (sourceIsHdr) {
+        AMediaFormat_setInt32(decoderFormat.get(),
+                              TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
+                              COLOR_TRANSFER_SDR_VIDEO);
+    }
+
     // Prevent decoder from overwriting frames that the encoder has not yet consumed.
     AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
 
@@ -340,6 +374,25 @@
         return status;
     }
 
+    if (sourceIsHdr) {
+        bool supported = false;
+        AMediaFormat* inputFormat = AMediaCodec_getInputFormat(mDecoder);
+
+        if (inputFormat != nullptr) {
+            int32_t transferFunc;
+            supported = AMediaFormat_getInt32(inputFormat,
+                                              TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
+                                              &transferFunc) &&
+                        transferFunc == COLOR_TRANSFER_SDR_VIDEO;
+            AMediaFormat_delete(inputFormat);
+        }
+
+        if (!supported) {
+            LOG(ERROR) << "HDR to SDR conversion unsupported by the codec";
+            return AMEDIA_ERROR_UNSUPPORTED;
+        }
+    }
+
     // Configure codecs to run in async mode.
     AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
             .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index 1a72be3..cc3399a 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -45,11 +45,18 @@
 static constexpr int COLOR_FormatYUV420Flexible = 0x7F420888;
 static constexpr int COLOR_FormatSurface = 0x7f000789;
 
+// Color transfer functions defined by MediaCodecConstants.h but not in NDK
+static constexpr int32_t COLOR_TRANSFER_HLG = 7;
+static constexpr int32_t COLOR_TRANSFER_LINEAR = 1;
+static constexpr int32_t COLOR_TRANSFER_SDR_VIDEO = 3;
+static constexpr int32_t COLOR_TRANSFER_ST2084 = 6;
+
 // constants not defined in NDK
 extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP;
 extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME;
 extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE;
 extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST;
 static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1;
 
 static constexpr int kBitrateModeConstant = 2;
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
index 11af0b1..3a499e5 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
@@ -272,6 +272,38 @@
     compareSamples(tester.getSamples());
 }
 
+/** Reads all samples except the last in each track, before finishing. */
+TEST_F(MediaSampleReaderNDKTests, TestLastSampleBeforeEOS) {
+    LOG(DEBUG) << "TestLastSampleBeforeEOS Starts";
+    initExtractorSamples();
+
+    {  // Natural track order
+        SampleAccessTester tester{mSourceFd, mFileSize};
+        for (int trackIndex = 0; trackIndex < mTrackCount; ++trackIndex) {
+            tester.readSamplesAsync(trackIndex, mExtractorSamples[trackIndex].size() - 1);
+        }
+        tester.waitForTracks();
+        for (int trackIndex = 0; trackIndex < mTrackCount; ++trackIndex) {
+            tester.readSamplesAsync(trackIndex, SAMPLE_COUNT_ALL);
+            tester.waitForTrack(trackIndex);
+        }
+        compareSamples(tester.getSamples());
+    }
+
+    {  // Reverse track order
+        SampleAccessTester tester{mSourceFd, mFileSize};
+        for (int trackIndex = mTrackCount - 1; trackIndex >= 0; --trackIndex) {
+            tester.readSamplesAsync(trackIndex, mExtractorSamples[trackIndex].size() - 1);
+        }
+        tester.waitForTracks();
+        for (int trackIndex = mTrackCount - 1; trackIndex >= 0; --trackIndex) {
+            tester.readSamplesAsync(trackIndex, SAMPLE_COUNT_ALL);
+            tester.waitForTrack(trackIndex);
+        }
+        compareSamples(tester.getSamples());
+    }
+}
+
 /** Reads all samples from all tracks sequentially. */
 TEST_F(MediaSampleReaderNDKTests, TestSequentialSampleAccess) {
     LOG(DEBUG) << "TestSequentialSampleAccess Starts";
diff --git a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
index 792c541..bba2bc5 100755
--- a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
@@ -1,8 +1,11 @@
 #!/bin/bash
+
+# Exit on compilation error.
+set -e
+
 #
 # Run tests in this directory.
 #
-
 if [ "$SYNC_FINISHED" != true ]; then
   if [ -z "$ANDROID_BUILD_TOP" ]; then
       echo "Android build environment not set"
@@ -24,6 +27,9 @@
 
 echo "========================================"
 
+# Don't exit if a test fails.
+set +e
+
 echo "testing MediaSampleReaderNDK"
 adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleReaderNDKTests/MediaSampleReaderNDKTests
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 9c67338..d3ced29 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -619,6 +619,7 @@
 constexpr int32_t COLOR_FormatYUV422SemiPlanar        = 24;
 constexpr int32_t COLOR_FormatYUV444Flexible          = 0x7F444888;
 constexpr int32_t COLOR_FormatYUV444Interleaved       = 29;
+constexpr int32_t COLOR_FormatYUVP010                 = 54;
 constexpr int32_t COLOR_QCOM_FormatYUV420SemiPlanar   = 0x7fa30c00;
 constexpr int32_t COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
 
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 5418f10..7368ad9 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -75,7 +75,31 @@
     ERROR_DRM_RESOURCE_CONTENTION            = DRM_ERROR_BASE - 14,
     ERROR_DRM_SESSION_LOST_STATE             = DRM_ERROR_BASE - 15,
     ERROR_DRM_INVALID_STATE                  = DRM_ERROR_BASE - 16,
-    ERROR_DRM_LAST_USED_ERRORCODE            = DRM_ERROR_BASE - 16,
+
+    // New in S / drm@1.4:
+    ERROR_DRM_CERTIFICATE_MALFORMED          = DRM_ERROR_BASE - 17,
+    ERROR_DRM_CERTIFICATE_MISSING            = DRM_ERROR_BASE - 18,
+    ERROR_DRM_CRYPTO_LIBRARY                 = DRM_ERROR_BASE - 19,
+    ERROR_DRM_GENERIC_OEM                    = DRM_ERROR_BASE - 20,
+    ERROR_DRM_GENERIC_PLUGIN                 = DRM_ERROR_BASE - 21,
+    ERROR_DRM_INIT_DATA                      = DRM_ERROR_BASE - 22,
+    ERROR_DRM_KEY_NOT_LOADED                 = DRM_ERROR_BASE - 23,
+    ERROR_DRM_LICENSE_PARSE                  = DRM_ERROR_BASE - 24,
+    ERROR_DRM_LICENSE_POLICY                 = DRM_ERROR_BASE - 25,
+    ERROR_DRM_LICENSE_RELEASE                = DRM_ERROR_BASE - 26,
+    ERROR_DRM_LICENSE_REQUEST_REJECTED       = DRM_ERROR_BASE - 27,
+    ERROR_DRM_LICENSE_RESTORE                = DRM_ERROR_BASE - 28,
+    ERROR_DRM_LICENSE_STATE                  = DRM_ERROR_BASE - 29,
+    ERROR_DRM_MEDIA_FRAMEWORK                = DRM_ERROR_BASE - 30,
+    ERROR_DRM_PROVISIONING_CERTIFICATE       = DRM_ERROR_BASE - 31,
+    ERROR_DRM_PROVISIONING_CONFIG            = DRM_ERROR_BASE - 32,
+    ERROR_DRM_PROVISIONING_PARSE             = DRM_ERROR_BASE - 33,
+    ERROR_DRM_PROVISIONING_RETRY             = DRM_ERROR_BASE - 34,
+    ERROR_DRM_SECURE_STOP_RELEASE            = DRM_ERROR_BASE - 35,
+    ERROR_DRM_STORAGE_READ                   = DRM_ERROR_BASE - 36,
+    ERROR_DRM_STORAGE_WRITE                  = DRM_ERROR_BASE - 37,
+    ERROR_DRM_ZERO_SUBSAMPLES                = DRM_ERROR_BASE - 38,
+    ERROR_DRM_LAST_USED_ERRORCODE            = DRM_ERROR_BASE - 38,
 
     ERROR_DRM_VENDOR_MAX                     = DRM_ERROR_BASE - 500,
     ERROR_DRM_VENDOR_MIN                     = DRM_ERROR_BASE - 999,
diff --git a/media/libstagefright/renderfright/Android.bp b/media/libstagefright/renderfright/Android.bp
index c17f84e..7a71f52 100644
--- a/media/libstagefright/renderfright/Android.bp
+++ b/media/libstagefright/renderfright/Android.bp
@@ -23,7 +23,6 @@
         "libEGL",
         "libGLESv1_CM",
         "libGLESv2",
-        "libgui",
         "liblog",
         "libnativewindow",
         "libprocessgroup",
diff --git a/media/libstagefright/renderfright/RenderEngine.cpp b/media/libstagefright/renderfright/RenderEngine.cpp
index c3fbb60..e96ffdb 100644
--- a/media/libstagefright/renderfright/RenderEngine.cpp
+++ b/media/libstagefright/renderfright/RenderEngine.cpp
@@ -18,7 +18,6 @@
 
 #include <cutils/properties.h>
 #include <log/log.h>
-#include <private/gui/SyncFeatures.h>
 #include "gl/GLESRenderEngine.h"
 #include "threaded/RenderEngineThreaded.h"
 
@@ -52,6 +51,39 @@
 
 RenderEngine::~RenderEngine() = default;
 
+// static
+SyncFeatures &SyncFeatures::GetInstance() {
+    static SyncFeatures syncFeatures;
+    return syncFeatures;
+}
+
+bool SyncFeatures::useNativeFenceSync() const { return mHasNativeFenceSync; }
+bool SyncFeatures::useFenceSync() const { return mHasFenceSync; }
+bool SyncFeatures::useWaitSync() const { return mHasWaitSync; }
+
+SyncFeatures::SyncFeatures()
+    : mHasNativeFenceSync(false),
+      mHasFenceSync(false),
+      mHasWaitSync(false) {
+    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    // This can only be called after EGL has been initialized; otherwise the
+    // check below will abort.
+    const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
+    LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryString failed");
+    if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
+        // This makes GLConsumer use the EGL_ANDROID_native_fence_sync
+        // extension to create Android native fences to signal when all
+        // GLES reads for a given buffer have completed.
+        mHasNativeFenceSync = true;
+    }
+    if (strstr(exts, "EGL_KHR_fence_sync")) {
+        mHasFenceSync = true;
+    }
+    if (strstr(exts, "EGL_KHR_wait_sync")) {
+        mHasWaitSync = true;
+    }
+}
+
 namespace impl {
 
 RenderEngine::RenderEngine(const RenderEngineCreationArgs& args) : mArgs(args) {}
@@ -59,11 +91,11 @@
 RenderEngine::~RenderEngine() = default;
 
 bool RenderEngine::useNativeFenceSync() const {
-    return SyncFeatures::getInstance().useNativeFenceSync();
+    return SyncFeatures::GetInstance().useNativeFenceSync();
 }
 
 bool RenderEngine::useWaitSync() const {
-    return SyncFeatures::getInstance().useWaitSync();
+    return SyncFeatures::GetInstance().useWaitSync();
 }
 
 } // namespace impl
diff --git a/media/libstagefright/renderfright/gl/GLESRenderEngine.cpp b/media/libstagefright/renderfright/gl/GLESRenderEngine.cpp
index 824bdd9..b7f8cb4 100644
--- a/media/libstagefright/renderfright/gl/GLESRenderEngine.cpp
+++ b/media/libstagefright/renderfright/gl/GLESRenderEngine.cpp
@@ -30,7 +30,6 @@
 #include <android-base/stringprintf.h>
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
-#include <gui/DebugEGLImageTracker.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/Texture.h>
 #include <renderengine/private/Description.h>
@@ -436,7 +435,6 @@
         EGLImageKHR expired = mFramebufferImageCache.front().second;
         mFramebufferImageCache.pop_front();
         eglDestroyImageKHR(mEGLDisplay, expired);
-        DEBUG_EGL_IMAGE_TRACKER_DESTROY();
     }
     eglDestroyImageKHR(mEGLDisplay, mPlaceholderImage);
     mImageCache.clear();
@@ -1012,15 +1010,11 @@
                 EGLImageKHR expired = mFramebufferImageCache.front().second;
                 mFramebufferImageCache.pop_front();
                 eglDestroyImageKHR(mEGLDisplay, expired);
-                DEBUG_EGL_IMAGE_TRACKER_DESTROY();
             }
             mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
         }
     }
 
-    if (image != EGL_NO_IMAGE_KHR) {
-        DEBUG_EGL_IMAGE_TRACKER_CREATE();
-    }
     return image;
 }
 
diff --git a/media/libstagefright/renderfright/gl/GLFramebuffer.cpp b/media/libstagefright/renderfright/gl/GLFramebuffer.cpp
index 383486b..d6582b3 100644
--- a/media/libstagefright/renderfright/gl/GLFramebuffer.cpp
+++ b/media/libstagefright/renderfright/gl/GLFramebuffer.cpp
@@ -22,7 +22,6 @@
 #include <GLES/glext.h>
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
-#include <gui/DebugEGLImageTracker.h>
 #include <nativebase/nativebase.h>
 #include <utils/Trace.h>
 #include "GLESRenderEngine.h"
@@ -48,7 +47,6 @@
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         if (!usingFramebufferCache) {
             eglDestroyImageKHR(mEGLDisplay, mEGLImage);
-            DEBUG_EGL_IMAGE_TRACKER_DESTROY();
         }
         mEGLImage = EGL_NO_IMAGE_KHR;
         mBufferWidth = 0;
diff --git a/media/libstagefright/renderfright/gl/GLImage.cpp b/media/libstagefright/renderfright/gl/GLImage.cpp
index 8497721..77e648e 100644
--- a/media/libstagefright/renderfright/gl/GLImage.cpp
+++ b/media/libstagefright/renderfright/gl/GLImage.cpp
@@ -20,7 +20,6 @@
 
 #include <vector>
 
-#include <gui/DebugEGLImageTracker.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 #include "GLESRenderEngine.h"
@@ -59,7 +58,6 @@
         if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
             ALOGE("failed to destroy image: %#x", eglGetError());
         }
-        DEBUG_EGL_IMAGE_TRACKER_DESTROY();
         mEGLImage = EGL_NO_IMAGE_KHR;
     }
 
@@ -71,7 +69,6 @@
             ALOGE("failed to create EGLImage: %#x", eglGetError());
             return false;
         }
-        DEBUG_EGL_IMAGE_TRACKER_CREATE();
         mProtected = isProtected;
     }
 
diff --git a/media/libstagefright/renderfright/include/renderengine/RenderEngine.h b/media/libstagefright/renderfright/include/renderengine/RenderEngine.h
index 40fdff4..af2870f 100644
--- a/media/libstagefright/renderfright/include/renderengine/RenderEngine.h
+++ b/media/libstagefright/renderfright/include/renderengine/RenderEngine.h
@@ -302,6 +302,20 @@
     status_t mStatus;
 };
 
+class SyncFeatures {
+public:
+    static SyncFeatures &GetInstance();
+    bool useNativeFenceSync() const;
+    bool useFenceSync() const;
+    bool useWaitSync() const;
+
+private:
+    SyncFeatures();
+    bool mHasNativeFenceSync;
+    bool mHasFenceSync;
+    bool mHasWaitSync;
+};
+
 namespace impl {
 
 // impl::RenderEngine contains common implementation that is graphics back-end agnostic.
diff --git a/media/libstagefright/renderfright/threaded/RenderEngineThreaded.cpp b/media/libstagefright/renderfright/threaded/RenderEngineThreaded.cpp
index d4184fd..222d3ee 100644
--- a/media/libstagefright/renderfright/threaded/RenderEngineThreaded.cpp
+++ b/media/libstagefright/renderfright/threaded/RenderEngineThreaded.cpp
@@ -23,7 +23,6 @@
 #include <future>
 
 #include <android-base/stringprintf.h>
-#include <private/gui/SyncFeatures.h>
 #include <utils/Trace.h>
 
 #include "gl/GLESRenderEngine.h"
@@ -123,7 +122,7 @@
         std::lock_guard lock(mThreadMutex);
         mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
             ATRACE_NAME("REThreaded::useNativeFenceSync");
-            bool returnValue = SyncFeatures::getInstance().useNativeFenceSync();
+            bool returnValue = SyncFeatures::GetInstance().useNativeFenceSync();
             resultPromise.set_value(returnValue);
         });
     }
@@ -138,7 +137,7 @@
         std::lock_guard lock(mThreadMutex);
         mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
             ATRACE_NAME("REThreaded::useWaitSync");
-            bool returnValue = SyncFeatures::getInstance().useWaitSync();
+            bool returnValue = SyncFeatures::GetInstance().useWaitSync();
             resultPromise.set_value(returnValue);
         });
     }
diff --git a/media/libstagefright/tests/fuzzers/Android.bp b/media/libstagefright/tests/fuzzers/Android.bp
index 49ff69a..d39dd18 100644
--- a/media/libstagefright/tests/fuzzers/Android.bp
+++ b/media/libstagefright/tests/fuzzers/Android.bp
@@ -8,7 +8,9 @@
     ],
     shared_libs: [
         "libstagefright",
-	"libstagefright_codecbase",
+        "libstagefright_codecbase",
+        "libbase",
+        "libcutils",
         "libutils",
         "libstagefright_foundation",
         "libmedia",
@@ -16,7 +18,10 @@
         "libmedia_omx",
         "libgui",
         "libbinder",
-        "libcutils",
+        "liblog",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
     ],
 }
 
@@ -51,3 +56,27 @@
     ],
     defaults: ["libstagefright_fuzzer_defaults"],
 }
+
+cc_fuzz {
+    name: "libstagefright_frameDecoder_fuzzer",
+    srcs: [
+        "FrameDecoderFuzzer.cpp",
+    ],
+    defaults: ["libstagefright_fuzzer_defaults"],
+}
+
+cc_fuzz {
+    name: "libstagefright_writer_fuzzer",
+    srcs: [
+        "FuzzerMediaUtility.cpp",
+        "WriterFuzzer.cpp",
+    ],
+    dictionary: "dictionaries/formats.dict",
+    defaults: ["libstagefright_fuzzer_defaults"],
+    static_libs: [
+        "libstagefright_webm",
+        "libdatasource",
+        "libstagefright_esds",
+        "libogg",
+    ],
+}
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
new file mode 100644
index 0000000..a628c70
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/FrameDecoder.h"
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/IMediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/AString.h>
+#include "FrameDecoderHelpers.h"
+#include "IMediaSourceFuzzImpl.h"
+
+namespace android {
+
+#define MAX_MEDIA_BUFFER_SIZE 2048
+
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    // Init our wrapper
+    FuzzedDataProvider fdp(data, size);
+
+    std::string name = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+    AString componentName(name.c_str());
+    sp<MetaData> trackMeta = generateMetaData(&fdp);
+    sp<IMediaSource> source = new IMediaSourceFuzzImpl(&fdp, MAX_MEDIA_BUFFER_SIZE);
+
+    // Image or video Decoder?
+    sp<FrameDecoder> decoder;
+    bool isVideoDecoder = fdp.ConsumeBool();
+    if (isVideoDecoder) {
+        decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+    } else {
+        decoder = new ImageDecoder(componentName, trackMeta, source);
+    }
+
+    while (fdp.remaining_bytes()) {
+        switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 3)) {
+            case 0:
+                decoder->init(/*frameTimeUs*/ fdp.ConsumeIntegral<int64_t>(),
+                              /*option*/ fdp.ConsumeIntegral<int>(),
+                              /*colorFormat*/ fdp.ConsumeIntegral<int>());
+                break;
+            case 1:
+                decoder->extractFrame();
+                break;
+            case 2: {
+                FrameRect rect;
+                rect.left = fdp.ConsumeIntegral<int32_t>();
+                rect.top = fdp.ConsumeIntegral<int32_t>();
+                rect.right = fdp.ConsumeIntegral<int32_t>();
+                rect.bottom = fdp.ConsumeIntegral<int32_t>();
+                decoder->extractFrame(&rect);
+                break;
+            }
+            case 3: {
+                sp<MetaData> trackMeta = generateMetaData(&fdp);
+                decoder->getMetadataOnly(trackMeta,
+                                         /*colorFormat*/ fdp.ConsumeIntegral<int>(),
+                                         /*thumbnail*/ fdp.ConsumeBool());
+                break;
+            }
+        }
+    }
+
+    generated_mime_types.clear();
+
+    return 0;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h b/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
new file mode 100644
index 0000000..228c04a
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderHelpers.h
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <media/stagefright/MetaData.h>
+#include "MediaMimeTypes.h"
+
+#define MAX_METADATA_BUF_SIZE 512
+
+namespace android {
+
+std::vector<std::shared_ptr<char>> generated_mime_types;
+
+sp<MetaData> generateMetaData(FuzzedDataProvider *fdp) {
+    sp<MetaData> newMeta = new MetaData();
+
+    // random MIME Type
+    const char *mime_type;
+    size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
+    // Let there be a chance of a true random string
+    if (index == kMimeTypes.size()) {
+        std::string mime_str = fdp->ConsumeRandomLengthString(64);
+        std::shared_ptr<char> mime_cstr(new char[mime_str.length()+1]);
+        generated_mime_types.push_back(mime_cstr);
+        strncpy(mime_cstr.get(), mime_str.c_str(), mime_str.length()+1);
+        mime_type = mime_cstr.get();
+    } else {
+        mime_type = kMimeTypes[index];
+    }
+    newMeta->setCString(kKeyMIMEType, mime_type);
+
+    // Thumbnail time
+    newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<int64_t>());
+
+    // Values used by allocVideoFrame
+    newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegral<int32_t>());
+    size_t profile_size =
+        fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
+    std::vector<uint8_t> profile_bytes =
+        fdp->ConsumeBytes<uint8_t>(profile_size);
+    newMeta->setData(kKeyIccProfile,
+                     fdp->ConsumeIntegral<int32_t>(),
+                     profile_bytes.empty() ? nullptr : profile_bytes.data(),
+                     profile_bytes.size());
+    newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<int32_t>());
+
+    // Values used by findThumbnailInfo
+    newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<int32_t>());
+    size_t thumbnail_size =
+        fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
+    std::vector<uint8_t> thumb_bytes =
+        fdp->ConsumeBytes<uint8_t>(thumbnail_size);
+    newMeta->setData(kKeyThumbnailHVCC,
+                     fdp->ConsumeIntegral<int32_t>(),
+                     thumb_bytes.empty() ? nullptr : thumb_bytes.data(),
+                     thumb_bytes.size());
+
+    // Values used by findGridInfo
+    newMeta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<int32_t>());
+
+    // A few functions perform a CHECK() that height/width are set
+    newMeta->setInt32(kKeyHeight, fdp->ConsumeIntegral<int32_t>());
+    newMeta->setInt32(kKeyWidth, fdp->ConsumeIntegral<int32_t>());
+
+    return newMeta;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
new file mode 100644
index 0000000..810ae95
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FuzzerMediaUtility.h"
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/OggWriter.h>
+
+#include "MediaMimeTypes.h"
+#include "webm/WebmWriter.h"
+
+namespace android {
+std::string genMimeType(FuzzedDataProvider *dataProvider) {
+    uint8_t idx = dataProvider->ConsumeIntegralInRange<uint8_t>(0, kMimeTypes.size() - 1);
+    return std::string(kMimeTypes[idx]);
+}
+
+sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, std::string mimeType,
+                                      uint16_t maxDataAmount) {
+    uint32_t dataBlobSize = dataProvider->ConsumeIntegralInRange<uint16_t>(0, maxDataAmount);
+    std::vector<uint8_t> data = dataProvider->ConsumeBytes<uint8_t>(dataBlobSize);
+    // data:[<mediatype>][;base64],<data>
+    std::string uri("data:");
+    uri += mimeType;
+    // Currently libstagefright only accepts base64 uris
+    uri += ";base64,";
+    android::AString out;
+    android::encodeBase64(data.data(), data.size(), &out);
+    uri += out.c_str();
+
+    sp<DataSource> source =
+        DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri.c_str());
+
+    if (source == NULL) {
+        return NULL;
+    }
+
+    return MediaExtractorFactory::Create(source);
+}
+
+sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize) {
+    std::string mime = genMimeType(dataProvider);
+    sp<IMediaExtractor> extractor = genMediaExtractor(dataProvider, mime, maxMediaBlobSize);
+
+    if (extractor == NULL) {
+        return NULL;
+    }
+
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+        const char *trackMime;
+        if (!strcasecmp(mime.c_str(), trackMime)) {
+            sp<IMediaSource> track = extractor->getTrack(i);
+            if (track == NULL) {
+                return NULL;
+            }
+            return new CallbackMediaSource(track);
+        }
+    }
+
+    return NULL;
+}
+
+sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> fileMeta) {
+    sp<MediaWriter> writer;
+    switch (writerType) {
+        case OGG:
+            writer = new OggWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+            break;
+        case AAC:
+            writer = new AACWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            break;
+        case AAC_ADTS:
+            writer = new AACWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+            break;
+        case WEBM:
+            writer = new WebmWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+            break;
+        case MPEG4:
+            writer = new MPEG4Writer(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            break;
+        case AMR_NB:
+            writer = new AMRWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            break;
+        case AMR_WB:
+            writer = new AMRWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            break;
+        case MPEG2TS:
+            writer = new MPEG2TSWriter(fd);
+            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            break;
+        default:
+            return nullptr;
+    }
+    if (writer != nullptr) {
+        fileMeta->setInt32(kKeyRealTimeRecording, false);
+    }
+    return writer;
+}
+}  // namespace android
\ No newline at end of file
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
new file mode 100644
index 0000000..98bfb94
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <datasource/DataSourceFactory.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <android/IMediaExtractor.h>
+#include <media/IMediaHTTPService.h>
+#include <media/mediarecorder.h>
+#include <media/stagefright/CallbackMediaSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/MediaWriter.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/base64.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+enum StandardWriters {
+    OGG,
+    AAC,
+    AAC_ADTS,
+    WEBM,
+    MPEG4,
+    AMR_NB,
+    AMR_WB,
+    MPEG2TS,
+    // Allows FuzzedDataProvider to find the end of this enum.
+    kMaxValue = MPEG2TS,
+};
+
+std::string genMimeType(FuzzedDataProvider *dataProvider);
+sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, uint16_t dataAmount);
+sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize);
+
+sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> fileMeta);
+}  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h b/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
new file mode 100644
index 0000000..e769950
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/IMediaSourceFuzzImpl.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMEDIASOURCEFUZZIMPL_H
+#define IMEDIASOURCEFUZZIMPL_H
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class IMediaSourceFuzzImpl : public IMediaSource {
+ public:
+    IMediaSourceFuzzImpl(FuzzedDataProvider *_fdp, size_t _max_buffer_size) :
+        fdp(_fdp),
+        max_buffer_size(_max_buffer_size) {}
+    status_t start(MetaData*) override { return 0; }
+    status_t stop() override { return 0; }
+    sp<MetaData> getFormat() override { return nullptr; }
+    status_t read(MediaBufferBase**,
+        const MediaSource::ReadOptions*) override;
+    status_t readMultiple(Vector<MediaBufferBase*>*, uint32_t,
+        const MediaSource::ReadOptions*) override;
+    bool supportReadMultiple() override { return true; }
+    bool supportNonblockingRead() override { return true; }
+    status_t pause() override { return 0; }
+
+ protected:
+    IBinder* onAsBinder() { return nullptr; }
+
+ private:
+    FuzzedDataProvider *fdp;
+    std::vector<std::shared_ptr<MediaBufferBase>> buffer_bases;
+    const size_t max_buffer_size;
+};
+
+// This class is simply to expose the destructor
+class MediaBufferFuzzImpl : public MediaBuffer {
+ public:
+    MediaBufferFuzzImpl(void *data, size_t size) : MediaBuffer(data, size) {}
+    ~MediaBufferFuzzImpl() {}
+};
+
+status_t IMediaSourceFuzzImpl::read(MediaBufferBase **buffer,
+        const MediaSource::ReadOptions *options) {
+    Vector<MediaBufferBase*> buffers;
+    status_t ret = readMultiple(&buffers, 1, options);
+    *buffer = buffers.empty() ? nullptr : buffers[0];
+
+    return ret;
+}
+
+status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers,
+        uint32_t maxNumBuffers, const MediaSource::ReadOptions*) {
+    uint32_t num_buffers =
+        fdp->ConsumeIntegralInRange<uint32_t>(0, maxNumBuffers);
+    for(uint32_t i = 0; i < num_buffers; i++) {
+        std::vector<uint8_t> buf = fdp->ConsumeBytes<uint8_t>(
+            fdp->ConsumeIntegralInRange<size_t>(0, max_buffer_size));
+
+        std::shared_ptr<MediaBufferBase> mbb(
+            new MediaBufferFuzzImpl(buf.data(), buf.size()));
+
+        buffer_bases.push_back(mbb);
+        buffers->push_back(mbb.get());
+    }
+
+    // STATUS_OK
+    return 0;
+}
+
+} // namespace android
+
+#endif // IMEDIASOURCEFUZZIMPL_H
+
diff --git a/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp b/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp
index e473541..9b26f0b 100644
--- a/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp
@@ -17,52 +17,53 @@
 //          dylan.katz@leviathansecurity.com
 
 #include <fuzzer/FuzzedDataProvider.h>
-#include <media/stagefright/MediaClock.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaClock.h>
 
 namespace android {
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
-  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-  sp<MediaClock> mClock(new MediaClock);
+    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+    sp<MediaClock> mClock(new MediaClock);
 
-  bool registered = false;
-  while (fdp.remaining_bytes() > 0) {
-    switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 5)) {
-    case 0: {
-      if (registered == false) {
-        mClock->init();
-        registered = true;
-      }
-      break;
+    bool registered = false;
+    while (fdp.remaining_bytes() > 0) {
+        switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 5)) {
+            case 0: {
+                if (registered == false) {
+                    mClock->init();
+                    registered = true;
+                }
+                break;
+                }
+            case 1: {
+                int64_t startingTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+                mClock->setStartingTimeMedia(startingTimeMediaUs);
+                break;
+            }
+            case 2: {
+                mClock->clearAnchor();
+                break;
+            }
+            case 3: {
+                int64_t anchorTimeRealUs = fdp.ConsumeIntegral<int64_t>();
+                int64_t anchorTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+                int64_t maxTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+                mClock->updateAnchor(anchorTimeMediaUs, anchorTimeRealUs,
+                                     maxTimeMediaUs);
+                break;
+            }
+            case 4: {
+                int64_t maxTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+                mClock->updateMaxTimeMedia(maxTimeMediaUs);
+                break;
+                }
+            case 5: {
+                wp<AMessage> msg(new AMessage);
+                mClock->setNotificationMessage(msg.promote());
+            }
+        }
     }
-    case 1: {
-      int64_t startingTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
-      mClock->setStartingTimeMedia(startingTimeMediaUs);
-      break;
-    }
-    case 2: {
-      mClock->clearAnchor();
-      break;
-    }
-    case 3: {
-      int64_t anchorTimeRealUs = fdp.ConsumeIntegral<int64_t>();
-      int64_t anchorTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
-      int64_t maxTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
-      mClock->updateAnchor(anchorTimeMediaUs, anchorTimeRealUs, maxTimeMediaUs);
-      break;
-    }
-    case 4: {
-      int64_t maxTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
-      mClock->updateMaxTimeMedia(maxTimeMediaUs);
-      break;
-    }
-    case 5: {
-      wp<AMessage> msg(new AMessage);
-      mClock->setNotificationMessage(msg.promote());
-    }
-    }
-  }
 
-  return 0;
+    return 0;
 }
-} // namespace android
+}  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/MediaMimeTypes.h b/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
new file mode 100644
index 0000000..9f337ac
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/MediaMimeTypes.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FUZZER_MEDIAMIMETYPES_H_
+#define FUZZER_MEDIAMIMETYPES_H_
+
+#include <media/stagefright/foundation/MediaDefs.h>
+
+namespace android {
+
+static const std::vector<const char*> kMimeTypes {
+    MEDIA_MIMETYPE_IMAGE_JPEG,
+    MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
+    MEDIA_MIMETYPE_VIDEO_VP8,
+    MEDIA_MIMETYPE_VIDEO_VP9,
+    MEDIA_MIMETYPE_VIDEO_AV1,
+    MEDIA_MIMETYPE_VIDEO_AVC,
+    MEDIA_MIMETYPE_VIDEO_HEVC,
+    MEDIA_MIMETYPE_VIDEO_MPEG4,
+    MEDIA_MIMETYPE_VIDEO_H263,
+    MEDIA_MIMETYPE_VIDEO_MPEG2,
+    MEDIA_MIMETYPE_VIDEO_RAW,
+    MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+    MEDIA_MIMETYPE_VIDEO_SCRAMBLED,
+    MEDIA_MIMETYPE_VIDEO_DIVX,
+    MEDIA_MIMETYPE_VIDEO_DIVX3,
+    MEDIA_MIMETYPE_VIDEO_XVID,
+    MEDIA_MIMETYPE_VIDEO_MJPEG,
+    MEDIA_MIMETYPE_AUDIO_AMR_NB,
+    MEDIA_MIMETYPE_AUDIO_AMR_WB,
+    MEDIA_MIMETYPE_AUDIO_MPEG,
+    MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+    MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+    MEDIA_MIMETYPE_AUDIO_MIDI,
+    MEDIA_MIMETYPE_AUDIO_AAC,
+    MEDIA_MIMETYPE_AUDIO_QCELP,
+    MEDIA_MIMETYPE_AUDIO_VORBIS,
+    MEDIA_MIMETYPE_AUDIO_OPUS,
+    MEDIA_MIMETYPE_AUDIO_G711_ALAW,
+    MEDIA_MIMETYPE_AUDIO_G711_MLAW,
+    MEDIA_MIMETYPE_AUDIO_RAW,
+    MEDIA_MIMETYPE_AUDIO_FLAC,
+    MEDIA_MIMETYPE_AUDIO_AAC_ADTS,
+    MEDIA_MIMETYPE_AUDIO_MSGSM,
+    MEDIA_MIMETYPE_AUDIO_AC3,
+    MEDIA_MIMETYPE_AUDIO_EAC3,
+    MEDIA_MIMETYPE_AUDIO_EAC3_JOC,
+    MEDIA_MIMETYPE_AUDIO_AC4,
+    MEDIA_MIMETYPE_AUDIO_SCRAMBLED,
+    MEDIA_MIMETYPE_AUDIO_ALAC,
+    MEDIA_MIMETYPE_AUDIO_WMA,
+    MEDIA_MIMETYPE_AUDIO_MS_ADPCM,
+    MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM,
+    MEDIA_MIMETYPE_CONTAINER_MPEG4,
+    MEDIA_MIMETYPE_CONTAINER_WAV,
+    MEDIA_MIMETYPE_CONTAINER_OGG,
+    MEDIA_MIMETYPE_CONTAINER_MATROSKA,
+    MEDIA_MIMETYPE_CONTAINER_MPEG2TS,
+    MEDIA_MIMETYPE_CONTAINER_AVI,
+    MEDIA_MIMETYPE_CONTAINER_MPEG2PS,
+    MEDIA_MIMETYPE_CONTAINER_HEIF,
+    MEDIA_MIMETYPE_TEXT_3GPP,
+    MEDIA_MIMETYPE_TEXT_SUBRIP,
+    MEDIA_MIMETYPE_TEXT_VTT,
+    MEDIA_MIMETYPE_TEXT_CEA_608,
+    MEDIA_MIMETYPE_TEXT_CEA_708,
+    MEDIA_MIMETYPE_DATA_TIMED_ID3
+};
+
+}  // namespace android
+
+#endif  // FUZZER_MEDIAMIMETYPES_H_
diff --git a/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp b/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp
index a072b7c..c50c951 100644
--- a/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp
@@ -16,7 +16,6 @@
 // Authors: corbin.souffrant@leviathansecurity.com
 //          dylan.katz@leviathansecurity.com
 
-#include <cutils/ashmem.h>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <media/stagefright/StagefrightMediaScanner.h>
 
@@ -24,59 +23,39 @@
 
 namespace android {
 class FuzzMediaScannerClient : public MediaScannerClient {
-public:
-  virtual status_t scanFile(const char *, long long, long long, bool, bool) {
-    return 0;
-  }
+ public:
+    virtual status_t scanFile(const char*, long long, long long, bool, bool) {
+        return 0;
+    }
 
-  virtual status_t handleStringTag(const char *, const char *) { return 0; }
+    virtual status_t handleStringTag(const char*, const char*) { return 0; }
 
-  virtual status_t setMimeType(const char *) { return 0; }
+    virtual status_t setMimeType(const char*) { return 0; }
 };
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
-  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
-  StagefrightMediaScanner mScanner = StagefrightMediaScanner();
-  // Without this, the fuzzer crashes for some reason.
-  mScanner.setLocale("");
+    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+    StagefrightMediaScanner mScanner = StagefrightMediaScanner();
+    // Without this, the fuzzer crashes for some reason.
+    mScanner.setLocale("");
 
-  size_t data_size = fdp.ConsumeIntegralInRange<size_t>(0, size);
-  int fd =
-      ashmem_create_region("stagefrightmediascanner_fuzz_region", data_size);
-  if (fd < 0)
+    while (fdp.remaining_bytes() > 0) {
+        switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 1)) {
+            case 0: {
+                std::string path = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+                std::string mimeType =
+                    fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+                std::shared_ptr<MediaScannerClient> client(new FuzzMediaScannerClient());
+                mScanner.processFile(path.c_str(), mimeType.c_str(), *client);
+                break;
+            }
+            case 1: {
+                int fd = fdp.ConsumeIntegral<int>();
+                if (fd >= 0 && fd <= 2) fd = 3;
+                mScanner.extractAlbumArt(fd);
+            }
+        }
+    }
     return 0;
-
-  uint8_t *sh_data = static_cast<uint8_t *>(
-      mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
-  if (sh_data == MAP_FAILED)
-    return 0;
-
-  while (fdp.remaining_bytes() > 8) {
-    switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 1)) {
-    case 0: {
-      std::string path = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
-      std::string mimeType =
-          fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
-      std::shared_ptr<MediaScannerClient> client(new FuzzMediaScannerClient());
-      mScanner.processFile(path.c_str(), mimeType.c_str(), *client);
-      break;
-    }
-    case 1: {
-      size_t to_copy = fdp.ConsumeIntegralInRange<size_t>(1, data_size);
-      std::vector<uint8_t> rand_buf = fdp.ConsumeBytes<uint8_t>(to_copy);
-
-      // If fdp doesn't have enough bytes left it will just make a shorter
-      // vector.
-      to_copy = std::min(rand_buf.size(), data_size);
-
-      std::copy(sh_data, sh_data + to_copy, rand_buf.begin());
-      mScanner.extractAlbumArt(fd);
-    }
-    }
-  }
-
-  munmap(sh_data, data_size);
-  close(fd);
-  return 0;
 }
-} // namespace android
+}  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
new file mode 100644
index 0000000..03e9b43
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#include <android-base/file.h>
+#include <ctype.h>
+#include <media/mediarecorder.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <stdlib.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include <functional>
+#include <string>
+
+#include "FuzzerMediaUtility.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+static constexpr uint16_t kMaxOperations = 5000;
+static constexpr uint8_t kMaxPackageNameLen = 50;
+// For other strings in mpeg we want a higher limit.
+static constexpr uint16_t kMaxMPEGStrLen = 1000;
+static constexpr uint16_t kMaxMediaBlobSize = 1000;
+
+namespace android {
+
+std::string getFourCC(FuzzedDataProvider *fdp) {
+    std::string fourCC = fdp->ConsumeRandomLengthString(4);
+    // Replace any existing nulls
+    for (size_t pos = 0; pos < fourCC.length(); pos++) {
+        if (fourCC.at(pos) == '\0') {
+            fourCC.replace(pos, 1, "a");
+        }
+    }
+
+    // If our string is too short, fill the remainder with "a"s.
+    while (fourCC.length() < 4) {
+        fourCC += 'a';
+    }
+    return fourCC;
+}
+
+typedef std::vector<std::function<void(FuzzedDataProvider*,
+                                    sp<MediaWriter>, sp<MetaData>, int tmpFileFd)>> OperationVec;
+typedef std::vector<std::function<void(FuzzedDataProvider*, MPEG4Writer*)>> MPEG4OperationVec;
+static const OperationVec operations = {
+    [](FuzzedDataProvider*, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
+        mediaWriter->pause();
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
+        bool valid_fd = dataProvider->ConsumeBool();
+        int fd = -1;
+        if (valid_fd) {
+            fd = tmpFd;
+        }
+        // Args don't seem to be used
+        Vector<String16> args;
+        mediaWriter->dump(fd, args);
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int tmpFd) {
+        bool valid_fd = dataProvider->ConsumeBool();
+        int fd = -1;
+        if (valid_fd) {
+            fd = tmpFd;
+        }
+        mediaWriter->setNextFd(fd);
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
+        mediaWriter->setCaptureRate(dataProvider->ConsumeFloatingPoint<float>());
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
+        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
+        mediaWriter->setStartTimeOffsetMs(dataProvider->ConsumeIntegral<int>());
+
+        // Likely won't do much, but might as well as do a quick check
+        // while we're here.
+        mediaWriter->getStartTimeOffsetMs();
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
+        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
+    },
+    [](FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter, sp<MetaData>, int) {
+        mediaWriter->setMaxFileDuration(dataProvider->ConsumeIntegral<int64_t>());
+    },
+};
+
+static const MPEG4OperationVec mpeg4Operations = {
+    [](FuzzedDataProvider*, MPEG4Writer *mediaWriter) { mediaWriter->notifyApproachingLimit(); },
+    // Lower level write methods.
+    // High-level startBox/endBox/etc are all called elsewhere,
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        uint8_t val = dataProvider->ConsumeIntegral<uint8_t>();
+        mediaWriter->writeInt8(val);
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        uint16_t val = dataProvider->ConsumeIntegral<uint16_t>();
+        mediaWriter->writeInt16(val);
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        uint32_t val = dataProvider->ConsumeIntegral<uint32_t>();
+        mediaWriter->writeInt32(val);
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        uint64_t val = dataProvider->ConsumeIntegral<uint64_t>();
+        mediaWriter->writeInt64(val);
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        std::string strVal = dataProvider->ConsumeRandomLengthString(kMaxMPEGStrLen);
+        mediaWriter->writeCString(strVal.c_str());
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        std::string fourCC = getFourCC(dataProvider);
+        mediaWriter->writeFourcc(fourCC.c_str());
+    },
+
+    // Misc setters
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        uint32_t layers = dataProvider->ConsumeIntegral<uint32_t>();
+        mediaWriter->setTemporalLayerCount(layers);
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        uint32_t duration = dataProvider->ConsumeIntegral<uint32_t>();
+        mediaWriter->setInterleaveDuration(duration);
+    },
+    [](FuzzedDataProvider *dataProvider, MPEG4Writer *mediaWriter) {
+        int lat = dataProvider->ConsumeIntegral<int>();
+        int lon = dataProvider->ConsumeIntegral<int>();
+        mediaWriter->setGeoData(lat, lon);
+    },
+};
+
+// Not all writers can always add new sources, so we'll need additional checks.
+void addSource(FuzzedDataProvider *dataProvider, sp<MediaWriter> mediaWriter) {
+    sp<MediaSource> mediaSource = genMediaSource(dataProvider, kMaxMediaBlobSize);
+    if (mediaSource == NULL) {
+        // There's a static check preventing NULLs in addSource.
+        return;
+    }
+    mediaWriter->addSource(mediaSource);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    TemporaryFile tf;
+    sp<MetaData> fileMeta = new MetaData;
+    StandardWriters writerType = dataProvider.ConsumeEnum<StandardWriters>();
+    sp<MediaWriter> writer = createWriter(tf.fd, writerType, fileMeta);
+
+    std::string packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
+
+    sp<MediaRecorder> mr = new MediaRecorder(String16(packageName.c_str()));
+    writer->setListener(mr);
+
+    uint8_t baseOpLen = operations.size();
+    uint8_t totalLen = baseOpLen;
+    uint8_t maxSources;
+    // Different writers support different amounts of sources.
+    switch (writerType) {
+        case StandardWriters::AAC:
+        case StandardWriters::AAC_ADTS:
+        case StandardWriters::AMR_NB:
+        case StandardWriters::AMR_WB:
+        case StandardWriters::OGG:
+            maxSources = 1;
+            break;
+        case StandardWriters::WEBM:
+            maxSources = 2;
+            break;
+        default:
+            maxSources = UINT8_MAX;
+            break;
+    }
+    // Initialize some number of sources and add them to our writer.
+    uint8_t sourceCount = dataProvider.ConsumeIntegralInRange<uint8_t>(0, maxSources);
+    for (uint8_t i = 0; i < sourceCount; i++) {
+        addSource(&dataProvider, writer);
+    }
+
+    // Increase our range if additional operations are implemented.
+    // Currently only MPEG4 has additiona public operations on their writer.
+    if (writerType == StandardWriters::MPEG4) {
+        totalLen += mpeg4Operations.size();
+    }
+
+    // Many operations require the writer to be started.
+    writer->start(fileMeta.get());
+    for (size_t ops_run = 0; dataProvider.remaining_bytes() > 0 && ops_run < kMaxOperations - 1;
+            ops_run++) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, totalLen - 1);
+        if (op < baseOpLen) {
+            operations[op](&dataProvider, writer, fileMeta, tf.fd);
+        } else if (writerType == StandardWriters::MPEG4) {
+            mpeg4Operations[op - baseOpLen](&dataProvider, (MPEG4Writer*)writer.get());
+        } else {
+            // Here just in case, will error out.
+            operations[op](&dataProvider, writer, fileMeta, tf.fd);
+        }
+    }
+    writer->stop();
+
+    writer.clear();
+    writer = nullptr;
+    return 0;
+}
+}  // namespace android
diff --git a/media/libstagefright/tests/fuzzers/dictionaries/formats.dict b/media/libstagefright/tests/fuzzers/dictionaries/formats.dict
new file mode 100644
index 0000000..4ab22de
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/dictionaries/formats.dict
@@ -0,0 +1,299 @@
+############################################################################################################
+# This file is a combination of these dictionaries:                                                        #
+# https://github.com/google/fuzzing/blob/0c48531c4d317cea9479b3ec1b0ddb9edc438c3a/dictionaries/mp4.dict    #
+# https://github.com/google/fuzzing/blob/0c48531c4d317cea9479b3ec1b0ddb9edc438c3a/dictionaries/webm.dict   #
+# https://github.com/google/fuzzing/blob/0c48531c4d317cea9479b3ec1b0ddb9edc438c3a/dictionaries/ogg.dict    #
+# MPEG4, OGG, and WEBM are all formats used by MediaWriter.                                                #
+############################################################################################################
+# mp4.dict
+# Taken from https://chromium.googlesource.com/chromium/src/+/master/media/test/mp4.dict
+FOURCC_NULL="\x00\x00\x00\x00"
+FOURCC_AC3 ="\x61\x63\x2d\x33"
+FOURCC_EAC3="\x65\x63\x2d\x33"
+FOURCC_AVC1="\x61\x76\x63\x31"
+FOURCC_AVC3="\x61\x76\x63\x33"
+FOURCC_AVCC="\x61\x76\x63\x43"
+FOURCC_BLOC="\x62\x6C\x6F\x63"
+FOURCC_CENC="\x63\x65\x6e\x63"
+FOURCC_CO64="\x63\x6f\x36\x34"
+FOURCC_CTTS="\x63\x74\x74\x73"
+FOURCC_DINF="\x64\x69\x6e\x66"
+FOURCC_EDTS="\x65\x64\x74\x73"
+FOURCC_EMSG="\x65\x6d\x73\x67"
+FOURCC_ELST="\x65\x6c\x73\x74"
+FOURCC_ENCA="\x65\x6e\x63\x61"
+FOURCC_ENCV="\x65\x6e\x63\x76"
+FOURCC_ESDS="\x65\x73\x64\x73"
+FOURCC_FREE="\x66\x72\x65\x65"
+FOURCC_FRMA="\x66\x72\x6d\x61"
+FOURCC_FTYP="\x66\x74\x79\x70"
+FOURCC_HDLR="\x68\x64\x6c\x72"
+FOURCC_HINT="\x68\x69\x6e\x74"
+FOURCC_HVC1="\x68\x76\x63\x31"
+FOURCC_HVCC="\x68\x76\x63\x43"
+FOURCC_IODS="\x69\x6f\x64\x73"
+FOURCC_MDAT="\x6d\x64\x61\x74"
+FOURCC_MDHD="\x6d\x64\x68\x64"
+FOURCC_MDIA="\x6d\x64\x69\x61"
+FOURCC_MECO="\x6d\x65\x63\x6f"
+FOURCC_MEHD="\x6d\x65\x68\x64"
+FOURCC_META="\x6d\x65\x74\x61"
+FOURCC_MFHD="\x6d\x66\x68\x64"
+FOURCC_MFRA="\x6d\x66\x72\x61"
+FOURCC_MINF="\x6d\x69\x6e\x66"
+FOURCC_MOOF="\x6d\x6f\x6f\x66"
+FOURCC_MOOV="\x6d\x6f\x6f\x76"
+FOURCC_MP4A="\x6d\x70\x34\x61"
+FOURCC_MP4V="\x6d\x70\x34\x76"
+FOURCC_MVEX="\x6d\x76\x65\x78"
+FOURCC_MVHD="\x6d\x76\x68\x64"
+FOURCC_PASP="\x70\x61\x73\x70"
+FOURCC_PDIN="\x70\x64\x69\x6e"
+FOURCC_PRFT="\x70\x72\x66\x74"
+FOURCC_PSSH="\x70\x73\x73\x68"
+FOURCC_SAIO="\x73\x61\x69\x6f"
+FOURCC_SAIZ="\x73\x61\x69\x7a"
+FOURCC_SBGP="\x73\x62\x67\x70"
+FOURCC_SCHI="\x73\x63\x68\x69"
+FOURCC_SCHM="\x73\x63\x68\x6d"
+FOURCC_SDTP="\x73\x64\x74\x70"
+FOURCC_SEIG="\x73\x65\x69\x67"
+FOURCC_SENC="\x73\x65\x6e\x63"
+FOURCC_SGPD="\x73\x67\x70\x64"
+FOURCC_SIDX="\x73\x69\x64\x78"
+FOURCC_SINF="\x73\x69\x6e\x66"
+FOURCC_SKIP="\x73\x6b\x69\x70"
+FOURCC_SMHD="\x73\x6d\x68\x64"
+FOURCC_SOUN="\x73\x6f\x75\x6e"
+FOURCC_SSIX="\x73\x73\x69\x78"
+FOURCC_STBL="\x73\x74\x62\x6c"
+FOURCC_STCO="\x73\x74\x63\x6f"
+FOURCC_STSC="\x73\x74\x73\x63"
+FOURCC_STSD="\x73\x74\x73\x64"
+FOURCC_STSS="\x73\x74\x73\x73"
+FOURCC_STSZ="\x73\x74\x73\x7a"
+FOURCC_STTS="\x73\x74\x74\x73"
+FOURCC_STYP="\x73\x74\x79\x70"
+FOURCC_TENC="\x74\x65\x6e\x63"
+FOURCC_TFDT="\x74\x66\x64\x74"
+FOURCC_TFHD="\x74\x66\x68\x64"
+FOURCC_TKHD="\x74\x6b\x68\x64"
+FOURCC_TRAF="\x74\x72\x61\x66"
+FOURCC_TRAK="\x74\x72\x61\x6b"
+FOURCC_TREX="\x74\x72\x65\x78"
+FOURCC_TRUN="\x74\x72\x75\x6e"
+FOURCC_UDTA="\x75\x64\x74\x61"
+FOURCC_UUID="\x75\x75\x69\x64"
+FOURCC_VIDE="\x76\x69\x64\x65"
+FOURCC_VMHD="\x76\x6d\x68\x64"
+FOURCC_WIDE="\x77\x69\x64\x65"
+
+# ogg.dict
+# https://xiph.org/vorbis/doc/Vorbis_I_spec.html
+
+header="OggS"
+
+# Codecs
+"BBCD\x00"
+"\x7fFLAC"
+"\x80theora"
+"\x01vorbis"
+"CELT    "
+"CMML\x00\x00\x00\x00"
+"\x8bJNG\x0d\x0a\x1a\x0a"
+"\x80kate\x00\x00\x00"
+"OggMIDI\x00"
+"\x8aMNG\x0d\x0a\x1a\x0a"
+"PCM     "
+"\x89PNG\x0d\x0a\x1a\x0a"
+"Speex   "
+"YUV4MPEG"
+
+# Metadata
+"TITLE="
+"VERSION="
+"ALBUM="
+"TRACKNUMBER="
+"ARTIST="
+"PERFORMER="
+"COPYRIGHT="
+"LICENSE="
+"ORGANIZATION="
+"DESCRIPTION="
+"GENRE="
+"DATE="
+"LOCATION="
+"CONTACT="
+"ISRC="
+
+# webm.dict
+# Element IDs.
+IdAesSettingsCipherMode = "\x47\xE8"
+IdAlphaMode = "\x53\xC0"
+IdAspectRatioType = "\x54\xB3"
+IdAudio = "\xE1"
+IdBitDepth = "\x62\x64"
+IdBitsPerChannel = "\x55\xB2"
+IdBlock = "\xA1"
+IdBlockAddId = "\xEE"
+IdBlockAdditional = "\xA5"
+IdBlockAdditions = "\x75\xA1"
+IdBlockDuration = "\x9B"
+IdBlockGroup = "\xA0"
+IdBlockMore = "\xA6"
+IdBlockVirtual = "\xA2"
+IdCbSubsamplingHorz = "\x55\xB5"
+IdCbSubsamplingVert = "\x55\xB6"
+IdChannels = "\x9F"
+IdChapCountry = "\x43\x7E"
+IdChapLanguage = "\x43\x7C"
+IdChapString = "\x85"
+IdChapterAtom = "\xB6"
+IdChapterDisplay = "\x80"
+IdChapterStringUID = "\x56\x54"
+IdChapterStringUid = "\x56\x54"
+IdChapterTimeEnd = "\x92"
+IdChapterTimeStart = "\x91"
+IdChapterUID = "\x73\xC4"
+IdChapterUid = "\x73\xC4"
+IdChapters = "\x10\x43\xA7\x70"
+IdChromaSitingHorz = "\x55\xB7"
+IdChromaSitingVert = "\x55\xB8"
+IdChromaSubsamplingHorz = "\x55\xB3"
+IdChromaSubsamplingVert = "\x55\xB4"
+IdCluster = "\x1F\x43\xB6\x75"
+IdCodecDelay = "\x56\xAA"
+IdCodecID = "\x86"
+IdCodecName = "\x25\x86\x88"
+IdCodecPrivate = "\x63\xA2"
+IdColour = "\x55\xB0"
+IdContentEncAESSettings = "\x47\xE7"
+IdContentEncAesSettings = "\x47\xE7"
+IdContentEncAlgo = "\x47\xE1"
+IdContentEncKeyId = "\x47\xE2"
+IdContentEncoding = "\x62\x40"
+IdContentEncodingOrder = "\x50\x31"
+IdContentEncodingScope = "\x50\x32"
+IdContentEncodingType = "\x50\x33"
+IdContentEncodings = "\x6D\x80"
+IdContentEncryption = "\x50\x35"
+IdCueBlockNumber = "\x53\x78"
+IdCueClusterPosition = "\xF1"
+IdCueDuration = "\xB2"
+IdCuePoint = "\xBB"
+IdCueRelativePosition = "\xF0"
+IdCueTime = "\xB3"
+IdCueTrack = "\xF7"
+IdCueTrackPositions = "\xB7"
+IdCues = "\x1C\x53\xBB\x6B"
+IdDateUTC = "\x44\x61"
+IdDateUtc = "\x44\x61"
+IdDefaultDuration = "\x23\xE3\x83"
+IdDiscardPadding = "\x75\xA2"
+IdDisplayHeight = "\x54\xBA"
+IdDisplayUnit = "\x54\xB2"
+IdDisplayWidth = "\x54\xB0"
+IdDocType = "\x42\x82"
+IdDocTypeReadVersion = "\x42\x85"
+IdDocTypeVersion = "\x42\x87"
+IdDuration = "\x44\x89"
+IdEBML = "\x1A\x45\xDF\xA3"
+IdEBMLMaxIDLength = "\x42\xF2"
+IdEBMLMaxSizeLength = "\x42\xF3"
+IdEBMLReadVersion = "\x42\xF7"
+IdEBMLVersion = "\x42\x86"
+IdEbml = "\x1A\x45\xDF\xA3"
+IdEbmlMaxIdLength = "\x42\xF2"
+IdEbmlMaxSizeLength = "\x42\xF3"
+IdEbmlReadVersion = "\x42\xF7"
+IdEbmlVersion = "\x42\x86"
+IdEditionEntry = "\x45\xB9"
+IdFileUsedEndTime = "\x46\x62"
+IdFileUsedStartTime = "\x46\x61"
+IdFlagDefault = "\x88"
+IdFlagEnabled = "\xB9"
+IdFlagForced = "\x55\xAA"
+IdFlagInterlaced = "\x9A"
+IdFlagLacing = "\x9C"
+IdFrameRate = "\x23\x83\xE3"
+IdInfo = "\x15\x49\xA9\x66"
+IdLaceNumber = "\xCC"
+IdLanguage = "\x22\xB5\x9C"
+IdLuminanceMax = "\x55\xD9"
+IdLuminanceMin = "\x55\xDA"
+IdMasteringMetadata = "\x55\xD0"
+IdMatrixCoefficients = "\x55\xB1"
+IdMaxCll = "\x55\xBC"
+IdMaxFall = "\x55\xBD"
+IdMuxingApp = "\x4D\x80"
+IdName = "\x53\x6E"
+IdOutputSamplingFrequency = "\x78\xB5"
+IdPixelCropBottom = "\x54\xAA"
+IdPixelCropLeft = "\x54\xCC"
+IdPixelCropRight = "\x54\xDD"
+IdPixelCropTop = "\x54\xBB"
+IdPixelHeight = "\xBA"
+IdPixelWidth = "\xB0"
+IdPrevSize = "\xAB"
+IdPrimaries = "\x55\xBB"
+IdPrimaryBChromaticityX = "\x55\xD5"
+IdPrimaryBChromaticityY = "\x55\xD6"
+IdPrimaryGChromaticityX = "\x55\xD3"
+IdPrimaryGChromaticityY = "\x55\xD4"
+IdPrimaryRChromaticityX = "\x55\xD1"
+IdPrimaryRChromaticityY = "\x55\xD2"
+IdProjection = "\x76\x70"
+IdProjectionPosePitch = "\x76\x74"
+IdProjectionPoseRoll = "\x76\x75"
+IdProjectionPoseYaw = "\x76\x73"
+IdProjectionPrivate = "\x76\x72"
+IdProjectionType = "\x76\x71"
+IdRange = "\x55\xB9"
+IdReferenceBlock = "\xFB"
+IdSamplingFrequency = "\xB5"
+IdSeek = "\x4D\xBB"
+IdSeekHead = "\x11\x4D\x9B\x74"
+IdSeekID = "\x53\xAB"
+IdSeekPosition = "\x53\xAC"
+IdSeekPreRoll = "\x56\xBB"
+IdSegment = "\x18\x53\x80\x67"
+IdSimpleBlock = "\xA3"
+IdSimpleTag = "\x67\xC8"
+IdSliceDuration = "\xCF"
+IdSlices = "\x8E"
+IdStereoMode = "\x53\xB8"
+IdTag = "\x73\x73"
+IdTagBinary = "\x44\x85"
+IdTagDefault = "\x44\x84"
+IdTagLanguage = "\x44\x7A"
+IdTagName = "\x45\xA3"
+IdTagString = "\x44\x87"
+IdTagTrackUid = "\x63\xC5"
+IdTags = "\x12\x54\xC3\x67"
+IdTargetType = "\x63\xCA"
+IdTargetTypeValue = "\x68\xCA"
+IdTargets = "\x63\xC0"
+IdTimeSlice = "\xE8"
+IdTimecode = "\xE7"
+IdTimecodeScale = "\x2A\xD7\xB1"
+IdTitle = "\x7B\xA9"
+IdTrackEntry = "\xAE"
+IdTrackNumber = "\xD7"
+IdTrackType = "\x83"
+IdTrackUID = "\x73\xC5"
+IdTracks = "\x16\x54\xAE\x6B"
+IdTransferCharacteristics = "\x55\xBA"
+IdTrickMasterTrackSegmentUID = "\xC4"
+IdTrickMasterTrackUID = "\xC7"
+IdTrickTrackFlag = "\xC6"
+IdTrickTrackSegmentUID = "\xC1"
+IdTrickTrackUID = "\xC0"
+IdVideo = "\xE0"
+IdVoid = "\xEC"
+IdWhitePointChromaticityX = "\x55\xD7"
+IdWhitePointChromaticityY = "\x55\xD8"
+IdWritingApp = "\x57\x41"
+
+# Interesting sizes.
+SizeUnknown = "\xFF"
+
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index 224aeb3..f1e504d 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -58,3 +58,59 @@
         "WriterFuzzerBase.cpp",
     ],
 }
+
+cc_fuzz {
+    name: "amrnb_writer_fuzzer",
+    defaults: ["writer-fuzzer-defaults"],
+    srcs: [
+        "amr_writer_fuzzer.cpp",
+    ],
+    cflags: [
+        "-DAMRNB",
+    ],
+}
+
+cc_fuzz {
+    name: "amrwb_writer_fuzzer",
+    defaults: ["writer-fuzzer-defaults"],
+    srcs: [
+        "amr_writer_fuzzer.cpp",
+    ],
+}
+
+cc_fuzz {
+    name : "mpeg4_writer_fuzzer",
+    defaults : ["writer-fuzzer-defaults"],
+    srcs : [
+        "mpeg4_writer_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_esds",
+    ],
+}
+
+cc_fuzz {
+    name : "ogg_writer_fuzzer",
+    defaults : ["writer-fuzzer-defaults"],
+    srcs : [
+        "ogg_writer_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libogg",
+    ],
+}
+
+cc_fuzz {
+    name : "webm_writer_fuzzer",
+    defaults : ["writer-fuzzer-defaults"],
+    srcs : [
+        "webm_writer_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_webm",
+        "libdatasource",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+}
diff --git a/media/libstagefright/writer_fuzzers/README.md b/media/libstagefright/writer_fuzzers/README.md
index 037236a..0d21031 100644
--- a/media/libstagefright/writer_fuzzers/README.md
+++ b/media/libstagefright/writer_fuzzers/README.md
@@ -1,7 +1,11 @@
 # Fuzzer for writers
 
 ## Table of contents
-   [libwriterfuzzerbase](#WriterFuzzerBase)
++  [libwriterfuzzerbase](#WriterFuzzerBase)
++  [Amr Writer](#amrWriterFuzzer)
++  [MPEG4 Writer](#mpeg4WriterFuzzer)
++  [OGG Writer](#oggWriterFuzzer)
++  [WEBM Writer](#webmWriterFuzzer)
 
 # <a name="WriterFuzzerBase"></a> Fuzzer for libwriterfuzzerbase
 All the writers have a common API - creating a writer, adding a source for
@@ -40,6 +44,56 @@
 This ensures that the plugin tolerates any kind of input (huge,
 malformed, etc) and thereby increasing the chance of identifying vulnerabilities.
 
+# <a name="amrWriterFuzzer"></a> Fuzzer for Amr Writer
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR writer uses the `WriterFuzzerBase` class and
+implements only the `createWriter` to create the AMR writer class.
+
+##### Other considerations
+ * Two fuzzer binaries - amrnb_writer_fuzzer and amrwb_writer_fuzzer are generated based on the presence of a flag - 'AMRNB'
+
+# <a name="mpeg4WriterFuzzer"></a> Fuzzer for MPEG4 Writer
+
+## Plugin Design Considerations
+The fuzzer plugin for MPEG4 writer uses the `WriterFuzzerBase` class and
+implements only the `createWriter` to create the MPEG4 writer class.
+
+# <a name="oggWriterFuzzer"></a> Fuzzer for OGG Writer
+
+## Plugin Design Considerations
+The fuzzer plugin for OGG writer uses the `WriterFuzzerBase` class and
+implements only the `createWriter` to create the OGG writer class.
+
+# <a name="webmWriterFuzzer"></a> Fuzzer for WEBM Writer
+
+## Plugin Design Considerations
+The fuzzer plugin for WEBM writer uses the `WriterFuzzerBase` class and
+implements only the `createWriter` to create the WEBM writer class.
+
+## Build
+
+This describes steps to build writer fuzzer binaries.
+
+### Android
+
+`*` = amrnb/amrwb/mpeg4/ogg/webm
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) *_writer_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some media files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/*_writer_fuzzer/*_writer_fuzzer CORPUS_DIR
+```
+
 
 ## References:
  * http://llvm.org/docs/LibFuzzer.html
diff --git a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
index 65593e7..844db39 100644
--- a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
+++ b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
@@ -218,7 +218,7 @@
     }
 }
 
-void WriterFuzzerBase::processData(const uint8_t *data, size_t size) {
+void WriterFuzzerBase::initFileWriterAndProcessData(const uint8_t *data, size_t size) {
     if (!createOutputFile()) {
         return;
     }
diff --git a/media/libstagefright/writer_fuzzers/amr_writer_fuzzer.cpp b/media/libstagefright/writer_fuzzers/amr_writer_fuzzer.cpp
new file mode 100644
index 0000000..bbb6f9f
--- /dev/null
+++ b/media/libstagefright/writer_fuzzers/amr_writer_fuzzer.cpp
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include "WriterFuzzerBase.h"
+
+#include <media/stagefright/AMRWriter.h>
+
+using namespace android;
+
+class AmrWriterFuzzer : public WriterFuzzerBase {
+   public:
+    bool createWriter();
+};
+
+bool AmrWriterFuzzer::createWriter() {
+    mWriter = new AMRWriter(mFd);
+    if (!mWriter) {
+        return false;
+    }
+    mFileMeta = new MetaData;
+#ifdef AMRNB
+    mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+#else
+    mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+#endif
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    AmrWriterFuzzer writerFuzzer;
+    writerFuzzer.initFileWriterAndProcessData(data, size);
+    return 0;
+}
diff --git a/media/libstagefright/writer_fuzzers/include/WriterFuzzerBase.h b/media/libstagefright/writer_fuzzers/include/WriterFuzzerBase.h
index d819d43..da06463 100644
--- a/media/libstagefright/writer_fuzzers/include/WriterFuzzerBase.h
+++ b/media/libstagefright/writer_fuzzers/include/WriterFuzzerBase.h
@@ -107,7 +107,7 @@
 
     void sendBuffersToWriter(sp<MediaAdapter>& currentTrack, int32_t trackIndex);
 
-    void processData(const uint8_t* data, size_t size);
+    void initFileWriterAndProcessData(const uint8_t* data, size_t size);
 
    protected:
     class BufferSource {
diff --git a/media/libstagefright/writer_fuzzers/mpeg4_writer_fuzzer.cpp b/media/libstagefright/writer_fuzzers/mpeg4_writer_fuzzer.cpp
new file mode 100644
index 0000000..99bd2b6
--- /dev/null
+++ b/media/libstagefright/writer_fuzzers/mpeg4_writer_fuzzer.cpp
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include "WriterFuzzerBase.h"
+
+#include <media/stagefright/MPEG4Writer.h>
+
+using namespace android;
+
+class Mpeg4WriterFuzzer : public WriterFuzzerBase {
+   public:
+    bool createWriter();
+};
+
+bool Mpeg4WriterFuzzer::createWriter() {
+    mWriter = new MPEG4Writer(mFd);
+    if (!mWriter) {
+        return false;
+    }
+    mFileMeta = new MetaData;
+    mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    Mpeg4WriterFuzzer writerFuzzer;
+    writerFuzzer.initFileWriterAndProcessData(data, size);
+    return 0;
+}
diff --git a/media/libstagefright/writer_fuzzers/ogg_writer_fuzzer.cpp b/media/libstagefright/writer_fuzzers/ogg_writer_fuzzer.cpp
new file mode 100644
index 0000000..ae9c94c
--- /dev/null
+++ b/media/libstagefright/writer_fuzzers/ogg_writer_fuzzer.cpp
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include "WriterFuzzerBase.h"
+
+#include <media/stagefright/OggWriter.h>
+
+using namespace android;
+
+class OGGWriterFuzzer : public WriterFuzzerBase {
+   public:
+    bool createWriter();
+};
+
+bool OGGWriterFuzzer::createWriter() {
+    mWriter = new OggWriter(mFd);
+    if (!mWriter) {
+        return false;
+    }
+    mFileMeta = new MetaData;
+    mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    OGGWriterFuzzer writerFuzzer;
+    writerFuzzer.initFileWriterAndProcessData(data, size);
+    return 0;
+}
diff --git a/media/libstagefright/writer_fuzzers/webm_writer_fuzzer.cpp b/media/libstagefright/writer_fuzzers/webm_writer_fuzzer.cpp
new file mode 100644
index 0000000..0a91b72
--- /dev/null
+++ b/media/libstagefright/writer_fuzzers/webm_writer_fuzzer.cpp
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+#include "WriterFuzzerBase.h"
+
+#include <webm/WebmWriter.h>
+
+using namespace android;
+
+class WEBMWriterFuzzer : public WriterFuzzerBase {
+   public:
+    bool createWriter();
+};
+
+bool WEBMWriterFuzzer::createWriter() {
+    mWriter = new WebmWriter(mFd);
+    if (!mWriter) {
+        return false;
+    }
+    mFileMeta = new MetaData;
+    mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    WEBMWriterFuzzer writerFuzzer;
+    writerFuzzer.initFileWriterAndProcessData(data, size);
+    return 0;
+}
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index ee4def5..6aed994 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -83,6 +83,7 @@
 
     static_libs: [
         "libgrallocusage",
+        "libnativehelper_lazy",
     ],
 
     header_libs: [
@@ -111,7 +112,6 @@
         "libgui",
         "libui",
         "libmediandk_utils",
-        "libnativehelper",
     ],
 
     export_header_lib_headers: ["jni_headers"],
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 941e3a1..eb6d510 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -40,18 +40,8 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
-#ifndef __ANDROID__
-// Value copied from 'bionic/libc/include/android/api-level.h' which is not available on
-// non Android systems. It is set to 10000 which is same as __ANDROID_API_FUTURE__ value.
-#ifndef __ANDROID_API__
-#define __ANDROID_API__ 10000
-#endif
-
-// Value copied from 'bionic/libc/include/android/versioning.h' which is not available on
-// non Android systems
-#ifndef __INTRODUCED_IN
-#define __INTRODUCED_IN(api_level)
-#endif
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
 
 #include "NdkMediaError.h"
@@ -312,13 +302,11 @@
  */
 extern const char* AMEDIAFORMAT_KEY_LOW_LATENCY __INTRODUCED_IN(30);
 
-#if __ANDROID_API__ >= 31
 extern const char* AMEDIAFORMAT_KEY_HDR10_PLUS_INFO __INTRODUCED_IN(31);
 extern const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS __INTRODUCED_IN(31);
 extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C __INTRODUCED_IN(31);
 extern const char* AMEDIAFORMAT_KEY_XMP_OFFSET __INTRODUCED_IN(31);
 extern const char* AMEDIAFORMAT_KEY_XMP_SIZE __INTRODUCED_IN(31);
-#endif /* __ANDROID_API__ >= 31 */
 
 __END_DECLS
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 7c0f2ce..9132086 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -285,13 +285,14 @@
 
     virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) = 0;
 
-    virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
-                                                           product_strategy_t &productStrategy) = 0;
+    virtual status_t getProductStrategyFromAudioAttributes(
+            const AudioAttributes &aa, product_strategy_t &productStrategy,
+            bool fallbackOnDefault) = 0;
 
     virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) = 0;
 
-    virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
-                                                       volume_group_t &volumeGroup) = 0;
+    virtual status_t getVolumeGroupFromAudioAttributes(
+            const AudioAttributes &aa, volume_group_t &volumeGroup, bool fallbackOnDefault) = 0;
 
     virtual bool     isCallScreenModeSupported() = 0;
 
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 3e42e2d..9bef97c 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -53,7 +53,7 @@
                                                audio_policy_dev_state_t /*state*/) override;
 
     product_strategy_t getProductStrategyForAttributes(
-            const audio_attributes_t &attr) const override;
+            const audio_attributes_t &attr, bool fallbackOnDefault = true) const override;
 
     audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const override;
 
@@ -79,9 +79,11 @@
 
     VolumeGroupVector getVolumeGroups() const override;
 
-    volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const override;
+    volume_group_t getVolumeGroupForAttributes(
+            const audio_attributes_t &attr, bool fallbackOnDefault = true) const override;
 
-    volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const override;
+    volume_group_t getVolumeGroupForStreamType(
+            audio_stream_type_t stream, bool fallbackOnDefault = true) const override;
 
     status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
 
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index c505456..54625ea 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -129,7 +129,8 @@
      * @param attr
      * @return applicable product strategy for the given attribute, default if none applicable.
      */
-    product_strategy_t getProductStrategyForAttributes(const audio_attributes_t &attr) const;
+    product_strategy_t getProductStrategyForAttributes(
+            const audio_attributes_t &attr, bool fallbackOnDefault = true) const;
 
     product_strategy_t getProductStrategyForStream(audio_stream_type_t stream) const;
 
@@ -153,9 +154,11 @@
 
     std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
 
-    volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const;
+    volume_group_t getVolumeGroupForAttributes(
+            const audio_attributes_t &attr, bool fallbackOnDefault = true) const;
 
-    volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const;
+    volume_group_t getVolumeGroupForStreamType(
+            audio_stream_type_t stream, bool fallbackOnDefault = true) const;
 
     volume_group_t getDefaultVolumeGroup() const;
 
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 2137dd0..37e4caa 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -74,9 +74,10 @@
     return NO_ERROR;
 }
 
-product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
+product_strategy_t EngineBase::getProductStrategyForAttributes(
+        const audio_attributes_t &attr, bool fallbackOnDefault) const
 {
-    return mProductStrategies.getProductStrategyForAttributes(attr);
+    return mProductStrategies.getProductStrategyForAttributes(attr, fallbackOnDefault);
 }
 
 audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
@@ -320,14 +321,16 @@
     return group;
 }
 
-volume_group_t EngineBase::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
+volume_group_t EngineBase::getVolumeGroupForAttributes(
+        const audio_attributes_t &attr, bool fallbackOnDefault) const
 {
-    return mProductStrategies.getVolumeGroupForAttributes(attr);
+    return mProductStrategies.getVolumeGroupForAttributes(attr, fallbackOnDefault);
 }
 
-volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t stream) const
+volume_group_t EngineBase::getVolumeGroupForStreamType(
+        audio_stream_type_t stream, bool fallbackOnDefault) const
 {
-    return mProductStrategies.getVolumeGroupForStreamType(stream);
+    return mProductStrategies.getVolumeGroupForStreamType(stream, fallbackOnDefault);
 }
 
 status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index 060568a..d4cea5a 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -169,7 +169,7 @@
 }
 
 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
-        const audio_attributes_t &attr) const
+        const audio_attributes_t &attr, bool fallbackOnDefault) const
 {
     for (const auto &iter : *this) {
         if (iter.second->matches(attr)) {
@@ -178,7 +178,7 @@
     }
     ALOGV("%s: No matching product strategy for attributes %s, return default", __FUNCTION__,
           toString(attr).c_str());
-    return getDefault();
+    return fallbackOnDefault? getDefault() : PRODUCT_STRATEGY_NONE;
 }
 
 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
@@ -272,7 +272,8 @@
     return at(psId)->getDeviceAddress();
 }
 
-volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
+volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(
+        const audio_attributes_t &attr, bool fallbackOnDefault) const
 {
     for (const auto &iter : *this) {
         volume_group_t group = iter.second->getVolumeGroupForAttributes(attr);
@@ -280,10 +281,11 @@
             return group;
         }
     }
-    return getDefaultVolumeGroup();
+    return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
 }
 
-volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const
+volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(
+        audio_stream_type_t stream, bool fallbackOnDefault) const
 {
     for (const auto &iter : *this) {
         volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
@@ -292,7 +294,7 @@
         }
     }
     ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
-    return getDefaultVolumeGroup();
+    return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
 }
 
 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index a9b536b..f0a01d3 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -110,11 +110,12 @@
      * Get the strategy selected for a given audio attributes.
      *
      * @param[in] audio attributes to get the selected @product_strategy_t followed by.
-     *
+     * @param fallbackOnDefault if true, will return the fallback strategy if the attributes
+     * are not explicitly assigned to a given strategy.
      * @return @product_strategy_t to be followed.
      */
     virtual product_strategy_t getProductStrategyForAttributes(
-            const audio_attributes_t &attr) const = 0;
+            const audio_attributes_t &attr, bool fallbackOnDefault = true) const = 0;
 
     /**
      * @brief getOutputDevicesForAttributes retrieves the devices to be used for given
@@ -271,19 +272,25 @@
      * @brief getVolumeGroupForAttributes gets the appropriate volume group to be used for a given
      * Audio Attributes.
      * @param attr to be considered
+     * @param fallbackOnDefault if true, will return the fallback volume group if the attributes
+     * are not associated to any volume group.
      * @return volume group associated to the given audio attributes, default group if none
      * applicable, VOLUME_GROUP_NONE if no default group defined.
      */
-    virtual volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const = 0;
+    virtual volume_group_t getVolumeGroupForAttributes(
+            const audio_attributes_t &attr, bool fallbackOnDefault = true) const = 0;
 
     /**
      * @brief getVolumeGroupForStreamType gets the appropriate volume group to be used for a given
      * legacy stream type
      * @param stream type to be considered
+     * @param fallbackOnDefault if true, will return the fallback volume group if the stream type
+     * is not associated to any volume group.
      * @return volume group associated to the given stream type, default group if none applicable,
      * VOLUME_GROUP_NONE if no default group defined.
      */
-    virtual volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const = 0;
+    virtual volume_group_t getVolumeGroupForStreamType(
+            audio_stream_type_t stream, bool fallbackOnDefault = true) const = 0;
 
     /**
      * @brief listAudioVolumeGroups introspection API to get the Audio Volume Groups, aka
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index 3e47324..b51918a 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -42,8 +42,8 @@
     cmd: "cp $(locations :audio_policy_configuration_files) $(genDir)/. && " +
          "cp $(location :audio_policy_configuration_top_file) $(genDir)/audio_policy_configuration.xml && " +
          "$(location buildPolicyCriterionTypes.py) " +
-         // @todo update if 1428659 is merged "--androidaudiobaseheader $(location :android_audio_base_header_file) " +
-         " --androidaudiobaseheader system/media/audio/include/system/audio-base.h " +
+         " --androidaudiobaseheader $(location :libaudio_system_audio_base) " +
+         " --androidaudiocommonbaseheader $(location :libaudio_system_audio_common_base) " +
          "--audiopolicyconfigurationfile $(genDir)/audio_policy_configuration.xml " +
          "--criteriontypes $(location :audio_policy_engine_criterion_types_template) " +
          "--outputfile $(out)",
@@ -51,6 +51,8 @@
         // The commented inputs must be provided to use this genrule_defaults
         // @todo uncomment if 1428659 is merged":android_audio_base_header_file",
         ":audio_policy_engine_criterion_types_template",
+        ":libaudio_system_audio_base",
+        ":libaudio_system_audio_common_base",
         // ":audio_policy_configuration_top_file",
         // ":audio_policy_configuration_files",
     ],
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index b8b60c1..b5885c0 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -55,6 +55,11 @@
                            metavar="ANDROID_AUDIO_BASE_HEADER",
                            type=argparse.FileType('r'),
                            required=True)
+    argparser.add_argument('--androidaudiocommonbaseheader',
+                           help="Android Audio CommonBase C header file, Mandatory.",
+                           metavar="ANDROID_AUDIO_COMMON_BASE_HEADER",
+                           type=argparse.FileType('r'),
+                           required=True)
     argparser.add_argument('--audiopolicyconfigurationfile',
                            help="Android Audio Policy Configuration file, Mandatory.",
                            metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
@@ -176,12 +181,12 @@
 #   -Output devices type
 #   -Input devices type
 #
-def parseAndroidAudioFile(androidaudiobaseheaderFile):
+def parseAndroidAudioFile(androidaudiobaseheaderFile, androidaudiocommonbaseheaderFile):
     #
     # Adaptation table between Android Enumeration prefix and Audio PFW Criterion type names
     #
     criterion_mapping_table = {
-        'AUDIO_MODE' : "AndroidModeType",
+        'HAL_AUDIO_MODE' : "AndroidModeType",
         'AUDIO_DEVICE_OUT' : "OutputDevicesMaskType",
         'AUDIO_DEVICE_IN' : "InputDevicesMaskType"}
 
@@ -196,9 +201,9 @@
     ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
 
     criteria_pattern = re.compile(
-        r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
-        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
-        r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
+        r"\s*V\((?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
+        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
+        r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])?[0-9a-fA-F]+|[0-9]+)")
 
     logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
 
@@ -209,27 +214,91 @@
                 androidaudiobaseheaderFile.name, line_number, line))
 
             criterion_name = criterion_mapping_table[match.groupdict()['type']]
-            literal = ''.join((w.capitalize() for w in match.groupdict()['literal'].split('_')))
-            numerical_value = match.groupdict()['values']
+            criterion_literal = \
+                ''.join((w.capitalize() for w in match.groupdict()['literal'].split('_')))
+            criterion_numerical_value = match.groupdict()['values']
 
-            # for AUDIO_DEVICE_IN: need to remove sign bit
+            # for AUDIO_DEVICE_IN: need to remove sign bit / rename default to stub
             if criterion_name == "InputDevicesMaskType":
-                numerical_value = str(int(numerical_value, 0) & ~2147483648)
+                if criterion_literal == "Default":
+                    criterion_numerical_value = str(int("0x40000000", 0))
+                else:
+                    try:
+                        string_int = int(criterion_numerical_value, 0)
+                    except ValueError:
+                        # Handle the exception
+                        logging.info("value {}:{} for criterion {} is not a number, ignoring"
+                            .format(criterion_numerical_value, criterion_literal, criterion_name))
+                        continue
+                    criterion_numerical_value = str(int(criterion_numerical_value, 0) & ~2147483648)
+
+            if criterion_name == "OutputDevicesMaskType":
+                if criterion_literal == "Default":
+                    criterion_numerical_value = str(int("0x40000000", 0))
+
+            try:
+                string_int = int(criterion_numerical_value, 0)
+            except ValueError:
+                # Handle the exception
+                logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+                    .format(criterion_numerical_value, criterion_literal, criterion_name))
+                continue
 
             # Remove duplicated numerical values
-            if int(numerical_value, 0) in all_criteria[criterion_name].values():
+            if int(criterion_numerical_value, 0) in all_criteria[criterion_name].values():
                 logging.info("criterion {} duplicated values:".format(criterion_name))
-                logging.info("{}:{}".format(numerical_value, literal))
+                logging.info("{}:{}".format(criterion_numerical_value, criterion_literal))
                 logging.info("KEEPING LATEST")
                 for key in list(all_criteria[criterion_name]):
-                    if all_criteria[criterion_name][key] == int(numerical_value, 0):
+                    if all_criteria[criterion_name][key] == int(criterion_numerical_value, 0):
                         del all_criteria[criterion_name][key]
 
-            all_criteria[criterion_name][literal] = int(numerical_value, 0)
+            all_criteria[criterion_name][criterion_literal] = int(criterion_numerical_value, 0)
 
             logging.debug("type:{},".format(criterion_name))
-            logging.debug("iteral:{},".format(literal))
-            logging.debug("values:{}.".format(numerical_value))
+            logging.debug("iteral:{},".format(criterion_literal))
+            logging.debug("values:{}.".format(criterion_numerical_value))
+
+    logging.info("Checking Android Common Header file {}".format(androidaudiocommonbaseheaderFile))
+
+    criteria_pattern = re.compile(
+        r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
+        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
+        r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])?[0-9a-fA-F]+|[0-9]+)")
+
+    for line_number, line in enumerate(androidaudiocommonbaseheaderFile):
+        match = criteria_pattern.match(line)
+        if match:
+            logging.debug("The following line is VALID: {}:{}\n{}".format(
+                androidaudiocommonbaseheaderFile.name, line_number, line))
+
+            criterion_name = criterion_mapping_table[match.groupdict()['type']]
+            criterion_literal = \
+                ''.join((w.capitalize() for w in match.groupdict()['literal'].split('_')))
+            criterion_numerical_value = match.groupdict()['values']
+
+            try:
+                string_int = int(criterion_numerical_value, 0)
+            except ValueError:
+                # Handle the exception
+                logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+                    .format(criterion_numerical_value, criterion_literal, criterion_name))
+                continue
+
+            # Remove duplicated numerical values
+            if int(criterion_numerical_value, 0) in all_criteria[criterion_name].values():
+                logging.info("criterion {} duplicated values:".format(criterion_name))
+                logging.info("{}:{}".format(criterion_numerical_value, criterion_literal))
+                logging.info("KEEPING LATEST")
+                for key in list(all_criteria[criterion_name]):
+                    if all_criteria[criterion_name][key] == int(criterion_numerical_value, 0):
+                        del all_criteria[criterion_name][key]
+
+            all_criteria[criterion_name][criterion_literal] = int(criterion_numerical_value, 0)
+
+            logging.debug("type:{},".format(criterion_name))
+            logging.debug("iteral:{},".format(criterion_literal))
+            logging.debug("values:{}.".format(criterion_numerical_value))
 
     return all_criteria
 
@@ -238,7 +307,8 @@
     logging.root.setLevel(logging.INFO)
     args = parseArgs()
 
-    all_criteria = parseAndroidAudioFile(args.androidaudiobaseheader)
+    all_criteria = parseAndroidAudioFile(args.androidaudiobaseheader,
+                                         args.androidaudiocommonbaseheader)
 
     address_criteria = parseAndroidAudioPolicyConfigurationFile(args.audiopolicyconfigurationfile)
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 340eca4..04bc5f1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1214,7 +1214,7 @@
                 (config->channel_mask == desc->getChannelMask()) &&
                 (session == desc->mDirectClientSession)) {
                 desc->mDirectOpenCount++;
-                ALOGI("%s reusing direct output %d for session %d", __func__,
+                ALOGV("%s reusing direct output %d for session %d", __func__,
                     mOutputs.keyAt(i), session);
                 *output = mOutputs.keyAt(i);
                 return NO_ERROR;
@@ -2139,7 +2139,7 @@
         *inputType = API_INPUT_LEGACY;
         device = inputDesc->getDevice();
 
-        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
         goto exit;
     }
 
@@ -3322,7 +3322,7 @@
 status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy,
                                                           device_role_t role)
 {
-    ALOGI("%s() strategy=%d role=%d", __func__, strategy, role);
+    ALOGV("%s() strategy=%d role=%d", __func__, strategy, role);
 
     status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role);
     if (status != NO_ERROR) {
@@ -3424,7 +3424,7 @@
 
 status_t AudioPolicyManager::setUserIdDeviceAffinities(int userId,
         const AudioDeviceTypeAddrVector& devices) {
-    ALOGI("%s() userId=%d num devices %zu", __func__, userId, devices.size());
+    ALOGV("%s() userId=%d num devices %zu", __func__, userId, devices.size());
     if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
         return BAD_VALUE;
     }
@@ -3443,7 +3443,7 @@
 }
 
 status_t AudioPolicyManager::removeUserIdDeviceAffinities(int userId) {
-    ALOGI("%s() userId=%d", __FUNCTION__, userId);
+    ALOGV("%s() userId=%d", __FUNCTION__, userId);
     status_t status = mPolicyMixes.removeUserIdDeviceAffinities(userId);
     if (status != NO_ERROR) {
         ALOGE("%s() Could not remove all device affinities fo userId = %d",
@@ -4945,7 +4945,8 @@
             const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
             DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
             if (availProfileDevices.isEmpty()) {
-                ALOGE("%s: Input device list is empty!", __FUNCTION__);
+                ALOGV("%s: Input device list is empty! for profile %s",
+                    __func__, inProfile->getTagName().c_str());
                 continue;
             }
             sp<AudioInputDescriptor> inputDesc =
@@ -6684,7 +6685,7 @@
         for (auto it = channelMasks.begin(); it != channelMasks.end();) {
             audio_channel_mask_t channelMask = *it;
             if (channelMask & ~AUDIO_CHANNEL_OUT_STEREO) {
-                ALOGI("%s: force NEVER, so remove channelMask 0x%08x", __FUNCTION__, channelMask);
+                ALOGV("%s: force NEVER, so remove channelMask 0x%08x", __FUNCTION__, channelMask);
                 it = channelMasks.erase(it);
             } else {
                 ++it;
@@ -6704,7 +6705,7 @@
         // If not then add 5.1 support.
         if (!supports5dot1) {
             channelMasks.insert(AUDIO_CHANNEL_OUT_5POINT1);
-            ALOGI("%s: force MANUAL or ALWAYS, so adding channelMask for 5.1 surround", __func__);
+            ALOGV("%s: force MANUAL or ALWAYS, so adding channelMask for 5.1 surround", __func__);
         }
     }
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index d3ceb1b..d0c8673 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -329,11 +329,14 @@
             return mEngine->listAudioProductStrategies(strategies);
         }
 
-        virtual status_t getProductStrategyFromAudioAttributes(const AudioAttributes &aa,
-                                                               product_strategy_t &productStrategy)
+        virtual status_t getProductStrategyFromAudioAttributes(
+                const AudioAttributes &aa, product_strategy_t &productStrategy,
+                bool fallbackOnDefault)
         {
-            productStrategy = mEngine->getProductStrategyForAttributes(aa.getAttributes());
-            return productStrategy != PRODUCT_STRATEGY_NONE ? NO_ERROR : BAD_VALUE;
+            productStrategy = mEngine->getProductStrategyForAttributes(
+                    aa.getAttributes(), fallbackOnDefault);
+            return (fallbackOnDefault && productStrategy == PRODUCT_STRATEGY_NONE) ?
+                    BAD_VALUE : NO_ERROR;
         }
 
         virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups)
@@ -341,11 +344,13 @@
             return mEngine->listAudioVolumeGroups(groups);
         }
 
-        virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
-                                                           volume_group_t &volumeGroup)
+        virtual status_t getVolumeGroupFromAudioAttributes(
+                const AudioAttributes &aa, volume_group_t &volumeGroup, bool fallbackOnDefault)
         {
-            volumeGroup = mEngine->getVolumeGroupForAttributes(aa.getAttributes());
-            return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
+            volumeGroup = mEngine->getVolumeGroupForAttributes(
+                        aa.getAttributes(), fallbackOnDefault);
+            return (fallbackOnDefault && volumeGroup == VOLUME_GROUP_NONE) ?
+                    BAD_VALUE : NO_ERROR;
         }
 
         bool isCallScreenModeSupported() override;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index caf7309..07122cc 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -1804,7 +1804,7 @@
 Status AudioPolicyService::getSurroundFormats(
         bool reported, media::Int* count,
         std::vector<media::audio::common::AudioFormat>* formats,
-        bool* _aidl_return) {
+        std::vector<bool>* formatsEnabled) {
     unsigned int numSurroundFormats = VALUE_OR_RETURN_BINDER_STATUS(
             convertIntegral<unsigned int>(count->value));
     if (numSurroundFormats > MAX_ITEMS_PER_LIST) {
@@ -1812,6 +1812,7 @@
     }
     unsigned int numSurroundFormatsReq = numSurroundFormats;
     std::unique_ptr<audio_format_t[]>surroundFormats(new audio_format_t[numSurroundFormats]);
+    std::unique_ptr<bool[]>surroundFormatsEnabled(new bool[numSurroundFormats]);
 
     if (mAudioPolicyManager == NULL) {
         return binderStatusFromStatusT(NO_INIT);
@@ -1820,11 +1821,15 @@
     AutoCallerClear acc;
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
             mAudioPolicyManager->getSurroundFormats(&numSurroundFormats, surroundFormats.get(),
-                                                    _aidl_return, reported)));
+                                                    surroundFormatsEnabled.get(), reported)));
     numSurroundFormatsReq = std::min(numSurroundFormats, numSurroundFormatsReq);
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
             convertRange(surroundFormats.get(), surroundFormats.get() + numSurroundFormatsReq,
                          std::back_inserter(*formats), legacy2aidl_audio_format_t_AudioFormat)));
+    formatsEnabled->insert(
+            formatsEnabled->begin(),
+            surroundFormatsEnabled.get(),
+            surroundFormatsEnabled.get() + numSurroundFormatsReq);
     count->value = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<uint32_t>(numSurroundFormats));
     return Status::ok();
 }
@@ -1922,7 +1927,7 @@
 }
 
 Status AudioPolicyService::getProductStrategyFromAudioAttributes(
-        const media::AudioAttributesEx& aaAidl, int32_t* _aidl_return) {
+        const media::AudioAttributesEx& aaAidl, bool fallbackOnDefault, int32_t* _aidl_return) {
     AudioAttributes aa = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioAttributesEx_AudioAttributes(aaAidl));
     product_strategy_t productStrategy;
@@ -1932,8 +1937,8 @@
     }
     Mutex::Autolock _l(mLock);
     RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
-            mAudioPolicyManager->getProductStrategyFromAudioAttributes(aa,
-                                                                       productStrategy)));
+            mAudioPolicyManager->getProductStrategyFromAudioAttributes(
+                    aa, productStrategy, fallbackOnDefault)));
     *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
             legacy2aidl_product_strategy_t_int32_t(productStrategy));
     return Status::ok();
@@ -1954,8 +1959,8 @@
     return Status::ok();
 }
 
-Status AudioPolicyService::getVolumeGroupFromAudioAttributes(const media::AudioAttributesEx& aaAidl,
-                                                             int32_t* _aidl_return) {
+Status AudioPolicyService::getVolumeGroupFromAudioAttributes(
+        const media::AudioAttributesEx& aaAidl, bool fallbackOnDefault, int32_t* _aidl_return) {
     AudioAttributes aa = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioAttributesEx_AudioAttributes(aaAidl));
     volume_group_t volumeGroup;
@@ -1966,7 +1971,8 @@
     Mutex::Autolock _l(mLock);
     RETURN_IF_BINDER_ERROR(
             binderStatusFromStatusT(
-                    mAudioPolicyManager->getVolumeGroupFromAudioAttributes(aa, volumeGroup)));
+                    mAudioPolicyManager->getVolumeGroupFromAudioAttributes(
+                            aa, volumeGroup, fallbackOnDefault)));
     *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_volume_group_t_int32_t(volumeGroup));
     return Status::ok();
 }
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index e25d542..a11b2cc 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -184,7 +184,7 @@
                                      float* _aidl_return) override;
     binder::Status getSurroundFormats(bool reported, media::Int* count,
                                       std::vector<media::audio::common::AudioFormat>* formats,
-                                      bool* _aidl_return) override;
+                                      std::vector<bool>* formatsEnabled) override;
     binder::Status getHwOffloadEncodingFormatsSupportedForA2DP(
             std::vector<media::audio::common::AudioFormat>* _aidl_return) override;
     binder::Status setSurroundFormatEnabled(media::audio::common::AudioFormat audioFormat,
@@ -196,10 +196,12 @@
     binder::Status listAudioProductStrategies(
             std::vector<media::AudioProductStrategy>* _aidl_return) override;
     binder::Status getProductStrategyFromAudioAttributes(const media::AudioAttributesEx& aa,
+                                                         bool fallbackOnDefault,
                                                          int32_t* _aidl_return) override;
     binder::Status listAudioVolumeGroups(
             std::vector<media::AudioVolumeGroup>* _aidl_return) override;
     binder::Status getVolumeGroupFromAudioAttributes(const media::AudioAttributesEx& aa,
+                                                     bool fallbackOnDefault,
                                                      int32_t* _aidl_return) override;
     binder::Status setRttEnabled(bool enabled) override;
     binder::Status isCallScreenModeSupported(bool* _aidl_return) override;
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index ca2f0c6..df4389b 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 
 #include <media/AudioSystem.h>
+#include <media/TypeConverter.h>
 #include <system/audio.h>
 #include <utils/Log.h>
 
@@ -70,10 +71,18 @@
     ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
 
     for (auto desc : manager.getConfig().getInputDevices()) {
-        ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+        if (attachedDevices.find(desc->type()) == attachedDevices.end()) {
+            std::string deviceType;
+            (void)DeviceConverter::toString(desc->type(), deviceType);
+            ADD_FAILURE() << "Input device \"" << deviceType << "\" not found";
+        }
     }
     for (auto desc : manager.getConfig().getOutputDevices()) {
-        ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+        if (attachedDevices.find(desc->type()) == attachedDevices.end()) {
+            std::string deviceType;
+            (void)DeviceConverter::toString(desc->type(), deviceType);
+            ADD_FAILURE() << "Output device \"" << deviceType << "\" not found";
+        }
     }
 }
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 641e463..1234dfd 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2937,10 +2937,21 @@
             res == AppOpsManager::MODE_ERRORED ? "ERRORED" :
             "UNKNOWN");
 
-    if (res != AppOpsManager::MODE_ALLOWED) {
+    if (res == AppOpsManager::MODE_ERRORED) {
         ALOGI("Camera %s: Access for \"%s\" revoked", mCameraIdStr.string(),
               String8(mClientPackageName).string());
         block();
+    } else if (res == AppOpsManager::MODE_IGNORED) {
+        bool isUidActive = sCameraService->mUidPolicy->isUidActive(mClientUid, mClientPackageName);
+        ALOGI("Camera %s: Access for \"%s\" has been restricted, isUidTrusted %d, isUidActive %d",
+                mCameraIdStr.string(), String8(mClientPackageName).string(),
+                mUidIsTrusted, isUidActive);
+        // If the calling Uid is trusted (a native service), or the client Uid is active (WAR for
+        // b/175320666), the AppOpsManager could return MODE_IGNORED. Do not treat such cases as
+        // error.
+        if (!mUidIsTrusted && !isUidActive) {
+            block();
+        }
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 7606d7d..3204217 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4802,6 +4802,7 @@
                 ATRACE_ASYNC_BEGIN("still capture", mNextRequests[i].halRequest.frame_number);
             }
 
+            e = camera_metadata_ro_entry_t();
             find_camera_metadata_ro_entry(settings, ANDROID_CONTROL_ENABLE_ZSL, &e);
             if ((e.count > 0) && (e.data.u8[0] == ANDROID_CONTROL_ENABLE_ZSL_TRUE)) {
                 isZslCapture = true;
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index b64f726..8e1a88b 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -100,7 +100,7 @@
         "libmediametricsservice",
         "libmediautils",
         "libutils",
-        "mediametricsservice-aidl-unstable-cpp",
+        "mediametricsservice-aidl-cpp",
     ],
     header_libs: [
         "libaudioutils_headers",
@@ -143,7 +143,7 @@
     },
 
     shared_libs: [
-        "mediametricsservice-aidl-unstable-cpp",
+        "mediametricsservice-aidl-cpp",
         "libbase", // android logging
         "libbinder",
         "libcutils",
diff --git a/services/mediametrics/fuzzer/Android.bp b/services/mediametrics/fuzzer/Android.bp
index 6ac9d20..19ed919 100644
--- a/services/mediametrics/fuzzer/Android.bp
+++ b/services/mediametrics/fuzzer/Android.bp
@@ -43,7 +43,7 @@
         "libstagefright",
         "libstatslog",
         "libutils",
-        "mediametricsservice-aidl-unstable-cpp",
+        "mediametricsservice-aidl-cpp",
     ],
 
     include_dirs: [
diff --git a/services/mediametrics/tests/Android.bp b/services/mediametrics/tests/Android.bp
index 94112b0..e9d91c2 100644
--- a/services/mediametrics/tests/Android.bp
+++ b/services/mediametrics/tests/Android.bp
@@ -19,7 +19,7 @@
         "libmediametricsservice",
         "libmediautils",
         "libutils",
-        "mediametricsservice-aidl-unstable-cpp",
+        "mediametricsservice-aidl-cpp",
     ],
 
     header_libs: [
diff --git a/services/tuner/TunerDemux.cpp b/services/tuner/TunerDemux.cpp
index 8346992..ba8d6a7 100644
--- a/services/tuner/TunerDemux.cpp
+++ b/services/tuner/TunerDemux.cpp
@@ -222,6 +222,8 @@
     }
 
     Result res = mDemux->close();
+    mDemux = NULL;
+
     if (res != Result::SUCCESS) {
         return Status::fromServiceSpecificError(static_cast<int32_t>(res));
     }
diff --git a/services/tuner/TunerDescrambler.cpp b/services/tuner/TunerDescrambler.cpp
index 6b2889d..16338db 100644
--- a/services/tuner/TunerDescrambler.cpp
+++ b/services/tuner/TunerDescrambler.cpp
@@ -97,6 +97,8 @@
     }
 
     Result res = mDescrambler->close();
+    mDescrambler = NULL;
+
     if (res != Result::SUCCESS) {
         return Status::fromServiceSpecificError(static_cast<int32_t>(res));
     }
diff --git a/services/tuner/TunerDvr.cpp b/services/tuner/TunerDvr.cpp
index c7227b6..db4e07b 100644
--- a/services/tuner/TunerDvr.cpp
+++ b/services/tuner/TunerDvr.cpp
@@ -154,6 +154,8 @@
     }
 
     Result res = mDvr->close();
+    mDvr = NULL;
+
     if (res != Result::SUCCESS) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
     }
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index af5a600..dc9d246 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -285,6 +285,7 @@
         .srcPort = static_cast<uint16_t>(ipConf.ipAddr.srcPort),
         .dstPort = static_cast<uint16_t>(ipConf.ipAddr.dstPort),
     };
+
     ipConf.ipAddr.srcIpAddress.isIpV6
             ? ipAddr.srcIpAddress.v6(getIpV6Address(ipConf.ipAddr.srcIpAddress))
             : ipAddr.srcIpAddress.v4(getIpV4Address(ipConf.ipAddr.srcIpAddress));
@@ -314,7 +315,7 @@
 }
 
 hidl_array<uint8_t, IP_V6_LENGTH> TunerFilter::getIpV6Address(TunerDemuxIpAddress addr) {
-    hidl_array<uint8_t, IP_V6_LENGTH> ip = {0};
+    hidl_array<uint8_t, IP_V6_LENGTH> ip;
     if (addr.addr.size() != IP_V6_LENGTH) {
         return ip;
     }
@@ -323,7 +324,7 @@
 }
 
 hidl_array<uint8_t, IP_V4_LENGTH> TunerFilter::getIpV4Address(TunerDemuxIpAddress addr) {
-    hidl_array<uint8_t, IP_V4_LENGTH> ip = {0};
+    hidl_array<uint8_t, IP_V4_LENGTH> ip;
     if (addr.addr.size() != IP_V4_LENGTH) {
         return ip;
     }
@@ -541,6 +542,9 @@
         return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
     }
     Result res = mFilter->close();
+    mFilter = NULL;
+    mFilter_1_1 = NULL;
+
     if (res != Result::SUCCESS) {
         return Status::fromServiceSpecificError(static_cast<int32_t>(res));
     }
@@ -620,16 +624,17 @@
         switch (eventExt.getDiscriminator()) {
             case DemuxFilterEventExt::Event::hidl_discriminator::monitorEvent: {
                 getMonitorEvent(eventsExt, tunerEvent);
-                break;
+                return;
             }
             case DemuxFilterEventExt::Event::hidl_discriminator::startId: {
                 getRestartEvent(eventsExt, tunerEvent);
-                break;
+                return;
             }
             default: {
                 break;
             }
         }
+        return;
     }
 
     if (!events.empty()) {
@@ -889,9 +894,6 @@
             tunerMonitor.set<TunerFilterMonitorEvent::cid>(static_cast<int>(monitorEvent.cid()));
             break;
         }
-        default: {
-            break;
-        }
     }
 
     TunerFilterEvent tunerEvent;
diff --git a/services/tuner/TunerFrontend.cpp b/services/tuner/TunerFrontend.cpp
index b85e58b..74b5519 100644
--- a/services/tuner/TunerFrontend.cpp
+++ b/services/tuner/TunerFrontend.cpp
@@ -278,11 +278,13 @@
     }
 
     Result status = mFrontend->close();
-    if (status == Result::SUCCESS) {
-        return Status::ok();
-    }
+    mFrontend = NULL;
+    mFrontend_1_1 = NULL;
 
-    return Status::fromServiceSpecificError(static_cast<int32_t>(status));
+    if (status != Result::SUCCESS) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return Status::ok();
 }
 
 Status TunerFrontend::getStatus(const vector<int32_t>& statusTypes,
@@ -804,13 +806,13 @@
             case FrontendStatusExt1_1::hidl_discriminator::rollOff: {
                 switch (s.rollOff().getDiscriminator()) {
                     case FrontendRollOff::hidl_discriminator::dvbs:
-                        status.set<TunerFrontendStatus::interleaving>((int)s.rollOff().dvbs());
+                        status.set<TunerFrontendStatus::rollOff>((int)s.rollOff().dvbs());
                         break;
                     case FrontendRollOff::hidl_discriminator::isdbs:
-                        status.set<TunerFrontendStatus::interleaving>((int)s.rollOff().isdbs());
+                        status.set<TunerFrontendStatus::rollOff>((int)s.rollOff().isdbs());
                         break;
                     case FrontendRollOff::hidl_discriminator::isdbs3:
-                        status.set<TunerFrontendStatus::interleaving>((int)s.rollOff().isdbs3());
+                        status.set<TunerFrontendStatus::rollOff>((int)s.rollOff().isdbs3());
                         break;
                 }
                 aidlStatus.push_back(status);
diff --git a/services/tuner/TunerLnb.cpp b/services/tuner/TunerLnb.cpp
index 0bfa3fd..4a5acf5 100644
--- a/services/tuner/TunerLnb.cpp
+++ b/services/tuner/TunerLnb.cpp
@@ -97,8 +97,13 @@
         return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
     }
 
-    Result status = mLnb->close();
-    return Status::fromServiceSpecificError(static_cast<int32_t>(status));
+    Result res = mLnb->close();
+    mLnb = NULL;
+
+    if (res != Result::SUCCESS) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
 }
 
 /////////////// ILnbCallback ///////////////////////
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 4f6f16c..b80fd85 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -52,10 +52,10 @@
 TunerService::TunerService() {}
 TunerService::~TunerService() {}
 
-void TunerService::instantiate() {
+binder_status_t TunerService::instantiate() {
     shared_ptr<TunerService> service =
             ::ndk::SharedRefBase::make<TunerService>();
-    AServiceManager_addService(service->asBinder().get(), getServiceName());
+    return AServiceManager_addService(service->asBinder().get(), getServiceName());
 }
 
 bool TunerService::hasITuner() {
@@ -68,23 +68,20 @@
         ALOGE("Failed to get ITuner service");
         return false;
     }
+    mTunerVersion = TUNER_HAL_VERSION_1_0;
+    mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::castFrom(mTuner);
+    if (mTuner_1_1 != nullptr) {
+        mTunerVersion = TUNER_HAL_VERSION_1_1;
+    } else {
+        ALOGE("Failed to get ITuner_1_1 service");
+    }
     return true;
 }
 
 bool TunerService::hasITuner_1_1() {
     ALOGD("hasITuner_1_1");
-    if (mTuner_1_1 != nullptr) {
-        return true;
-    }
-    if (!hasITuner()) {
-        return false;
-    }
-    mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::castFrom(mTuner);
-    if (mTuner_1_1 == nullptr) {
-        ALOGE("Failed to get ITuner_1_1 service");
-        return false;
-    }
-    return true;
+    hasITuner();
+    return (mTunerVersion == TUNER_HAL_VERSION_1_1);
 }
 
 Status TunerService::openDemux(
@@ -300,6 +297,12 @@
     return Status::ok();
 }
 
+Status TunerService::getTunerHalVersion(int* _aidl_return) {
+    hasITuner();
+    *_aidl_return = mTunerVersion;
+    return Status::ok();
+}
+
 void TunerService::updateFrontendResources() {
     hidl_vec<FrontendId> ids;
     Result res = getHidlFrontendIds(ids);
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index ce085cb..cc65b39 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -69,6 +69,10 @@
 
 namespace android {
 
+const static int TUNER_HAL_VERSION_UNKNOWN = 0;
+const static int TUNER_HAL_VERSION_1_0 = 1 << 16;
+const static int TUNER_HAL_VERSION_1_1 = (1 << 16) | 1;
+
 typedef enum {
     FRONTEND,
     LNB,
@@ -93,7 +97,7 @@
 
 public:
     static char const *getServiceName() { return "media.tuner"; }
-    static void instantiate();
+    static binder_status_t instantiate();
     TunerService();
     virtual ~TunerService();
 
@@ -110,6 +114,7 @@
     Status openDescrambler(int32_t descramblerHandle,
             std::shared_ptr<ITunerDescrambler>* _aidl_return) override;
     Status updateTunerResources() override;
+    Status getTunerHalVersion(int* _aidl_return) override;
 
     // TODO: create a map between resource id and handles.
     static int getResourceIdFromHandle(int resourceHandle, int /*type*/) {
@@ -141,6 +146,8 @@
 
     shared_ptr<ITunerResourceManager> mTunerResourceManager;
     int mResourceRequestCount = 0;
+
+    int mTunerVersion = TUNER_HAL_VERSION_UNKNOWN;
 };
 
 } // namespace android
diff --git a/services/tuner/TunerTimeFilter.cpp b/services/tuner/TunerTimeFilter.cpp
index dce76d2..25e1ad9 100644
--- a/services/tuner/TunerTimeFilter.cpp
+++ b/services/tuner/TunerTimeFilter.cpp
@@ -18,6 +18,9 @@
 
 #include "TunerTimeFilter.h"
 
+using ::android::hardware::tv::tuner::V1_0::Result;
+using ::android::hardware::tv::tuner::V1_1::Constant64Bit;
+
 namespace android {
 
 TunerTimeFilter::TunerTimeFilter(sp<ITimeFilter> timeFilter) {
@@ -28,23 +31,76 @@
     mTimeFilter = NULL;
 }
 
-Status TunerTimeFilter::setTimeStamp(int64_t /*timeStamp*/) {
-    return Status::ok();
+Status TunerTimeFilter::setTimeStamp(int64_t timeStamp) {
+    if (mTimeFilter == NULL) {
+        ALOGE("ITimeFilter is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result status = mTimeFilter->setTimeStamp(timeStamp);
+    return Status::fromServiceSpecificError(static_cast<int32_t>(status));
 }
 
 Status TunerTimeFilter::clearTimeStamp() {
-    return Status::ok();
+    if (mTimeFilter == NULL) {
+        ALOGE("ITimeFilter is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result status = mTimeFilter->clearTimeStamp();
+    return Status::fromServiceSpecificError(static_cast<int32_t>(status));
 }
 
-Status TunerTimeFilter::getSourceTime(int64_t* /*_aidl_return*/) {
-    return Status::ok();
+Status TunerTimeFilter::getSourceTime(int64_t* _aidl_return) {
+    if (mTimeFilter == NULL) {
+        *_aidl_return = (int64_t)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+        ALOGE("ITimeFilter is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result status;
+    mTimeFilter->getSourceTime(
+            [&](Result r, uint64_t t) {
+                status = r;
+                *_aidl_return = t;
+            });
+    if (status != Result::SUCCESS) {
+        *_aidl_return = (int64_t)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+    }
+    return Status::fromServiceSpecificError(static_cast<int32_t>(status));
 }
 
-Status TunerTimeFilter::getTimeStamp(int64_t* /*_aidl_return*/) {
-    return Status::ok();
+Status TunerTimeFilter::getTimeStamp(int64_t* _aidl_return) {
+    if (mTimeFilter == NULL) {
+        *_aidl_return = (int64_t)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+        ALOGE("ITimeFilter is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result status;
+    mTimeFilter->getTimeStamp(
+            [&](Result r, uint64_t t) {
+                status = r;
+                *_aidl_return = t;
+            });
+    if (status != Result::SUCCESS) {
+        *_aidl_return = (int64_t)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+    }
+    return Status::fromServiceSpecificError(static_cast<int32_t>(status));
 }
 
 Status TunerTimeFilter::close() {
+    if (mTimeFilter == NULL) {
+        ALOGE("ITimeFilter is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res = mTimeFilter->close();
+    mTimeFilter = NULL;
+
+    if (res != Result::SUCCESS) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
     return Status::ok();
 }
 }  // namespace android
diff --git a/services/tuner/TunerTimeFilter.h b/services/tuner/TunerTimeFilter.h
index 50b8f54..d675319 100644
--- a/services/tuner/TunerTimeFilter.h
+++ b/services/tuner/TunerTimeFilter.h
@@ -19,6 +19,7 @@
 
 #include <aidl/android/media/tv/tuner/BnTunerTimeFilter.h>
 #include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <utils/Log.h>
 
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
index bea8811..f1651b9 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -101,4 +101,11 @@
      */
     // TODO: b/178124017 update TRM in TunerService independently.
     void updateTunerResources();
+
+    /**
+     * Get an integer that carries the Tuner HIDL version. The high 16 bits are the
+     * major version number while the low 16 bits are the minor version. Default
+     * value is unknown version 0.
+     */
+    int getTunerHalVersion();
 }
diff --git a/services/tuner/main_tunerservice.cpp b/services/tuner/main_tunerservice.cpp
index a0e7a9f..586a0e2 100644
--- a/services/tuner/main_tunerservice.cpp
+++ b/services/tuner/main_tunerservice.cpp
@@ -32,7 +32,11 @@
     sp<IServiceManager> sm = defaultServiceManager();
     ALOGD("ServiceManager: %p", sm.get());
 
-    TunerService::instantiate();
+    binder_status_t status = TunerService::instantiate();
+    if (status != STATUS_OK) {
+        ALOGD("Failed to add tuner service as AIDL interface");
+        return -1;
+    }
 
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
diff --git a/tools/mainline_hook.sh b/tools/mainline_hook.sh
deleted file mode 100755
index 58afb49..0000000
--- a/tools/mainline_hook.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/bash
-LOCAL_DIR="$( dirname "${BASH_SOURCE}" )"
-
-MAINLINE_FRAMEWORKS_AV_PATHS=(
-    media/extractors/
-    media/codec2/components/
-    media/libstagefright/codecs/amrnb
-    media/libstagefright/codecs/amrwb
-    media/libstagefright/codecs/amrwbenc
-    media/libstagefright/codecs/common
-    media/libstagefright/codecs/mp3dec
-    media/libstagefright/codecs/m4v_h263
-    media/libstagefright/flac/dec
-    media/libstagefright/mpeg2ts
-)
-
-MAINLINE_EXTERNAL_PROJECTS=(
-    external/aac
-    external/flac
-    external/libaac
-    external/libaom
-    external/libavc
-    external/libgav1
-    external/libgsm
-    external/libhevc
-    external/libmpeg2
-    external/libopus
-    external/libvpx
-    external/libxaac
-    external/sonivox
-    external/tremolo
-)
-
-DEV_BRANCH=qt-aml-media-dev
-RED=$(tput setaf 1)
-NORMAL=$(tput sgr0)
-WARNING_FULL="${RED}Please upload this change in ${DEV_BRANCH} unless it is restricted
-from mainline release until next dessert release. Low/moderate security bugs
-are restricted this way.${NORMAL}"
-WARNING_PARTIAL="${RED}It looks like your change has mainline and non-mainline changes;
-Consider separating them into two separate CLs -- one for mainline files,
-one for non-mainline files.${NORMAL}"
-PWD=`pwd`
-
-if git branch -vv | grep -q -P "^\*[^\[]+\[goog/qt-aml-media-dev"; then
-    # Change appears to be in mainline dev branch
-    exit 0
-fi
-
-for path in "${MAINLINE_EXTERNAL_PROJECTS[@]}"; do
-    if [[ $PWD =~ $path ]]; then
-        echo -e "${RED}The source of truth for '$path' is in ${DEV_BRANCH}.${NORMAL}"
-        echo -e ${WARNING_FULL}
-        exit 1
-    fi
-done
-
-if [[ ! $PWD =~ frameworks/av ]]; then
-    exit 0
-fi
-
-mainline_count=0
-total_count=0
-echo
-while read -r file ; do
-    (( total_count++ ))
-    for path in "${MAINLINE_FRAMEWORKS_AV_PATHS[@]}"; do
-        if [[ $file =~ ^$path ]]; then
-            echo -e "${RED}The source of truth for '$file' is in ${DEV_BRANCH}.${NORMAL}"
-            (( mainline_count++ ))
-            break
-        fi
-    done
-done < <(git show --name-only --pretty=format: $1 | grep -- "$2")
-
-if (( mainline_count != 0 )); then
-    if (( mainline_count == total_count )); then
-        echo -e ${WARNING_FULL}
-    else
-        echo -e ${WARNING_PARTIAL}
-    fi
-    exit 1
-fi
-exit 0
diff --git a/tools/mainline_hook_partial.sh b/tools/mainline_hook_partial.sh
index 3dc6163..74c8ebd 100755
--- a/tools/mainline_hook_partial.sh
+++ b/tools/mainline_hook_partial.sh
Binary files differ
diff --git a/tools/mainline_hook_project.sh b/tools/mainline_hook_project.sh
index 8d35470..e432000 100755
--- a/tools/mainline_hook_project.sh
+++ b/tools/mainline_hook_project.sh
@@ -16,7 +16,8 @@
 
 
 # tunables
-DEV_BRANCH=rvc-dev
+DEV_BRANCH=master
+MAINLINE_BRANCH=mainline-prod
 
 ###
 RED=$(tput setaf 1)
@@ -25,41 +26,27 @@
 ## check the active branch:
 ## * b131183694 d198c6a [goog/master] Fix to handle missing checks on error returned
 ##
-current=`git branch -vv | grep -P "^\*[^\[]+\[goog/"|sed -e 's/^.*\[//' | sed -e 's/:.*$//'| sed -e 's/^goog\///'`
+current=`git branch -vv | grep -P "^\*[^\[]+\[goog/"|sed -e 's/^.*\[//' | sed -e 's/\].*$//'|sed -e 's/:.*$//'| sed -e 's/^goog\///'`
 if [ "${current}" = "" ] ; then
         current=unknown
 fi
 
-if [ "${current}" = "${DEV_BRANCH}" ] ; then
-    # Change appears to be in mainline dev branch
-    exit 0
+# simple reminder that it should also land in mainline branch
+#
+if [ "${current}" != "${MAINLINE_BRANCH}" ] ; then
+        # simple reminder to ensure it hits mainline
+        cat - <<EOF
+You are uploading repo  ${RED}${REPO_PATH}${NORMAL} to branch ${RED}${current}${NORMAL}.
+The mainline branch for ${RED}${REPO_PATH}${NORMAL} is branch ${RED}${MAINLINE_BRANCH}${NORMAL}.
+
+Ensure an appropriate cherry pick or equivalent lands in branch ${RED}${MAINLINE_BRANCH}${NORMAL}.
+Security bulletin timing or unreleased functionality may determine when that can be landed.
+
+EOF
 fi
 
-## warn the user that about not being on the typical/desired branch.
-
-cat - <<EOF
-
-You are uploading repo  ${RED}${REPO_PATH}${NORMAL} to branch ${RED}${current}${NORMAL}. 
-The source of truth for ${RED}${REPO_PATH}${NORMAL} is branch ${RED}${DEV_BRANCH}${NORMAL}. 
-
-Please upload this change to branch ${RED}${DEV_BRANCH}${NORMAL} unless one or more of
-the following apply:
-- this is a security bug prohibited from disclosure before the next dessert release.
-  (moderate security bugs fall into this category).
-- this is new functionality prohibitied from disclosure before the next dessert release.
-EOF
-
-
-##
-## TODO: prompt the user y/n to continue right now instead of re-invoking with no-verify
-## this has to get around how repo buffers stdout from this script such that the output
-## is not flushed before we try to read the input.
-## 
-
-cat - <<EOF
-If you are sure you want to proceed uploading to branch ${RED}${current}${NORMAL},
-re-run your repo upload command with the '--no-verify' option
-
-EOF
-exit 1
+# exit 0 is "all good, no output passed along to user"
+# exit 77 is "all ok, but output is passed along to the user"
+#
+exit 77