Merge "additional codec-related media metrics" into sc-dev
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index f8f2bc6..f33f5f1 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -16,13 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "DrmHal"
-#include <iomanip>
-
-#include <utils/Log.h>
-
-#include <android/binder_manager.h>
 
 #include <aidl/android/media/BnResourceManagerClient.h>
+#include <android/binder_manager.h>
 #include <android/hardware/drm/1.2/types.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
@@ -40,7 +36,9 @@
 #include <mediadrm/DrmSessionManager.h>
 #include <mediadrm/IDrmMetricsConsumer.h>
 #include <mediadrm/DrmUtils.h>
+#include <utils/Log.h>
 
+#include <iomanip>
 #include <vector>
 
 using drm::V1_0::KeyedVector;
@@ -345,10 +343,10 @@
         // must be in passthrough mode, load the default passthrough service
         auto passthrough = IDrmFactory::getService();
         if (passthrough != NULL) {
-            ALOGI("makeDrmFactories: using default passthrough drm instance");
+            DrmUtils::LOG2BI("makeDrmFactories: using default passthrough drm instance");
             factories.push_back(passthrough);
         } else {
-            ALOGE("Failed to find any drm factories");
+            DrmUtils::LOG2BE("Failed to find any drm factories");
         }
     }
     return factories;
@@ -364,7 +362,7 @@
     Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
             [&](Status status, const sp<IDrmPlugin>& hPlugin) {
                 if (status != Status::OK) {
-                    ALOGE("Failed to make drm plugin");
+                    DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d", status);
                     return;
                 }
                 plugin = hPlugin;
@@ -372,7 +370,8 @@
         );
 
     if (!hResult.isOk()) {
-        ALOGE("createPlugin remote call failed");
+        DrmUtils::LOG2BE(uuid, "createPlugin remote call failed: %s",
+                         hResult.description().c_str());
     }
 
     return plugin;
@@ -566,7 +565,8 @@
     Mutex::Autolock autoLock(mLock);
 
     for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
-        if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+        auto hResult = mFactories[i]->isCryptoSchemeSupported(uuid);
+        if (hResult.isOk() && hResult) {
             auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
             if (plugin != NULL) {
                 mPlugin = plugin;
@@ -579,6 +579,7 @@
     }
 
     if (mPlugin == NULL) {
+        DrmUtils::LOG2BE(uuid, "No supported hal instance found");
         mInitCheck = ERROR_UNSUPPORTED;
     } else {
         mInitCheck = OK;
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index 82eadd9..9b125af 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -27,6 +27,8 @@
 #include <android/hardware/drm/1.2/IDrmFactory.h>
 #include <android/hardware/drm/1.3/ICryptoFactory.h>
 #include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <android/hardware/drm/1.4/ICryptoFactory.h>
+#include <android/hardware/drm/1.4/IDrmFactory.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/HidlSupport.h>
 
@@ -68,15 +70,15 @@
 void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
     sp<HServiceManager> serviceManager = HServiceManager::getService();
     if (serviceManager == nullptr) {
-        ALOGE("Failed to get service manager");
-        exit(-1);
+        LOG2BE("Failed to get service manager");
+        return;
     }
 
     serviceManager->listManifestByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> &registered) {
         for (const auto &instance : registered) {
             auto factory = Hal::getService(instance);
             if (factory != nullptr) {
-                ALOGI("found %s %s", Hal::descriptor, instance.c_str());
+                LOG2BI("found %s %s", Hal::descriptor, instance.c_str());
                 if (!uuid || factory->isCryptoSchemeSupported(uuid)) {
                     factories.push_back(factory);
                 }
@@ -106,6 +108,7 @@
     factory->createPlugin(toHidlArray16(uuid), hidl_string(appPackageName),
                           [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin> &hPlugin) {
                               if (status != ::V1_0::Status::OK) {
+                                  LOG2BE(uuid, "MakeDrmPlugin failed: %d", status);
                                   return;
                               }
                               plugin = hPlugin;
@@ -120,6 +123,7 @@
     factory->createPlugin(toHidlArray16(uuid), toHidlVec(initData, initDataSize),
                           [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin> &hPlugin) {
                               if (status != ::V1_0::Status::OK) {
+                                  LOG2BE(uuid, "MakeCryptoPlugin failed: %d", status);
                                   return;
                               }
                               plugin = hPlugin;
@@ -147,6 +151,7 @@
     MakeHidlFactories<::V1_1::IDrmFactory>(uuid, drmFactories);
     MakeHidlFactories<::V1_2::IDrmFactory>(uuid, drmFactories);
     MakeHidlFactories<::V1_3::IDrmFactory>(uuid, drmFactories);
+    MakeHidlFactories<::V1_4::IDrmFactory>(uuid, drmFactories);
     return drmFactories;
 }
 
@@ -165,6 +170,7 @@
     MakeHidlFactories<::V1_1::ICryptoFactory>(uuid, cryptoFactories);
     MakeHidlFactories<::V1_2::ICryptoFactory>(uuid, cryptoFactories);
     MakeHidlFactories<::V1_3::ICryptoFactory>(uuid, cryptoFactories);
+    MakeHidlFactories<::V1_4::ICryptoFactory>(uuid, cryptoFactories);
     return cryptoFactories;
 }
 
@@ -265,5 +271,65 @@
     return ERROR_DRM_UNKNOWN;
 }
 
+namespace {
+char logPriorityToChar(::V1_4::LogPriority priority) {
+    char p = 'U';
+    switch (priority) {
+        case ::V1_4::LogPriority::VERBOSE:  p = 'V'; break;
+        case ::V1_4::LogPriority::DEBUG:    p = 'D'; break;
+        case ::V1_4::LogPriority::INFO:     p = 'I'; break;
+        case ::V1_4::LogPriority::WARN:     p = 'W'; break;
+        case ::V1_4::LogPriority::ERROR:    p = 'E'; break;
+        case ::V1_4::LogPriority::FATAL:    p = 'F'; break;
+        default: p = 'U'; break;
+    }
+    return p;
+}
+}  // namespace
+
+std::string GetExceptionMessage(status_t err, const char *msg,
+                                const Vector<::V1_4::LogMessage> &logs) {
+    String8 msg8;
+    if (msg) {
+        msg8 += msg;
+        msg8 += ": ";
+    }
+    auto errStr = StrCryptoError(err);
+    msg8 += errStr.c_str();
+
+    for (auto log : logs) {
+        time_t seconds = log.timeMs / 1000;
+        int ms = log.timeMs % 1000;
+        char buf[64] = {0};
+        std::string timeStr = "00-00 00:00:00";
+        if (strftime(buf, sizeof buf, "%m-%d %H:%M:%S", std::localtime(&seconds))) {
+            timeStr = buf;
+        }
+
+        char p = logPriorityToChar(log.priority);
+        msg8 += String8::format("\n%s.%03d %c %s", timeStr.c_str(), ms, p, log.message.c_str());
+    }
+
+    return msg8.c_str();
+}
+
+void LogBuffer::addLog(const ::V1_4::LogMessage &log) {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mBuffer.push_back(log);
+    while (mBuffer.size() > MAX_CAPACITY) {
+        mBuffer.pop_front();
+    }
+}
+
+Vector<::V1_4::LogMessage> LogBuffer::getLogs() {
+    std::unique_lock<std::mutex> lock(mMutex);
+    Vector<::V1_4::LogMessage> logs;
+    for (auto log : mBuffer) {
+        logs.push_back(log);
+    }
+    return logs;
+}
+
+LogBuffer gLogBuf;
 }  // namespace DrmUtils
 }  // namespace android
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index c362aa6..988cda9 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -27,7 +27,16 @@
 #include <utils/String8.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
+#include <algorithm>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
 #include <ctime>
+#include <deque>
+#include <endian.h>
+#include <iterator>
+#include <mutex>
+#include <string>
 #include <vector>
 
 
@@ -42,6 +51,61 @@
 
 namespace DrmUtils {
 
+// Log APIs
+class LogBuffer {
+  public:
+    static const int MAX_CAPACITY = 100;
+    void addLog(const ::V1_4::LogMessage &log);
+    Vector<::V1_4::LogMessage> getLogs();
+
+  private:
+    std::deque<::V1_4::LogMessage> mBuffer;
+    std::mutex mMutex;
+};
+
+extern LogBuffer gLogBuf;
+
+static inline int formatBuffer(char *buf, size_t size, const char *msg) {
+    return snprintf(buf, size, "%s", msg);
+}
+
+template <typename First, typename... Args>
+static inline int formatBuffer(char *buf, size_t size, const char *fmt, First first, Args... args) {
+    return snprintf(buf, size, fmt, first, args...);
+}
+
+template <typename... Args>
+void LogToBuffer(android_LogPriority level, const char *fmt, Args... args) {
+    const int LOG_BUF_SIZE = 256;
+    char buf[LOG_BUF_SIZE];
+    int len = formatBuffer(buf, LOG_BUF_SIZE, fmt, args...);
+    if (len <= 0) {
+        return;
+    }
+    __android_log_write(level, LOG_TAG, buf);
+    if (level >= ANDROID_LOG_INFO) {
+        int64_t epochTimeMs =
+                std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
+        gLogBuf.addLog({epochTimeMs, static_cast<::V1_4::LogPriority>(level), buf});
+    }
+}
+
+template <typename... Args>
+void LogToBuffer(android_LogPriority level, const uint8_t uuid[16], const char *fmt, Args... args) {
+    const uint64_t* uuid2 = reinterpret_cast<const uint64_t*>(uuid);
+    std::string uuidFmt("uuid=[%lx %lx] ");
+    uuidFmt += fmt;
+    LogToBuffer(level, uuidFmt.c_str(), htobe64(uuid2[0]), htobe64(uuid2[1]), args...);
+}
+
+#ifndef LOG2BE
+#define LOG2BE(...) LogToBuffer(ANDROID_LOG_ERROR, __VA_ARGS__)
+#define LOG2BW(...) LogToBuffer(ANDROID_LOG_WARN, __VA_ARGS__)
+#define LOG2BI(...) LogToBuffer(ANDROID_LOG_INFO, __VA_ARGS__)
+#define LOG2BD(...) LogToBuffer(ANDROID_LOG_DEBUG, __VA_ARGS__)
+#define LOG2BV(...) LogToBuffer(ANDROID_LOG_VERBOSE, __VA_ARGS__)
+#endif
+
 bool UseDrmService();
 
 sp<IDrm> MakeDrm(status_t *pstatus = nullptr);
@@ -119,11 +183,14 @@
 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;
+    if (obj == NULL) {
+        LOG2BW("%s obj is null", U::descriptor);
+    } else if (plugin == NULL) {
+        LOG2BW("Cannot cast %s obj to %s plugin", U::descriptor, T::descriptor);
     }
 
     ::V1_4::Status err{};
+    std::vector<::V1_4::LogMessage> pluginLogs;
     ::V1_4::IDrmPlugin::getLogMessages_cb cb = [&](
             ::V1_4::Status status,
             hidl_vec<::V1_4::LogMessage> hLogs) {
@@ -131,62 +198,39 @@
             err = status;
             return;
         }
-        logs.appendArray(hLogs.data(), hLogs.size());
+        pluginLogs.assign(hLogs.data(), hLogs.data() + hLogs.size());
     };
 
-    Return<void> hResult = plugin->getLogMessages(cb);
-    if (!hResult.isOk()) {
-        return DEAD_OBJECT;
+    Return<void> hResult;
+    if (plugin != NULL) {
+        hResult = plugin->getLogMessages(cb);
     }
-    return toStatusT(err);
+    if (!hResult.isOk()) {
+        LOG2BW("%s::getLogMessages remote call failed %s",
+               T::descriptor, hResult.description().c_str());
+    }
+
+    auto allLogs(gLogBuf.getLogs());
+    LOG2BI("framework logs size %zu; plugin logs size %zu",
+           allLogs.size(), pluginLogs.size());
+    std::copy(pluginLogs.begin(), pluginLogs.end(), std::back_inserter(allLogs));
+    std::sort(allLogs.begin(), allLogs.end(),
+              [](const ::V1_4::LogMessage &a, const ::V1_4::LogMessage &b) {
+                  return a.timeMs < b.timeMs;
+              });
+
+    logs.appendVector(allLogs);
+    return OK;
 }
 
-namespace {
-static inline char logPriorityToChar(::V1_4::LogPriority priority) {
-    char p = 'U';
-    switch (priority) {
-        case ::V1_4::LogPriority::VERBOSE:  p = 'V'; break;
-        case ::V1_4::LogPriority::DEBUG:    p = 'D'; break;
-        case ::V1_4::LogPriority::INFO:     p = 'I'; break;
-        case ::V1_4::LogPriority::WARN:     p = 'W'; break;
-        case ::V1_4::LogPriority::ERROR:    p = 'E'; break;
-        case ::V1_4::LogPriority::FATAL:    p = 'F'; break;
-        default: p = 'U'; break;
-    }
-    return p;
-}
-}
+std::string GetExceptionMessage(status_t err, const char *msg,
+                                const Vector<::V1_4::LogMessage> &logs);
 
 template<typename T>
 std::string GetExceptionMessage(status_t err, const char *msg, const sp<T> &iface) {
-    String8 msg8;
-    if (msg) {
-        msg8 += msg;
-        msg8 += ": ";
-    }
-    auto errStr = StrCryptoError(err);
-    msg8 += errStr.c_str();
-
     Vector<::V1_4::LogMessage> logs;
-    if (iface->getLogMessages(logs) != NO_ERROR) {
-        return msg8.c_str();
-    }
-
-    for (auto log: logs) {
-        time_t seconds = log.timeMs / 1000;
-        int ms = log.timeMs % 1000;
-        char buf[64] = {0};
-        std::string timeStr = "00-00 00:00:00";
-        if (strftime(buf, sizeof buf, "%m-%d %H:%M:%S", std::localtime(&seconds))) {
-            timeStr = buf;
-        }
-
-        char p = logPriorityToChar(log.priority);
-        msg8 += String8::format("\n%s.%03d %c %s",
-                timeStr.c_str(), ms, p, log.message.c_str());
-    }
-
-    return msg8.c_str();
+    iface->getLogMessages(logs);
+    return GetExceptionMessage(err, msg, logs);
 }
 
 } // namespace DrmUtils
diff --git a/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp b/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
index c4a72ef..2b235f2 100644
--- a/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
+++ b/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
@@ -158,6 +158,11 @@
 bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
                                   uint32_t generation,
                                   uint64_t bqId) {
+    uint64_t consumerUsage = 0;
+    if (igbp->getConsumerUsage(&consumerUsage) != OK) {
+        ALOGW("failed to get consumer usage");
+    }
+
     size_t tryNum = 0;
     size_t success = 0;
     sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
@@ -183,7 +188,24 @@
             }
             ++tryNum;
             int bqSlot;
+
+            // Update buffer's generation and usage.
+            if ((mBuffers[i]->getUsage() & consumerUsage) != consumerUsage) {
+                mBuffers[i] = new GraphicBuffer(
+                    mBuffers[i]->handle, GraphicBuffer::CLONE_HANDLE,
+                    mBuffers[i]->width, mBuffers[i]->height,
+                    mBuffers[i]->format, mBuffers[i]->layerCount,
+                    mBuffers[i]->getUsage() | consumerUsage,
+                    mBuffers[i]->stride);
+                if (mBuffers[i]->initCheck() != OK) {
+                    ALOGW("%s() failed to update usage, original usage=%" PRIx64
+                          ", consumer usage=%" PRIx64,
+                          __func__, mBuffers[i]->getUsage(), consumerUsage);
+                    continue;
+                }
+            }
             mBuffers[i]->setGenerationNumber(generation);
+
             status_t result = igbp->attachBuffer(&bqSlot, mBuffers[i]);
             if (result != OK) {
                 continue;
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index dd1f485..ab73245 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -209,15 +209,23 @@
 
             pDef->nBufferCountActual = 16;
 
-            std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
-            C2PortActualDelayTuning::input inputDelay(0);
-            C2ActualPipelineDelayTuning pipelineDelay(0);
-            c2_status_t c2err = comp->query(
-                    {&inputDelay, &pipelineDelay}, {}, C2_DONT_BLOCK, nullptr);
-            if (c2err == C2_OK || c2err == C2_BAD_INDEX) {
-                pDef->nBufferCountActual = 4;
-                pDef->nBufferCountActual += (inputDelay ? inputDelay.value : 0u);
-                pDef->nBufferCountActual += (pipelineDelay ? pipelineDelay.value : 0u);
+            // WORKAROUND: having more slots improve performance while consuming
+            // more memory. This is a temporary workaround to reduce memory for
+            // larger-than-4K scenario.
+            if (mWidth * mHeight > 4096 * 2340) {
+                std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
+                C2PortActualDelayTuning::input inputDelay(0);
+                C2ActualPipelineDelayTuning pipelineDelay(0);
+                c2_status_t c2err = C2_NOT_FOUND;
+                if (comp) {
+                    c2err = comp->query(
+                            {&inputDelay, &pipelineDelay}, {}, C2_DONT_BLOCK, nullptr);
+                }
+                if (c2err == C2_OK || c2err == C2_BAD_INDEX) {
+                    pDef->nBufferCountActual = 4;
+                    pDef->nBufferCountActual += (inputDelay ? inputDelay.value : 0u);
+                    pDef->nBufferCountActual += (pipelineDelay ? pipelineDelay.value : 0u);
+                }
             }
 
             pDef->eDomain = OMX_PortDomainVideo;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 452ffce..66a2b6a 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -248,19 +248,14 @@
         }
 
         size_t numSlots = 16;
-        // WORKAROUND: having more slots improve performance while consuming
-        // more memory. This is a temporary workaround to reduce memory for
-        // larger-than-4K scenario.
-        if (mWidth * mHeight > 4096 * 2340) {
-            constexpr OMX_U32 kPortIndexInput = 0;
+        constexpr OMX_U32 kPortIndexInput = 0;
 
-            OMX_PARAM_PORTDEFINITIONTYPE param;
-            param.nPortIndex = kPortIndexInput;
-            status_t err = mNode->getParameter(OMX_IndexParamPortDefinition,
-                                               &param, sizeof(param));
-            if (err == OK) {
-                numSlots = param.nBufferCountActual;
-            }
+        OMX_PARAM_PORTDEFINITIONTYPE param;
+        param.nPortIndex = kPortIndexInput;
+        status_t err = mNode->getParameter(OMX_IndexParamPortDefinition,
+                                           &param, sizeof(param));
+        if (err == OK) {
+            numSlots = param.nBufferCountActual;
         }
 
         for (size_t i = 0; i < numSlots; ++i) {
@@ -833,12 +828,14 @@
                 return BAD_VALUE;
             }
         }
+        int32_t width = 0;
+        int32_t height = 0;
         if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)) {
-            if (!msg->findInt32(KEY_WIDTH, &i32)) {
+            if (!msg->findInt32(KEY_WIDTH, &width)) {
                 ALOGD("width is missing, which is required for image/video components.");
                 return BAD_VALUE;
             }
-            if (!msg->findInt32(KEY_HEIGHT, &i32)) {
+            if (!msg->findInt32(KEY_HEIGHT, &height)) {
                 ALOGD("height is missing, which is required for image/video components.");
                 return BAD_VALUE;
             }
@@ -1143,6 +1140,7 @@
             return BAD_VALUE;
         }
 
+        int32_t componentColorFormat = 0;
         if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
             // propagate HDR static info to output format for both encoders and decoders
             // if component supports this info, we will update from component, but only the raw port,
@@ -1160,8 +1158,8 @@
             }
             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);
+                if (msg->findInt32("android._color-format", &componentColorFormat)) {
+                    config->mInputFormat->setInt32("android._color-format", componentColorFormat);
                 }
             } else {
                 config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format);
@@ -1219,8 +1217,59 @@
             config->mInputFormat->setInt32("color-transfer-request", colorTransferRequest);
         }
 
-        ALOGD("setup formats input: %s and output: %s",
-                config->mInputFormat->debugString().c_str(),
+        if (componentColorFormat != 0 && componentColorFormat != COLOR_FormatSurface) {
+            // Need to get stride/vstride
+            uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
+            if (C2Mapper::mapPixelFormatFrameworkToCodec(componentColorFormat, &pixelFormat)) {
+                // TODO: retrieve these values without allocating a buffer.
+                //       Currently allocating a buffer is necessary to retrieve the layout.
+                int64_t blockUsage =
+                    usage.value | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE;
+                std::shared_ptr<C2GraphicBlock> block = FetchGraphicBlock(
+                        width, height, pixelFormat, blockUsage, {comp->getName()});
+                sp<GraphicBlockBuffer> buffer;
+                if (block) {
+                    buffer = GraphicBlockBuffer::Allocate(
+                            config->mInputFormat,
+                            block,
+                            [](size_t size) -> sp<ABuffer> { return new ABuffer(size); });
+                } else {
+                    ALOGD("Failed to allocate a graphic block "
+                            "(width=%d height=%d pixelFormat=%u usage=%llx)",
+                            width, height, pixelFormat, (long long)blockUsage);
+                    // This means that byte buffer mode is not supported in this configuration
+                    // anyway. Skip setting stride/vstride to input format.
+                }
+                if (buffer) {
+                    sp<ABuffer> imageData = buffer->getImageData();
+                    MediaImage2 *img = nullptr;
+                    if (imageData && imageData->data()
+                            && imageData->size() >= sizeof(MediaImage2)) {
+                        img = (MediaImage2*)imageData->data();
+                    }
+                    if (img && img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
+                        int32_t stride = img->mPlane[0].mRowInc;
+                        config->mInputFormat->setInt32(KEY_STRIDE, stride);
+                        if (img->mNumPlanes > 1 && stride > 0) {
+                            int64_t offsetDelta =
+                                (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
+                            if (offsetDelta % stride == 0) {
+                                int32_t vstride = int32_t(offsetDelta / stride);
+                                config->mInputFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
+                            } else {
+                                ALOGD("Cannot report accurate slice height: "
+                                        "offsetDelta = %lld stride = %d",
+                                        (long long)offsetDelta, stride);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        ALOGD("setup formats input: %s",
+                config->mInputFormat->debugString().c_str());
+        ALOGD("setup formats output: %s",
                 config->mOutputFormat->debugString().c_str());
         return OK;
     };
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 8e59df1..bee6b7f 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -546,7 +546,19 @@
             status_t err = GraphicBufferMapper::get().lockYCbCr(
                     const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
             if (err) {
-                ALOGE("failed transaction: lockYCbCr");
+                ALOGE("failed transaction: lockYCbCr (err=%d)", err);
+                return C2_CORRUPTED;
+            }
+            if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
+                    || ycbcrLayout.ystride == 0
+                    || ycbcrLayout.cstride == 0
+                    || ycbcrLayout.chroma_step == 0) {
+                ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
+                        "ystride=%zu cstride=%zu chroma_step=%zu)",
+                        ycbcrLayout.y ? "(non-null)" : "(null)",
+                        ycbcrLayout.cb ? "(non-null)" : "(null)",
+                        ycbcrLayout.cr ? "(non-null)" : "(null)",
+                        ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
                 return C2_CORRUPTED;
             }
 
@@ -671,7 +683,10 @@
 
             status_t err = GraphicBufferMapper::get().lockYCbCr(
                     const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
-            if (err == OK) {
+            if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
+                    && ycbcrLayout.ystride > 0
+                    && ycbcrLayout.cstride > 0
+                    && ycbcrLayout.chroma_step > 0) {
                 addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
                 addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
                 addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index e1a8138..066f1e1 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -20,9 +20,14 @@
 #include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 
 #include <C2Buffer.h>
+#include <C2BlockInternal.h>
 
 #include <functional>
 
+namespace android {
+class GraphicBuffer;
+}  // namespace android
+
 class C2BufferQueueBlockPool : public C2BlockPool {
 public:
     C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
@@ -77,4 +82,66 @@
     friend struct C2BufferQueueBlockPoolData;
 };
 
+
+struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
+public:
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer;
+
+    // Create a remote BlockPoolData.
+    C2BufferQueueBlockPoolData(
+            uint32_t generation, uint64_t bqId, int32_t bqSlot,
+            const std::shared_ptr<int> &owner,
+            const android::sp<HGraphicBufferProducer>& producer);
+
+    // Create a local BlockPoolData.
+    C2BufferQueueBlockPoolData(
+            uint32_t generation, uint64_t bqId, int32_t bqSlot,
+            const android::sp<HGraphicBufferProducer>& producer);
+
+    virtual ~C2BufferQueueBlockPoolData() override;
+
+    virtual type_t getType() const override;
+
+    int migrate(const android::sp<HGraphicBufferProducer>& producer,
+                uint32_t toGeneration, uint64_t toUsage, uint64_t toBqId,
+                android::sp<android::GraphicBuffer>& graphicBuffer, uint32_t oldGeneration);
+
+private:
+    friend struct _C2BlockFactory;
+
+    // Methods delegated from _C2BlockFactory.
+    void getBufferQueueData(uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) const;
+    bool holdBlockFromBufferQueue(const std::shared_ptr<int>& owner,
+                                  const android::sp<HGraphicBufferProducer>& igbp);
+    bool beginTransferBlockToClient();
+    bool endTransferBlockToClient(bool transfer);
+    bool beginAttachBlockToBufferQueue();
+    bool endAttachBlockToBufferQueue(const std::shared_ptr<int>& owner,
+                                     const android::sp<HGraphicBufferProducer>& igbp,
+                                     uint32_t generation, uint64_t bqId, int32_t bqSlot);
+    bool displayBlockToBufferQueue();
+
+    const bool mLocal;
+    bool mHeld;
+
+    // Data of the corresponding buffer.
+    uint32_t mGeneration;
+    uint64_t mBqId;
+    int32_t mBqSlot;
+
+    // Data of the current IGBP, updated at migrate(). If the values are
+    // mismatched, then the corresponding buffer will not be cancelled back to
+    // IGBP at the destructor.
+    uint32_t mCurrentGeneration;
+    uint64_t mCurrentBqId;
+
+    bool mTransfer; // local transfer to remote
+    bool mAttach; // attach on remote
+    bool mDisplay; // display on remote;
+    std::weak_ptr<int> mOwner;
+    android::sp<HGraphicBufferProducer> mIgbp;
+    mutable std::mutex mLock;
+};
+
 #endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index fff12c4..e14b4b1 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -54,59 +54,13 @@
 using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::V2_0
         ::IGraphicBufferProducer;
 
-struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
-
-    bool held;
-    bool local;
-    uint32_t generation;
-    uint64_t bqId;
-    int32_t bqSlot;
-    bool transfer; // local transfer to remote
-    bool attach; // attach on remote
-    bool display; // display on remote;
-    std::weak_ptr<int> owner;
-    sp<HGraphicBufferProducer> igbp;
-    std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool;
-    mutable std::mutex lock;
-
-    virtual type_t getType() const override {
-        return TYPE_BUFFERQUEUE;
-    }
-
-    // Create a remote BlockPoolData.
-    C2BufferQueueBlockPoolData(
-            uint32_t generation, uint64_t bqId, int32_t bqSlot,
-            const std::shared_ptr<int> &owner,
-            const sp<HGraphicBufferProducer>& producer);
-
-    // Create a local BlockPoolData.
-    C2BufferQueueBlockPoolData(
-            uint32_t generation, uint64_t bqId, int32_t bqSlot,
-            const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool);
-
-    virtual ~C2BufferQueueBlockPoolData() override;
-
-    int migrate(const sp<HGraphicBufferProducer>& producer,
-                uint32_t toGeneration, uint64_t toBqId,
-                sp<GraphicBuffer> *buffers, uint32_t oldGeneration);
-};
-
 bool _C2BlockFactory::GetBufferQueueData(
         const std::shared_ptr<const _C2BlockPoolData>& data,
         uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) {
     if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
-        if (generation) {
-            const std::shared_ptr<const C2BufferQueueBlockPoolData> poolData =
-                    std::static_pointer_cast<const C2BufferQueueBlockPoolData>(data);
-            std::scoped_lock<std::mutex> lock(poolData->lock);
-            *generation = poolData->generation;
-            if (bqId) {
-                *bqId = poolData->bqId;
-            }
-            if (bqSlot) {
-                *bqSlot = poolData->bqSlot;
-            }
-        }
+        const std::shared_ptr<const C2BufferQueueBlockPoolData> poolData =
+                std::static_pointer_cast<const C2BufferQueueBlockPoolData>(data);
+        poolData->getBufferQueueData(generation, bqId, bqSlot);
         return true;
     }
     return false;
@@ -118,26 +72,14 @@
         const sp<HGraphicBufferProducer>& igbp) {
     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
-    std::scoped_lock<std::mutex> lock(poolData->lock);
-    if (!poolData->local) {
-        poolData->owner = owner;
-        poolData->igbp = igbp;
-    }
-    if (poolData->held) {
-        poolData->held = true;
-        return false;
-    }
-    poolData->held = true;
-    return true;
+    return poolData->holdBlockFromBufferQueue(owner, igbp);
 }
 
 bool _C2BlockFactory::BeginTransferBlockToClient(
         const std::shared_ptr<_C2BlockPoolData>& data) {
     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
-    std::scoped_lock<std::mutex> lock(poolData->lock);
-    poolData->transfer = true;
-    return true;
+    return poolData->beginTransferBlockToClient();
 }
 
 bool _C2BlockFactory::EndTransferBlockToClient(
@@ -145,28 +87,14 @@
         bool transfer) {
     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
-    std::scoped_lock<std::mutex> lock(poolData->lock);
-    poolData->transfer = false;
-    if (transfer) {
-        poolData->held = false;
-    }
-    return true;
+    return poolData->endTransferBlockToClient(transfer);
 }
 
 bool _C2BlockFactory::BeginAttachBlockToBufferQueue(
         const std::shared_ptr<_C2BlockPoolData>& data) {
     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
-    std::scoped_lock<std::mutex> lock(poolData->lock);
-    if (poolData->local || poolData->display ||
-        poolData->attach || !poolData->held) {
-        return false;
-    }
-    if (poolData->bqId == 0) {
-        return false;
-    }
-    poolData->attach = true;
-    return true;
+    return poolData->beginAttachBlockToBufferQueue();
 }
 
 // if display was tried during attach, buffer should be retired ASAP.
@@ -179,42 +107,14 @@
         int32_t bqSlot) {
     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
-    std::scoped_lock<std::mutex> lock(poolData->lock);
-    if (poolData->local || !poolData->attach ) {
-        return false;
-    }
-    if (poolData->display) {
-        poolData->attach = false;
-        poolData->held = false;
-        return false;
-    }
-    poolData->attach = false;
-    poolData->held = true;
-    poolData->owner = owner;
-    poolData->igbp = igbp;
-    poolData->generation = generation;
-    poolData->bqId = bqId;
-    poolData->bqSlot = bqSlot;
-    return true;
+    return poolData->endAttachBlockToBufferQueue(owner, igbp, generation, bqId, bqSlot);
 }
 
 bool _C2BlockFactory::DisplayBlockToBufferQueue(
         const std::shared_ptr<_C2BlockPoolData>& data) {
     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
-    std::scoped_lock<std::mutex> lock(poolData->lock);
-    if (poolData->local || poolData->display || !poolData->held) {
-        return false;
-    }
-    if (poolData->bqId == 0) {
-        return false;
-    }
-    poolData->display = true;
-    if (poolData->attach) {
-        return false;
-    }
-    poolData->held = false;
-    return true;
+    return poolData->displayBlockToBufferQueue();
 }
 
 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
@@ -267,8 +167,8 @@
     return stamp;
 }
 
-bool getGenerationNumber(const sp<HGraphicBufferProducer> &producer,
-                         uint32_t *generation) {
+bool getGenerationNumberAndUsage(const sp<HGraphicBufferProducer> &producer,
+                                 uint32_t *generation, uint64_t *usage) {
     status_t status{};
     int slot{};
     bool bufferNeedsReallocation{};
@@ -302,7 +202,7 @@
     // instead of a new allocation.
     transResult = producer->requestBuffer(
             slot,
-            [&status, &slotBuffer, &generation](
+            [&status, &slotBuffer, &generation, &usage](
                     HStatus hStatus,
                     HBuffer const& hBuffer,
                     uint32_t generationNumber){
@@ -310,6 +210,7 @@
                         h2b(hBuffer, &slotBuffer) &&
                         slotBuffer) {
                     *generation = generationNumber;
+                    *usage = slotBuffer->getUsage();
                     slotBuffer->setGenerationNumber(generationNumber);
                 } else {
                     status = android::BAD_VALUE;
@@ -469,7 +370,7 @@
                         std::make_shared<C2BufferQueueBlockPoolData>(
                                 slotBuffer->getGenerationNumber(),
                                 mProducerId, slot,
-                                shared_from_this());
+                                mProducer);
                 mPoolDatas[slot] = poolData;
                 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
                 return C2_OK;
@@ -537,7 +438,7 @@
             }
             std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
                     std::make_shared<C2BufferQueueBlockPoolData>(
-                            0, (uint64_t)0, ~0, shared_from_this());
+                            0, (uint64_t)0, ~0, nullptr);
             *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
             ALOGV("allocated a buffer successfully");
 
@@ -560,6 +461,7 @@
     void configureProducer(const sp<HGraphicBufferProducer> &producer) {
         uint64_t producerId = 0;
         uint32_t generation = 0;
+        uint64_t usage = 0;
         bool haveGeneration = false;
         if (producer) {
             Return<uint64_t> transResult = producer->getUniqueId();
@@ -569,7 +471,7 @@
             }
             producerId = static_cast<uint64_t>(transResult);
             // TODO: provide gneration number from parameter.
-            haveGeneration = getGenerationNumber(producer, &generation);
+            haveGeneration = getGenerationNumberAndUsage(producer, &generation, &usage);
             if (!haveGeneration) {
                 ALOGW("get generationNumber failed %llu",
                       (unsigned long long)producerId);
@@ -609,8 +511,8 @@
                             mPoolDatas[i].lock();
                     if (data) {
                         int slot = data->migrate(
-                                mProducer, generation,
-                                producerId, mBuffers, oldGeneration);
+                                mProducer, generation, usage,
+                                producerId, mBuffers[i], oldGeneration);
                         if (slot >= 0) {
                             buffers[slot] = mBuffers[i];
                             poolDatas[slot] = data;
@@ -634,17 +536,6 @@
 private:
     friend struct C2BufferQueueBlockPoolData;
 
-    void cancel(uint32_t generation, uint64_t igbp_id, int32_t igbp_slot) {
-        bool cancelled = false;
-        {
-        std::scoped_lock<std::mutex> lock(mMutex);
-        if (generation == mGeneration && igbp_id == mProducerId && mProducer) {
-            (void)mProducer->cancelBuffer(igbp_slot, hidl_handle{}).isOk();
-            cancelled = true;
-        }
-        }
-    }
-
     c2_status_t mInit;
     uint64_t mProducerId;
     uint32_t mGeneration;
@@ -668,65 +559,90 @@
         uint32_t generation, uint64_t bqId, int32_t bqSlot,
         const std::shared_ptr<int>& owner,
         const sp<HGraphicBufferProducer>& producer) :
-        held(producer && bqId != 0), local(false),
-        generation(generation), bqId(bqId), bqSlot(bqSlot),
-        transfer(false), attach(false), display(false),
-        owner(owner), igbp(producer),
-        localPool() {
+        mLocal(false), mHeld(producer && bqId != 0),
+        mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
+        mCurrentGeneration(generation), mCurrentBqId(bqId),
+        mTransfer(false), mAttach(false), mDisplay(false),
+        mOwner(owner), mIgbp(producer) {
 }
 
 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
         uint32_t generation, uint64_t bqId, int32_t bqSlot,
-        const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) :
-        held(true), local(true),
-        generation(generation), bqId(bqId), bqSlot(bqSlot),
-        transfer(false), attach(false), display(false),
-        igbp(pool ? pool->mProducer : nullptr),
-        localPool(pool) {
+        const android::sp<HGraphicBufferProducer>& producer) :
+        mLocal(true), mHeld(true),
+        mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
+        mCurrentGeneration(generation), mCurrentBqId(bqId),
+        mTransfer(false), mAttach(false), mDisplay(false), mIgbp(producer) {
 }
 
 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
-    if (!held || bqId == 0) {
+    if (!mHeld || mBqId == 0 || !mIgbp) {
         return;
     }
-    if (local) {
-        if (localPool) {
-            localPool->cancel(generation, bqId, bqSlot);
+
+    if (mLocal) {
+        if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId) {
+            mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
         }
-    } else if (igbp && !owner.expired()) {
-        igbp->cancelBuffer(bqSlot, hidl_handle{}).isOk();
+    } else if (!mOwner.expired()) {
+        mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
     }
 }
+
+C2BufferQueueBlockPoolData::type_t C2BufferQueueBlockPoolData::getType() const {
+    return TYPE_BUFFERQUEUE;
+}
+
 int C2BufferQueueBlockPoolData::migrate(
         const sp<HGraphicBufferProducer>& producer,
-        uint32_t toGeneration, uint64_t toBqId,
-        sp<GraphicBuffer> *buffers, uint32_t oldGeneration) {
-    std::scoped_lock<std::mutex> l(lock);
-    if (!held || bqId == 0) {
+        uint32_t toGeneration, uint64_t toUsage, uint64_t toBqId,
+        sp<GraphicBuffer>& graphicBuffer, uint32_t oldGeneration) {
+    std::scoped_lock<std::mutex> l(mLock);
+
+    mCurrentBqId = toBqId;
+    mCurrentGeneration = toGeneration;
+
+    if (!mHeld || mBqId == 0) {
         ALOGV("buffer is not owned");
         return -1;
     }
-    if (!local || !localPool) {
+    if (!mLocal) {
         ALOGV("pool is not local");
         return -1;
     }
-    if (bqSlot < 0 || bqSlot >= NUM_BUFFER_SLOTS || !buffers[bqSlot]) {
+    if (mBqSlot < 0 || mBqSlot >= NUM_BUFFER_SLOTS) {
         ALOGV("slot is not in effect");
         return -1;
     }
-    if (toGeneration == generation && bqId == toBqId) {
+    if (!graphicBuffer) {
+        ALOGV("buffer is null");
+        return -1;
+    }
+    if (toGeneration == mGeneration && mBqId == toBqId) {
         ALOGV("cannot migrate to same bufferqueue");
         return -1;
     }
-    if (oldGeneration != generation) {
+    if (oldGeneration != mGeneration) {
         ALOGV("cannot migrate stale buffer");
     }
-    if (transfer) {
+    if (mTransfer) {
         // either transferred or detached.
         ALOGV("buffer is in transfer");
         return -1;
     }
-    sp<GraphicBuffer> const& graphicBuffer = buffers[bqSlot];
+
+    if (toUsage != graphicBuffer->getUsage()) {
+        sp<GraphicBuffer> newBuffer = new GraphicBuffer(
+            graphicBuffer->handle, GraphicBuffer::CLONE_HANDLE,
+            graphicBuffer->width, graphicBuffer->height, graphicBuffer->format,
+            graphicBuffer->layerCount, toUsage, graphicBuffer->stride);
+        if (newBuffer->initCheck() == android::NO_ERROR) {
+            graphicBuffer = std::move(newBuffer);
+        } else {
+            ALOGW("%s() failed to update usage, original usage=%" PRIx64 ", toUsage=%" PRIx64,
+                  __func__, graphicBuffer->getUsage(), toUsage);
+        }
+    }
     graphicBuffer->setGenerationNumber(toGeneration);
 
     HBuffer hBuffer{};
@@ -755,13 +671,112 @@
         return -1;
     }
     ALOGV("local migration from gen %u : %u slot %d : %d",
-          generation, toGeneration, bqSlot, slot);
-    generation = toGeneration;
-    bqId = toBqId;
-    bqSlot = slot;
+          mGeneration, toGeneration, mBqSlot, slot);
+    mIgbp = producer;
+    mGeneration = toGeneration;
+    mBqId = toBqId;
+    mBqSlot = slot;
     return slot;
 }
 
+void C2BufferQueueBlockPoolData::getBufferQueueData(
+        uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) const {
+    if (generation) {
+        std::scoped_lock<std::mutex> lock(mLock);
+        *generation = mGeneration;
+        if (bqId) {
+            *bqId = mBqId;
+        }
+        if (bqSlot) {
+            *bqSlot = mBqSlot;
+        }
+    }
+}
+
+bool C2BufferQueueBlockPoolData::holdBlockFromBufferQueue(
+        const std::shared_ptr<int>& owner,
+        const sp<HGraphicBufferProducer>& igbp) {
+    std::scoped_lock<std::mutex> lock(mLock);
+    if (!mLocal) {
+        mOwner = owner;
+        mIgbp = igbp;
+    }
+    if (mHeld) {
+        return false;
+    }
+    mHeld = true;
+    return true;
+}
+
+bool C2BufferQueueBlockPoolData::beginTransferBlockToClient() {
+    std::scoped_lock<std::mutex> lock(mLock);
+    mTransfer = true;
+    return true;
+}
+
+bool C2BufferQueueBlockPoolData::endTransferBlockToClient(bool transfer) {
+    std::scoped_lock<std::mutex> lock(mLock);
+    mTransfer = false;
+    if (transfer) {
+        mHeld = false;
+    }
+    return true;
+}
+
+bool C2BufferQueueBlockPoolData::beginAttachBlockToBufferQueue() {
+    std::scoped_lock<std::mutex> lock(mLock);
+    if (mLocal || mDisplay ||
+        mAttach || !mHeld) {
+        return false;
+    }
+    if (mBqId == 0) {
+        return false;
+    }
+    mAttach = true;
+    return true;
+}
+
+bool C2BufferQueueBlockPoolData::endAttachBlockToBufferQueue(
+        const std::shared_ptr<int>& owner,
+        const sp<HGraphicBufferProducer>& igbp,
+        uint32_t generation,
+        uint64_t bqId,
+        int32_t bqSlot) {
+    std::scoped_lock<std::mutex> lock(mLock);
+    if (mLocal || !mAttach) {
+        return false;
+    }
+    if (mDisplay) {
+        mAttach = false;
+        mHeld = false;
+        return false;
+    }
+    mAttach = false;
+    mHeld = true;
+    mOwner = owner;
+    mIgbp = igbp;
+    mGeneration = generation;
+    mBqId = bqId;
+    mBqSlot = bqSlot;
+    return true;
+}
+
+bool C2BufferQueueBlockPoolData::displayBlockToBufferQueue() {
+    std::scoped_lock<std::mutex> lock(mLock);
+    if (mLocal || mDisplay || !mHeld) {
+        return false;
+    }
+    if (mBqId == 0) {
+        return false;
+    }
+    mDisplay = true;
+    if (mAttach) {
+        return false;
+    }
+    mHeld = false;
+    return true;
+}
+
 C2BufferQueueBlockPool::C2BufferQueueBlockPool(
         const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
         : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
index 9b93659..f2245b1 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
@@ -101,6 +101,16 @@
     context->param.audioChannelCount = 0;
     context->param.maxHapticIntensity = os::HapticScale::MUTE;
 
+    context->param.resonantFrequency = 150.0f;
+    context->param.bpfQ = 1.0f;
+    context->param.slowEnvNormalizationPower = -0.8f;
+    context->param.bsfZeroQ = 8.0f;
+    context->param.bsfPoleQ = 4.0f;
+    context->param.distortionCornerFrequency = 300.0f;
+    context->param.distortionInputGain = 0.3f;
+    context->param.distortionCubeThreshold = 0.1f;
+    context->param.distortionOutputGain = 1.5f;
+
     context->state = HAPTICGENERATOR_STATE_INITIALIZED;
     return 0;
 }
@@ -128,16 +138,17 @@
  */
 void HapticGenerator_buildProcessingChain(
         std::vector<std::function<void(float*, const float*, size_t)>>& processingChain,
-        struct HapticGeneratorProcessorsRecord& processorsRecord,
-        float sampleRate, size_t channelCount) {
-    float highPassCornerFrequency = 100.0f;
+        struct HapticGeneratorProcessorsRecord& processorsRecord, float sampleRate,
+        const struct HapticGeneratorParam* param) {
+    const size_t channelCount = param->hapticChannelCount;
+    float highPassCornerFrequency = 50.0f;
     auto hpf = createHPF2(highPassCornerFrequency, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, hpf);
-    float lowPassCornerFrequency = 3000.0f;
+    float lowPassCornerFrequency = 9000.0f;
     auto lpf = createLPF2(lowPassCornerFrequency, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, lpf);
 
-    auto ramp = std::make_shared<Ramp>(channelCount);
+    auto ramp = std::make_shared<Ramp>(channelCount);  // ramp = half-wave rectifier.
     // The process chain captures the shared pointer of the ramp in lambda. It will be the only
     // reference to the ramp.
     // The process record will keep a weak pointer to the ramp so that it is possible to access
@@ -154,19 +165,6 @@
     lpf = createLPF2(lowPassCornerFrequency, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, lpf);
 
-    lowPassCornerFrequency = 5.0f;
-    float normalizationPower = -0.3f;
-    // The process chain captures the shared pointer of the slow envelope in lambda. It will
-    // be the only reference to the slow envelope.
-    // The process record will keep a weak pointer to the slow envelope so that it is possible
-    // to access the slow envelope outside of the process chain.
-    auto slowEnv = std::make_shared<SlowEnvelope>(
-            lowPassCornerFrequency, sampleRate, normalizationPower, channelCount);
-    processorsRecord.slowEnvs.push_back(slowEnv);
-    processingChain.push_back([slowEnv](float *out, const float *in, size_t frameCount) {
-            slowEnv->process(out, in, frameCount);
-    });
-
     lowPassCornerFrequency = 400.0f;
     lpf = createLPF2(lowPassCornerFrequency, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, lpf);
@@ -174,23 +172,38 @@
     lpf = createLPF2(lowPassCornerFrequency, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, lpf);
 
-    auto apf = createAPF2(400.0f, 200.0f, sampleRate, channelCount);
-    addBiquadFilter(processingChain, processorsRecord, apf);
-    apf = createAPF2(100.0f, 50.0f, sampleRate, channelCount);
-    addBiquadFilter(processingChain, processorsRecord, apf);
-    float allPassCornerFrequency = 25.0f;
-    apf = createAPF(allPassCornerFrequency, sampleRate, channelCount);
-    addBiquadFilter(processingChain, processorsRecord, apf);
-
-    float resonantFrequency = 150.0f;
-    float bandpassQ = 1.0f;
-    auto bpf = createBPF(resonantFrequency, bandpassQ, sampleRate, channelCount);
+    auto bpf = createBPF(param->resonantFrequency, param->bpfQ, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, bpf);
 
-    float zeroQ = 8.0f;
-    float poleQ = 4.0f;
-    auto bsf = createBSF(resonantFrequency, zeroQ, poleQ, sampleRate, channelCount);
+    float normalizationPower = param->slowEnvNormalizationPower;
+    // The process chain captures the shared pointer of the slow envelope in lambda. It will
+    // be the only reference to the slow envelope.
+    // The process record will keep a weak pointer to the slow envelope so that it is possible
+    // to access the slow envelope outside of the process chain.
+    auto slowEnv = std::make_shared<SlowEnvelope>(  // SlowEnvelope = partial normalizer, or AGC.
+            5.0f /*envCornerFrequency*/, sampleRate, normalizationPower,
+            0.01f /*envOffset*/, channelCount);
+    processorsRecord.slowEnvs.push_back(slowEnv);
+    processingChain.push_back([slowEnv](float *out, const float *in, size_t frameCount) {
+            slowEnv->process(out, in, frameCount);
+    });
+
+
+    auto bsf = createBSF(
+            param->resonantFrequency, param->bsfZeroQ, param->bsfPoleQ, sampleRate, channelCount);
     addBiquadFilter(processingChain, processorsRecord, bsf);
+
+    // The process chain captures the shared pointer of the Distortion in lambda. It will
+    // be the only reference to the Distortion.
+    // The process record will keep a weak pointer to the Distortion so that it is possible
+    // to access the Distortion outside of the process chain.
+    auto distortion = std::make_shared<Distortion>(
+            param->distortionCornerFrequency, sampleRate, param->distortionInputGain,
+            param->distortionCubeThreshold, param->distortionOutputGain, channelCount);
+    processorsRecord.distortions.push_back(distortion);
+    processingChain.push_back([distortion](float *out, const float *in, size_t frameCount) {
+            distortion->process(out, in, frameCount);
+    });
 }
 
 int HapticGenerator_Configure(struct HapticGeneratorContext *context, effect_config_t *config) {
@@ -206,6 +219,7 @@
         context->processorsRecord.filters.clear();
         context->processorsRecord.ramps.clear();
         context->processorsRecord.slowEnvs.clear();
+        context->processorsRecord.distortions.clear();
         memcpy(&context->config, config, sizeof(effect_config_t));
         context->param.audioChannelCount = audio_channel_count_from_out_mask(
                 ((audio_channel_mask_t) config->inputCfg.channels) & ~AUDIO_CHANNEL_HAPTIC_ALL);
@@ -224,7 +238,7 @@
         HapticGenerator_buildProcessingChain(context->processingChain,
                                              context->processorsRecord,
                                              config->inputCfg.samplingRate,
-                                             context->param.hapticChannelCount);
+                                             &context->param);
     }
     return 0;
 }
@@ -236,6 +250,9 @@
     for (auto& slowEnv : context->processorsRecord.slowEnvs) {
         slowEnv->clear();
     }
+    for (auto& distortion : context->processorsRecord.distortions) {
+        distortion->clear();
+    }
     return 0;
 }
 
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
index 57b4338..d2d7afe 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
@@ -51,6 +51,16 @@
     // A map from track id to haptic intensity.
     std::map<int, os::HapticScale> id2Intensity;
     os::HapticScale maxHapticIntensity; // max intensity will be used to scale haptic data.
+
+    float resonantFrequency;
+    float bpfQ;
+    float slowEnvNormalizationPower;
+    float bsfZeroQ;
+    float bsfPoleQ;
+    float distortionCornerFrequency;
+    float distortionInputGain;
+    float distortionCubeThreshold;
+    float distortionOutputGain;
 };
 
 // A structure to keep all shared pointers for all processors in HapticGenerator.
@@ -58,6 +68,7 @@
     std::vector<std::shared_ptr<HapticBiquadFilter>> filters;
     std::vector<std::shared_ptr<Ramp>> ramps;
     std::vector<std::shared_ptr<SlowEnvelope>> slowEnvs;
+    std::vector<std::shared_ptr<Distortion>> distortions;
 };
 
 // A structure to keep all the context for HapticGenerator.
diff --git a/media/libeffects/hapticgenerator/Processors.cpp b/media/libeffects/hapticgenerator/Processors.cpp
index 3157b35..79a4e2c 100644
--- a/media/libeffects/hapticgenerator/Processors.cpp
+++ b/media/libeffects/hapticgenerator/Processors.cpp
@@ -83,30 +83,92 @@
         float cornerFrequency,
         float sampleRate,
         float normalizationPower,
+        float envOffset,
         size_t channelCount)
         : mLpf(createLPF(cornerFrequency, sampleRate, channelCount)),
           mNormalizationPower(normalizationPower),
-          mChannelCount(channelCount),
-          mEnv(0.25 * (sampleRate / (2 * M_PI * cornerFrequency))) {}
+          mEnvOffset(envOffset),
+          mChannelCount(channelCount) {}
 
 void SlowEnvelope::process(float* out, const float* in, size_t frameCount) {
     size_t sampleCount = frameCount * mChannelCount;
-    if (sampleCount > mLpfInBuffer.size()) {
-        mLpfInBuffer.resize(sampleCount, mEnv);
+    if (sampleCount > mLpfOutBuffer.size()) {
         mLpfOutBuffer.resize(sampleCount);
+        mLpfInBuffer.resize(sampleCount);
+    }
+    for (size_t i = 0; i < sampleCount; ++i) {
+        mLpfInBuffer[i] = fabs(in[i]);
     }
     mLpf->process(mLpfOutBuffer.data(), mLpfInBuffer.data(), frameCount);
     for (size_t i = 0; i < sampleCount; ++i) {
-        *out = *in * pow(mLpfOutBuffer[i], mNormalizationPower);
-        out++;
-        in++;
+        out[i] = in[i] * pow(mLpfOutBuffer[i] + mEnvOffset, mNormalizationPower);
     }
 }
 
+void SlowEnvelope::setNormalizationPower(float normalizationPower) {
+    mNormalizationPower = normalizationPower;
+}
+
 void SlowEnvelope::clear() {
     mLpf->clear();
 }
 
+// Implementation of distortion
+
+Distortion::Distortion(
+        float cornerFrequency,
+        float sampleRate,
+        float inputGain,
+        float cubeThreshold,
+        float outputGain,
+        size_t channelCount)
+        : mLpf(createLPF2(cornerFrequency, sampleRate, channelCount)),
+          mSampleRate(sampleRate),
+          mCornerFrequency(cornerFrequency),
+          mInputGain(inputGain),
+          mCubeThreshold(cubeThreshold),
+          mOutputGain(outputGain),
+          mChannelCount(channelCount) {}
+
+void Distortion::process(float *out, const float *in, size_t frameCount) {
+    size_t sampleCount = frameCount * mChannelCount;
+    if (sampleCount > mLpfInBuffer.size()) {
+        mLpfInBuffer.resize(sampleCount);
+    }
+    for (size_t i = 0; i < sampleCount; ++i) {
+        const float x = mInputGain * in[i];
+        mLpfInBuffer[i] = x * x * x / (mCubeThreshold + x * x);  // "Coring" nonlinearity.
+    }
+    mLpf->process(out, mLpfInBuffer.data(), frameCount);  // Reduce 3*F components.
+    for (size_t i = 0; i < sampleCount; ++i) {
+        const float x = out[i];
+        out[i] = mOutputGain * x / (1.0f + fabs(x));  // Soft limiter.
+    }
+}
+
+void Distortion::setCornerFrequency(float cornerFrequency) {
+    mCornerFrequency = cornerFrequency;
+    BiquadFilterCoefficients coefficient = lpfCoefs(cornerFrequency, mSampleRate);
+    mLpf->setCoefficients(coefficient);
+}
+
+void Distortion::setInputGain(float inputGain) {
+    mInputGain = inputGain;
+}
+
+void Distortion::setCubeThrehold(float cubeThreshold) {
+    mCubeThreshold = cubeThreshold;
+}
+
+void Distortion::setOutputGain(float outputGain) {
+    mOutputGain = outputGain;
+}
+
+void Distortion::clear() {
+    mLpf->clear();
+}
+
+
 // Implementation of helper functions
 
 BiquadFilterCoefficients cascadeFirstOrderFilters(const BiquadFilterCoefficients &coefs1,
@@ -134,6 +196,40 @@
     return coefficient;
 }
 
+BiquadFilterCoefficients bpfCoefs(const float ringingFrequency,
+                                  const float q,
+                                  const float sampleRate) {
+    BiquadFilterCoefficients coefficient;
+    const auto [real, img] = getComplexPoleZ(ringingFrequency, q, sampleRate);
+    // Note: this is not a standard cookbook BPF, but a low pass filter with zero at DC
+    coefficient[0] = 1.0f;
+    coefficient[1] = -1.0f;
+    coefficient[2] = 0.0f;
+    coefficient[3] = -2 * real;
+    coefficient[4] = real * real + img * img;
+    return coefficient;
+}
+
+BiquadFilterCoefficients bsfCoefs(const float ringingFrequency,
+                                  const float sampleRate,
+                                  const float zq,
+                                  const float pq) {
+    BiquadFilterCoefficients coefficient;
+    const auto [zeroReal, zeroImg] = getComplexPoleZ(ringingFrequency, zq, sampleRate);
+    float zeroCoeff1 = -2 * zeroReal;
+    float zeroCoeff2 = zeroReal* zeroReal + zeroImg * zeroImg;
+    const auto [poleReal, poleImg] = getComplexPoleZ(ringingFrequency, pq, sampleRate);
+    float poleCoeff1 = -2 * poleReal;
+    float poleCoeff2 = poleReal * poleReal + poleImg * poleImg;
+    const float norm = (1.0f + poleCoeff1 + poleCoeff2) / (1.0f + zeroCoeff1 + zeroCoeff2);
+    coefficient[0] = 1.0f * norm;
+    coefficient[1] = zeroCoeff1 * norm;
+    coefficient[2] = zeroCoeff2 * norm;
+    coefficient[3] = poleCoeff1;
+    coefficient[4] = poleCoeff2;
+    return coefficient;
+}
+
 std::shared_ptr<HapticBiquadFilter> createLPF(const float cornerFrequency,
                                         const float sampleRate,
                                         const size_t channelCount) {
@@ -166,47 +262,11 @@
             channelCount, cascadeFirstOrderFilters(coefficient, coefficient));
 }
 
-BiquadFilterCoefficients apfCoefs(const float cornerFrequency, const float sampleRate) {
-    BiquadFilterCoefficients coefficient;
-    float realPoleZ = getRealPoleZ(cornerFrequency, sampleRate);
-    float zeroZ = 1.0f / realPoleZ;
-    coefficient[0] = (1.0f - realPoleZ) / (1.0f - zeroZ);
-    coefficient[1] = -coefficient[0] * zeroZ;
-    coefficient[2] = 0.0f;
-    coefficient[3] = -realPoleZ;
-    coefficient[4] = 0.0f;
-    return coefficient;
-}
-
-std::shared_ptr<HapticBiquadFilter> createAPF(const float cornerFrequency,
-                                        const float sampleRate,
-                                        const size_t channelCount) {
-    BiquadFilterCoefficients coefficient = apfCoefs(cornerFrequency, sampleRate);
-    return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
-}
-
-std::shared_ptr<HapticBiquadFilter> createAPF2(const float cornerFrequency1,
-                                         const float cornerFrequency2,
-                                         const float sampleRate,
-                                         const size_t channelCount) {
-    BiquadFilterCoefficients coefs1 = apfCoefs(cornerFrequency1, sampleRate);
-    BiquadFilterCoefficients coefs2 = apfCoefs(cornerFrequency2, sampleRate);
-    return std::make_shared<HapticBiquadFilter>(
-            channelCount, cascadeFirstOrderFilters(coefs1, coefs2));
-}
-
 std::shared_ptr<HapticBiquadFilter> createBPF(const float ringingFrequency,
                                         const float q,
                                         const float sampleRate,
                                         const size_t channelCount) {
-    BiquadFilterCoefficients coefficient;
-    const auto [real, img] = getComplexPoleZ(ringingFrequency, q, sampleRate);
-    // Note: this is not a standard cookbook BPF, but a low pass filter with zero at DC
-    coefficient[0] = 1.0f;
-    coefficient[1] = -1.0f;
-    coefficient[2] = 0.0f;
-    coefficient[3] = -2 * real;
-    coefficient[4] = real * real + img * img;
+    BiquadFilterCoefficients coefficient = bpfCoefs(ringingFrequency, q, sampleRate);
     return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
 }
 
@@ -215,19 +275,7 @@
                                         const float pq,
                                         const float sampleRate,
                                         const size_t channelCount) {
-    BiquadFilterCoefficients coefficient;
-    const auto [zeroReal, zeroImg] = getComplexPoleZ(ringingFrequency, zq, sampleRate);
-    float zeroCoeff1 = -2 * zeroReal;
-    float zeroCoeff2 = zeroReal* zeroReal + zeroImg * zeroImg;
-    const auto [poleReal, poleImg] = getComplexPoleZ(ringingFrequency, pq, sampleRate);
-    float poleCoeff1 = -2 * poleReal;
-    float poleCoeff2 = poleReal * poleReal + poleImg * poleImg;
-    const float norm = (1.0f + poleCoeff1 + poleCoeff2) / (1.0f + zeroCoeff1 + zeroCoeff2);
-    coefficient[0] = 1.0f * norm;
-    coefficient[1] = zeroCoeff1 * norm;
-    coefficient[2] = zeroCoeff2 * norm;
-    coefficient[3] = poleCoeff1;
-    coefficient[4] = poleCoeff2;
+    BiquadFilterCoefficients coefficient = bsfCoefs(ringingFrequency, sampleRate, zq, pq);
     return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
 }
 
diff --git a/media/libeffects/hapticgenerator/Processors.h b/media/libeffects/hapticgenerator/Processors.h
index 5cf0557..452a985 100644
--- a/media/libeffects/hapticgenerator/Processors.h
+++ b/media/libeffects/hapticgenerator/Processors.h
@@ -44,19 +44,50 @@
 class SlowEnvelope {
 public:
     SlowEnvelope(float cornerFrequency, float sampleRate,
-                 float normalizationPower, size_t channelCount);
+                 float normalizationPower, float envOffset,
+                 size_t channelCount);
 
     void process(float *out, const float *in, size_t frameCount);
 
+    void setNormalizationPower(float normalizationPower);
+
     void clear();
 
 private:
     const std::shared_ptr<HapticBiquadFilter> mLpf;
     std::vector<float> mLpfInBuffer;
     std::vector<float> mLpfOutBuffer;
-    const float mNormalizationPower;
+    float mNormalizationPower;
+    const float mEnvOffset;
     const float mChannelCount;
-    const float mEnv;
+};
+
+
+// A class providing a process function that compressively distorts a waveforms
+class Distortion {
+public:
+    Distortion(float cornerFrequency, float sampleRate,
+               float inputGain, float cubeThreshold,
+               float outputGain, size_t channelCount);
+
+    void process(float *out, const float *in, size_t frameCount);
+
+    void setCornerFrequency(float cornerFrequency);
+    void setInputGain(float inputGain);
+    void setCubeThrehold(float cubeThreshold);
+    void setOutputGain(float outputGain);
+
+    void clear();
+
+private:
+    const std::shared_ptr<HapticBiquadFilter> mLpf;
+    std::vector<float> mLpfInBuffer;
+    float mSampleRate;
+    float mCornerFrequency;
+    float mInputGain;
+    float mCubeThreshold;
+    float mOutputGain;
+    const size_t mChannelCount;
 };
 
 // Helper functions
@@ -64,6 +95,17 @@
 BiquadFilterCoefficients cascadeFirstOrderFilters(const BiquadFilterCoefficients &coefs1,
                                                   const BiquadFilterCoefficients &coefs2);
 
+BiquadFilterCoefficients lpfCoefs(const float cornerFrequency, const float sampleRate);
+
+BiquadFilterCoefficients bpfCoefs(const float ringingFrequency,
+                                  const float q,
+                                  const float sampleRate);
+
+BiquadFilterCoefficients bsfCoefs(const float ringingFrequency,
+                                  const float sampleRate,
+                                  const float zq,
+                                  const float pq);
+
 std::shared_ptr<HapticBiquadFilter> createLPF(const float cornerFrequency,
                                         const float sampleRate,
                                         const size_t channelCount);
@@ -78,16 +120,6 @@
                                          const float sampleRate,
                                          const size_t channelCount);
 
-std::shared_ptr<HapticBiquadFilter> createAPF(const float cornerFrequency,
-                                        const float sampleRate,
-                                        const size_t channelCount);
-
-// Create two cascaded APF with two different corner frequency.
-std::shared_ptr<HapticBiquadFilter> createAPF2(const float cornerFrequency1,
-                                         const float cornerFrequency2,
-                                         const float sampleRate,
-                                         const size_t channelCount);
-
 std::shared_ptr<HapticBiquadFilter> createBPF(const float ringingFrequency,
                                         const float q,
                                         const float sampleRate,
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index e46a136..eb3ce34 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -18,7 +18,7 @@
     ],
 }
 
-cc_library_shared {
+cc_library {
     name: "libaudiopreprocessing",
     vendor: true,
     relative_install_path: "soundfx",
diff --git a/media/libeffects/preprocessing/benchmarks/Android.bp b/media/libeffects/preprocessing/benchmarks/Android.bp
index 246d14e..c1b2295 100644
--- a/media/libeffects/preprocessing/benchmarks/Android.bp
+++ b/media/libeffects/preprocessing/benchmarks/Android.bp
@@ -12,14 +12,16 @@
 cc_benchmark {
     name: "preprocessing_benchmark",
     vendor: true,
-    relative_install_path: "soundfx",
     srcs: ["preprocessing_benchmark.cpp"],
     shared_libs: [
-        "libaudiopreprocessing",
         "libaudioutils",
         "liblog",
         "libutils",
     ],
+    static_libs: [
+        "libaudiopreprocessing",
+        "webrtc_audio_processing",
+    ],
     cflags: [
         "-DWEBRTC_POSIX",
         "-fvisibility=default",
diff --git a/media/libeffects/preprocessing/tests/Android.bp b/media/libeffects/preprocessing/tests/Android.bp
index cfa6559..8848e79 100644
--- a/media/libeffects/preprocessing/tests/Android.bp
+++ b/media/libeffects/preprocessing/tests/Android.bp
@@ -12,19 +12,17 @@
 
 cc_test {
     name: "AudioPreProcessingTest",
-
     vendor: true,
-
-    relative_install_path: "soundfx",
-
     srcs: ["PreProcessingTest.cpp"],
-
     shared_libs: [
-        "libaudiopreprocessing",
         "libaudioutils",
         "liblog",
         "libutils",
     ],
+    static_libs: [
+        "libaudiopreprocessing",
+        "webrtc_audio_processing",
+    ],
     header_libs: [
         "libaudioeffects",
         "libhardware_headers",
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index aa678ba..4c78b01 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -92,8 +92,8 @@
         (*dataJson)["threadNum"] = item.first;
         root.append(*dataJson);
     }
-    Json::StyledWriter writer;
-    std::string rootStr = writer.write(root);
+    Json::StreamWriterBuilder factory;
+    std::string rootStr = Json::writeString(factory, root);
     write(fd, rootStr.c_str(), rootStr.size());
 }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index d96b48b..7fa870a 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -3228,16 +3228,21 @@
                 break;
             }
 
-            // If we're flushing, stopping, configuring or starting  but
+            // If we're flushing, configuring or starting  but
             // received a release request, post the reply for the pending call
             // first, and consider it done. The reply token will be replaced
             // after this, and we'll no longer be able to reply.
-            if (mState == FLUSHING || mState == STOPPING
-                    || mState == CONFIGURING || mState == STARTING) {
+            if (mState == FLUSHING || mState == CONFIGURING || mState == STARTING) {
                 // mReply is always set if in these states.
                 postPendingRepliesAndDeferredMessages(
                         std::string("kWhatRelease:") + stateString(mState));
             }
+            // If we're stopping but received a release request, post the reply
+            // for the pending call if necessary. Note that the reply may have been
+            // already posted due to an error.
+            if (mState == STOPPING && mReplyID) {
+                postPendingRepliesAndDeferredMessages("kWhatRelease:STOPPING");
+            }
 
             if (mFlags & kFlagSawMediaServerDie) {
                 // It's dead, Jim. Don't expect initiateShutdown to yield
diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
index d00a50f..6facbd8 100644
--- a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
+++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
@@ -286,16 +286,18 @@
     //    initiateShutdown(); shutdown is being handled at the component thread.
     // 2) Error occurred, but the shutdown operation is still being done.
     // 3) MediaCodec looper thread handles the error.
-    // 4) Component thread completes shutdown and posts onStopCompleted()
+    // 4) Client releases the codec upon the error; previous shutdown is still
+    //    going on.
+    // 5) Component thread completes shutdown and posts onStopCompleted();
+    //    Shutdown from release also completes.
 
     static const AString kCodecName{"test.codec"};
     static const AString kCodecOwner{"nobody"};
     static const AString kMediaType{"video/x-test"};
 
-    std::promise<void> errorOccurred;
     sp<MockCodec> mockCodec;
     std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase =
-        [&mockCodec, &errorOccurred](const AString &, const char *) {
+        [&mockCodec](const AString &, const char *) {
             mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) {
                 // No mock setup, as we don't expect any buffer operations
                 // in this scenario.
@@ -314,13 +316,14 @@
                     mockCodec->callback()->onStartCompleted();
                 });
             ON_CALL(*mockCodec, initiateShutdown(true))
-                .WillByDefault([mockCodec, &errorOccurred](bool) {
+                .WillByDefault([mockCodec](bool) {
                     mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
-                    // Mark that 1) and 2) are complete.
-                    errorOccurred.set_value();
                 });
             ON_CALL(*mockCodec, initiateShutdown(false))
                 .WillByDefault([mockCodec](bool) {
+                    // Previous stop finished now.
+                    mockCodec->callback()->onStopCompleted();
+                    // Release also finished.
                     mockCodec->callback()->onReleaseCompleted();
                 });
             return mockCodec;
@@ -332,19 +335,11 @@
     ASSERT_NE(nullptr, codec) << "Codec must not be null";
     ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null";
 
-    std::thread([mockCodec, &errorOccurred]{
-        // Simulate component thread that handles stop()
-        errorOccurred.get_future().wait();
-        // Error occurred but shutdown request still got processed.
-        mockCodec->callback()->onStopCompleted();
-    }).detach();
-
     codec->configure(new AMessage, nullptr, nullptr, 0);
     codec->start();
-    codec->stop();
-    // Sleep here to give time for the MediaCodec looper thread
-    // to process the messages.
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    // stop() will fail because of the error
+    EXPECT_NE(OK, codec->stop());
+    // upon receiving the error, client tries to release the codec.
     codec->release();
     looper->stop();
 }
diff --git a/services/audiopolicy/common/managerdefinitions/include/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
index 48c4147..b70c595 100644
--- a/services/audiopolicy/common/managerdefinitions/include/Serializer.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -21,5 +21,9 @@
 namespace android {
 
 status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config);
+// In VTS mode all vendor extensions are ignored. This is done because
+// VTS tests are built using AOSP code and thus can not use vendor overlays
+// of system libraries.
+status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfig *config);
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 129f6f6..562c213 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -20,8 +20,8 @@
 #include <memory>
 #include <string>
 #include <utility>
+#include <variant>
 
-#include <hidl/Status.h>
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
 #include <media/convert.h>
@@ -36,12 +36,14 @@
 
 namespace {
 
-// TODO(mnaganov): Consider finding an alternative for using HIDL code.
-using hardware::Return;
-using hardware::Status;
-using hardware::Void;
 using utilities::convertTo;
 
+static inline bool maybeVendorExtension(const std::string& s) {
+    // Only checks whether the string starts with the "vendor prefix".
+    static const std::string vendorPrefix = "VX_";
+    return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix;
+}
+
 template<typename E, typename C>
 struct AndroidCollectionTraits {
     typedef sp<E> Element;
@@ -187,7 +189,7 @@
 
 struct GlobalConfigTraits
 {
-    typedef void Element;
+    typedef std::monostate Element;
 
     static constexpr const char *tag = "globalConfiguration";
 
@@ -203,7 +205,7 @@
 
 struct SurroundSoundTraits
 {
-    typedef void Element;
+    typedef std::monostate Element;
 
     static constexpr const char *tag = "surroundSound";
 
@@ -226,14 +228,15 @@
 class PolicySerializer
 {
 public:
-    status_t deserialize(const char *configFile, AudioPolicyConfig *config);
+    status_t deserialize(const char *configFile, AudioPolicyConfig *config,
+            bool ignoreVendorExtensions = false);
 
     template <class Trait>
     status_t deserializeCollection(const xmlNode *cur,
             typename Trait::Collection *collection,
             typename Trait::PtrSerializingCtx serializingContext);
     template <class Trait>
-    Return<typename Trait::Element> deserialize(const xmlNode *cur,
+    std::variant<status_t, typename Trait::Element> deserialize(const xmlNode *cur,
             typename Trait::PtrSerializingCtx serializingContext);
 
 private:
@@ -242,6 +245,7 @@
 
     typedef AudioPolicyConfig Element;
 
+    bool mIgnoreVendorExtensions = false;
     std::string mChannelMasksSeparator = ",";
     std::string mSamplingRatesSeparator = ",";
     std::string mFlagsSeparator = "|";
@@ -307,14 +311,17 @@
         }
         for (; child != NULL; child = child->next) {
             if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
-                auto element = deserialize<Trait>(child, serializingContext);
-                if (element.isOk()) {
-                    status_t status = Trait::addElementToCollection(element, collection);
+                auto maybeElement = deserialize<Trait>(child, serializingContext);
+                if (maybeElement.index() == 1) {
+                    status_t status = Trait::addElementToCollection(
+                            std::get<1>(maybeElement), collection);
                     if (status != NO_ERROR) {
                         ALOGE("%s: could not add element to %s collection", __func__,
                             Trait::collectionTag);
                         return status;
                     }
+                } else if (mIgnoreVendorExtensions && std::get<status_t>(maybeElement) == NO_INIT) {
+                    // Skip a vendor extension element.
                 } else {
                     return BAD_VALUE;
                 }
@@ -328,8 +335,8 @@
 }
 
 template<>
-Return<AudioGainTraits::Element> PolicySerializer::deserialize<AudioGainTraits>(const xmlNode *cur,
-        AudioGainTraits::PtrSerializingCtx /*serializingContext*/)
+std::variant<status_t, AudioGainTraits::Element> PolicySerializer::deserialize<AudioGainTraits>(
+        const xmlNode *cur, AudioGainTraits::PtrSerializingCtx /*serializingContext*/)
 {
     using Attributes = AudioGainTraits::Attributes;
 
@@ -393,12 +400,13 @@
     if (gain->getMode() != 0) {
         return gain;
     } else {
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
 }
 
 template<>
-Return<AudioProfileTraits::Element> PolicySerializer::deserialize<AudioProfileTraits>(
+std::variant<status_t, AudioProfileTraits::Element>
+PolicySerializer::deserialize<AudioProfileTraits>(
         const xmlNode *cur, AudioProfileTraits::PtrSerializingCtx /*serializingContext*/)
 {
     using Attributes = AudioProfileTraits::Attributes;
@@ -407,6 +415,10 @@
     std::string format = getXmlAttribute(cur, Attributes::format);
     std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
 
+    if (mIgnoreVendorExtensions && maybeVendorExtension(format)) {
+        ALOGI("%s: vendor extension format \"%s\" skipped", __func__, format.c_str());
+        return NO_INIT;
+    }
     AudioProfileTraits::Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
             channelMasksFromString(channels, mChannelMasksSeparator.c_str()),
             samplingRatesFromString(samplingRates, mSamplingRatesSeparator.c_str()));
@@ -419,21 +431,21 @@
 }
 
 template<>
-Return<MixPortTraits::Element> PolicySerializer::deserialize<MixPortTraits>(const xmlNode *child,
-        MixPortTraits::PtrSerializingCtx /*serializingContext*/)
+std::variant<status_t, MixPortTraits::Element> PolicySerializer::deserialize<MixPortTraits>(
+        const xmlNode *child, MixPortTraits::PtrSerializingCtx /*serializingContext*/)
 {
     using Attributes = MixPortTraits::Attributes;
 
     std::string name = getXmlAttribute(child, Attributes::name);
     if (name.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::name);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     ALOGV("%s: %s %s=%s", __func__, MixPortTraits::tag, Attributes::name, name.c_str());
     std::string role = getXmlAttribute(child, Attributes::role);
     if (role.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::role);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     ALOGV("%s: Role=%s", __func__, role.c_str());
     audio_port_role_t portRole = (role == Attributes::roleSource) ?
@@ -444,7 +456,7 @@
     AudioProfileTraits::Collection profiles;
     status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     if (profiles.empty()) {
         profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
@@ -476,7 +488,7 @@
     AudioGainTraits::Collection gains;
     status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     mixPort->setGains(gains);
 
@@ -484,7 +496,7 @@
 }
 
 template<>
-Return<DevicePortTraits::Element> PolicySerializer::deserialize<DevicePortTraits>(
+std::variant<status_t, DevicePortTraits::Element> PolicySerializer::deserialize<DevicePortTraits>(
         const xmlNode *cur, DevicePortTraits::PtrSerializingCtx /*serializingContext*/)
 {
     using Attributes = DevicePortTraits::Attributes;
@@ -493,30 +505,34 @@
     std::string name = getXmlAttribute(cur, Attributes::tagName);
     if (name.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::tagName);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
     std::string typeName = getXmlAttribute(cur, Attributes::type);
     if (typeName.empty()) {
         ALOGE("%s: no type for %s", __func__, name.c_str());
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
     std::string role = getXmlAttribute(cur, Attributes::role);
     if (role.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::role);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
     audio_port_role_t portRole = (role == Attributes::roleSource) ?
                 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
+    if (mIgnoreVendorExtensions && maybeVendorExtension(typeName)) {
+        ALOGI("%s: vendor extension device type \"%s\" skipped", __func__, typeName.c_str());
+        return NO_INIT;
+    }
     audio_devices_t type = AUDIO_DEVICE_NONE;
     if (!DeviceConverter::fromString(typeName, type) ||
             (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
             (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
         ALOGW("%s: bad type %08x", __func__, type);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
     ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
@@ -531,7 +547,7 @@
     AudioProfileTraits::Collection profiles;
     status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     if (profiles.empty()) {
         profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
@@ -544,7 +560,7 @@
     // Deserialize AudioGain children
     status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     ALOGV("%s: adding device tag %s type %08x address %s", __func__,
           deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
@@ -552,7 +568,7 @@
 }
 
 template<>
-Return<RouteTraits::Element> PolicySerializer::deserialize<RouteTraits>(
+std::variant<status_t, RouteTraits::Element> PolicySerializer::deserialize<RouteTraits>(
         const xmlNode *cur, RouteTraits::PtrSerializingCtx ctx)
 {
     using Attributes = RouteTraits::Attributes;
@@ -560,7 +576,7 @@
     std::string type = getXmlAttribute(cur, Attributes::type);
     if (type.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::type);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     audio_route_type_t routeType = (type == Attributes::typeMix) ?
                 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
@@ -571,20 +587,24 @@
     std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
     if (sinkAttr.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::sink);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     // Convert Sink name to port pointer
     sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
-    if (sink == NULL) {
+    if (sink == NULL && !mIgnoreVendorExtensions) {
         ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
+    } else if (sink == NULL) {
+        ALOGW("Skipping route to sink \"%s\" as it likely has vendor extension type",
+                sinkAttr.c_str());
+        return NO_INIT;
     }
     route->setSink(sink);
 
     std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
     if (sourcesAttr.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::sources);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     // Tokenize and Convert Sources name to port pointer
     PolicyAudioPortVector sources;
@@ -594,11 +614,15 @@
     while (devTag != NULL) {
         if (strlen(devTag) != 0) {
             sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
-            if (source == NULL) {
+            if (source == NULL && !mIgnoreVendorExtensions) {
                 ALOGE("%s: no source found with name=%s", __func__, devTag);
-                return Status::fromStatusT(BAD_VALUE);
+                return BAD_VALUE;
+            } else if (source == NULL) {
+                ALOGW("Skipping route source \"%s\" as it likely has vendor extension type",
+                        devTag);
+            } else {
+                sources.add(source);
             }
-            sources.add(source);
         }
         devTag = strtok(NULL, ",");
     }
@@ -613,7 +637,7 @@
 }
 
 template<>
-Return<ModuleTraits::Element> PolicySerializer::deserialize<ModuleTraits>(
+std::variant<status_t, ModuleTraits::Element> PolicySerializer::deserialize<ModuleTraits>(
         const xmlNode *cur, ModuleTraits::PtrSerializingCtx ctx)
 {
     using Attributes = ModuleTraits::Attributes;
@@ -625,7 +649,7 @@
     std::string name = getXmlAttribute(cur, Attributes::name);
     if (name.empty()) {
         ALOGE("%s: No %s found", __func__, Attributes::name);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     uint32_t versionMajor = 0, versionMinor = 0;
     std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
@@ -643,21 +667,21 @@
     MixPortTraits::Collection mixPorts;
     status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     module->setProfiles(mixPorts);
 
     DevicePortTraits::Collection devicePorts;
     status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     module->setDeclaredDevices(devicePorts);
 
     RouteTraits::Collection routes;
     status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
     if (status != NO_ERROR) {
-        return Status::fromStatusT(status);
+        return status;
     }
     module->setRoutes(routes);
 
@@ -677,6 +701,12 @@
                         sp<DeviceDescriptor> device = module->getDeclaredDevices().
                                 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
                                                         attachedDevice.get())));
+                        if (device == nullptr && mIgnoreVendorExtensions) {
+                            ALOGW("Skipped attached device \"%s\" because it likely uses a vendor"
+                                    "extension type",
+                                    reinterpret_cast<const char*>(attachedDevice.get()));
+                            continue;
+                        }
                         ctx->addDevice(device);
                     }
                 }
@@ -703,7 +733,8 @@
 }
 
 template<>
-Return<GlobalConfigTraits::Element> PolicySerializer::deserialize<GlobalConfigTraits>(
+std::variant<status_t, GlobalConfigTraits::Element>
+PolicySerializer::deserialize<GlobalConfigTraits>(
         const xmlNode *root, GlobalConfigTraits::PtrSerializingCtx config)
 {
     using Attributes = GlobalConfigTraits::Attributes;
@@ -725,14 +756,15 @@
             if (!engineLibrarySuffix.empty()) {
                 config->setEngineLibraryNameSuffix(engineLibrarySuffix);
             }
-            return Void();
+            return NO_ERROR;
         }
     }
-    return Void();
+    return NO_ERROR;
 }
 
 template<>
-Return<SurroundSoundTraits::Element> PolicySerializer::deserialize<SurroundSoundTraits>(
+std::variant<status_t, SurroundSoundTraits::Element>
+PolicySerializer::deserialize<SurroundSoundTraits>(
         const xmlNode *root, SurroundSoundTraits::PtrSerializingCtx config)
 {
     config->setDefaultSurroundFormats();
@@ -745,14 +777,15 @@
             if (status == NO_ERROR) {
                 config->setSurroundFormats(formats);
             }
-            return Void();
+            return NO_ERROR;
         }
     }
-    return Void();
+    return NO_ERROR;
 }
 
 template<>
-Return<SurroundSoundFormatTraits::Element> PolicySerializer::deserialize<SurroundSoundFormatTraits>(
+std::variant<status_t, SurroundSoundFormatTraits::Element>
+PolicySerializer::deserialize<SurroundSoundFormatTraits>(
         const xmlNode *cur, SurroundSoundFormatTraits::PtrSerializingCtx /*serializingContext*/)
 {
     using Attributes = SurroundSoundFormatTraits::Attributes;
@@ -760,12 +793,16 @@
     std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
     if (formatLiteral.empty()) {
         ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
+    }
+    if (mIgnoreVendorExtensions && maybeVendorExtension(formatLiteral)) {
+        ALOGI("%s: vendor extension format \"%s\" skipped", __func__, formatLiteral.c_str());
+        return NO_INIT;
     }
     audio_format_t format = formatFromString(formatLiteral);
     if (format == AUDIO_FORMAT_DEFAULT) {
         ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
-        return Status::fromStatusT(BAD_VALUE);
+        return BAD_VALUE;
     }
     SurroundSoundFormatTraits::Element pair = std::make_pair(
             format, SurroundSoundFormatTraits::Collection::mapped_type{});
@@ -777,14 +814,16 @@
         auto result = pair.second.insert(subformat);
         if (!result.second) {
             ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
-            return Status::fromStatusT(BAD_VALUE);
+            return BAD_VALUE;
         }
     }
     return pair;
 }
 
-status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config,
+                                       bool ignoreVendorExtensions)
 {
+    mIgnoreVendorExtensions = ignoreVendorExtensions;
     auto doc = make_xmlUnique(xmlParseFile(configFile));
     if (doc == nullptr) {
         ALOGE("%s: Could not parse %s document.", __func__, configFile);
@@ -845,4 +884,12 @@
     return status;
 }
 
+status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfig *config)
+{
+    PolicySerializer serializer;
+    status_t status = serializer.deserialize(fileName, config, true /*ignoreVendorExtensions*/);
+    if (status != OK) config->clear();
+    return status;
+}
+
 } // namespace android
diff --git a/services/mediametrics/tests/Android.bp b/services/mediametrics/tests/Android.bp
index 71193a2..3baf739 100644
--- a/services/mediametrics/tests/Android.bp
+++ b/services/mediametrics/tests/Android.bp
@@ -11,6 +11,10 @@
     name: "mediametrics_tests",
     test_suites: ["device-tests"],
 
+    // not all shared libraries are populated in the 2nd architecture in
+    // particular, libmediametricsservice we use to have a tame copy of the service
+    compile_multilib: "first",
+
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/tuner/Android.bp b/services/tuner/Android.bp
index 63120f8..df2b4a3 100644
--- a/services/tuner/Android.bp
+++ b/services/tuner/Android.bp
@@ -81,6 +81,7 @@
         "android.hardware.tv.tuner@1.0",
         "android.hardware.tv.tuner@1.1",
         "libbase",
+        "libbinder",
         "libbinder_ndk",
         "libcutils",
         "libfmq",
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 9624e27..77e1c40 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "TunerService"
 
 #include <android/binder_manager.h>
+#include <android/content/pm/IPackageManagerNative.h>
+#include <binder/IServiceManager.h>
 #include <utils/Log.h>
 #include "TunerService.h"
 #include "TunerFrontend.h"
@@ -50,6 +52,33 @@
 namespace android {
 
 TunerService::TunerService() {
+    sp<IServiceManager> serviceMgr = defaultServiceManager();
+    sp<content::pm::IPackageManagerNative> packageMgr;
+    if (serviceMgr.get() == nullptr) {
+        ALOGE("%s: Cannot find service manager", __func__);
+        return;
+    } else {
+        sp<IBinder> binder = serviceMgr->waitForService(String16("package_native"));
+        packageMgr = interface_cast<content::pm::IPackageManagerNative>(binder);
+    }
+
+    bool hasFeature = false;
+    if (packageMgr != nullptr) {
+        binder::Status status = packageMgr->hasSystemFeature(FEATURE_TUNER, 0, &hasFeature);
+        if (!status.isOk()) {
+            ALOGE("%s: hasSystemFeature failed: %s",
+                    __func__, status.exceptionMessage().c_str());
+            return;
+        }
+        if (!hasFeature) {
+            ALOGD("Current device does not support tuner feaure.");
+            return;
+        }
+    } else {
+        ALOGD("%s: Cannot find package manager.", __func__);
+        return;
+    }
+
     ::ndk::SpAIBinder binder(AServiceManager_waitForService("tv_tuner_resource_mgr"));
     mTunerResourceManager = ITunerResourceManager::fromBinder(binder);
     updateTunerResources();
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index 0570681..f8e2ee6 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -72,6 +72,8 @@
 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;
+// System Feature defined in PackageManager
+static const ::android::String16 FEATURE_TUNER(::android::String16("android.hardware.tv.tuner"));
 
 typedef enum {
     FRONTEND,