Merge "cameraserver: Fix logic to skip callbacks for non HAL3 devices for vendor listeners."
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index d6f1412..68db233 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -33,7 +33,9 @@
         dev->unlockDevice();
     }
     // Fire onClosed callback
-    (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+    if (mUserSessionCallback.onClosed != nullptr) {
+        (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+    }
     ALOGV("~ACameraCaptureSession: %p is deleted", this);
 }
 
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 7ab0124..938b5f5 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -253,21 +253,9 @@
         return true;
     }
 
-    static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
-
-    static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
-
-    static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
-    static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
-    static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
    private:
-    ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
-                                           onDeviceError};
-    ACameraCaptureSession_stateCallbacks mSessionCb{
-        this, onSessionClosed, onSessionReady, onSessionActive};
+    ACameraDevice_StateCallbacks mDeviceCb{this, nullptr, nullptr};
+    ACameraCaptureSession_stateCallbacks mSessionCb{ this, nullptr, nullptr, nullptr};
 
     native_handle_t* mImgReaderAnw = nullptr;  // not owned by us.
 
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index cacd465..0d591d7 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -37,7 +37,7 @@
     static constexpr int64_t kLogDurationUs = 5000000; // 5 secs
 
     static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
-    static constexpr size_t kMinBufferCountForEviction = 40;
+    static constexpr size_t kMinBufferCountForEviction = 25;
 }
 
 // Buffer structure in bufferpool process
@@ -718,8 +718,8 @@
                   mStats.mTotalFetches, mStats.mTotalTransfers);
         }
         for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
-            if (!clearCache && mStats.mSizeCached < kMinAllocBytesForEviction
-                    && mBuffers.size() < kMinBufferCountForEviction) {
+            if (!clearCache && (mStats.mSizeCached < kMinAllocBytesForEviction
+                    || mBuffers.size() < kMinBufferCountForEviction)) {
                 break;
             }
             auto it = mBuffers.find(*freeIt);
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index 1dc676b..4db94f5 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -155,11 +155,10 @@
       mNumBytesPerInputFrame(0u),
       mOutBufferSize(0u),
       mSentCodecSpecificData(false),
-      mInputTimeSet(false),
       mInputSize(0),
-      mNextFrameTimestampUs(0),
       mSignalledError(false),
-      mOutIndex(0u) {
+      mOutIndex(0u),
+      mRemainderLen(0u) {
 }
 
 C2SoftAacEnc::~C2SoftAacEnc() {
@@ -181,10 +180,11 @@
 
 c2_status_t C2SoftAacEnc::onStop() {
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mNextFrameTimestampUs = 0;
+    mNextFrameTimestampUs.reset();
+    mLastFrameEndTimestampUs.reset();
     mSignalledError = false;
+    mRemainderLen = 0;
     return C2_OK;
 }
 
@@ -199,9 +199,9 @@
 
 c2_status_t C2SoftAacEnc::onFlush_sm() {
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mNextFrameTimestampUs = 0;
+    mNextFrameTimestampUs.reset();
+    mLastFrameEndTimestampUs.reset();
     return C2_OK;
 }
 
@@ -364,23 +364,35 @@
         data = view.data();
         capacity = view.capacity();
     }
-    if (!mInputTimeSet && capacity > 0) {
-        mNextFrameTimestampUs = work->input.ordinal.timestamp;
-        mInputTimeSet = true;
+    c2_cntr64_t inputTimestampUs = work->input.ordinal.timestamp;
+    if (inputTimestampUs < mLastFrameEndTimestampUs.value_or(inputTimestampUs)) {
+        ALOGW("Correcting overlapping timestamp: last frame ended at %lldus but "
+              "current frame is starting at %lldus. Using the last frame's end timestamp",
+              mLastFrameEndTimestampUs->peekll(), inputTimestampUs.peekll());
+        inputTimestampUs = *mLastFrameEndTimestampUs;
+    }
+    if (capacity > 0) {
+        if (!mNextFrameTimestampUs) {
+            mNextFrameTimestampUs = work->input.ordinal.timestamp;
+        }
+        mLastFrameEndTimestampUs = inputTimestampUs
+                + (capacity / sizeof(int16_t) * 1000000ll / channelCount / sampleRate);
     }
 
-    size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
-            / mNumBytesPerInputFrame;
+    size_t numFrames =
+        (mRemainderLen + capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
+        / mNumBytesPerInputFrame;
     ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu "
-          "mNumBytesPerInputFrame = %u inputTS = %lld",
-          capacity, mInputSize, numFrames,
-          mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll());
+          "mNumBytesPerInputFrame = %u inputTS = %lld remaining = %zu",
+          capacity, mInputSize, numFrames, mNumBytesPerInputFrame, inputTimestampUs.peekll(),
+          mRemainderLen);
 
     std::shared_ptr<C2LinearBlock> block;
     std::unique_ptr<C2WriteView> wView;
     uint8_t *outPtr = temp;
     size_t outAvailable = 0u;
     uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
+    size_t bytesPerSample = channelCount * sizeof(int16_t);
 
     AACENC_InArgs inargs;
     AACENC_OutArgs outargs;
@@ -449,7 +461,25 @@
     };
     std::list<OutputBuffer> outputBuffers;
 
-    while (encoderErr == AACENC_OK && inargs.numInSamples > 0) {
+    if (mRemainderLen > 0) {
+        size_t offset = 0;
+        for (; mRemainderLen < bytesPerSample && offset < capacity; ++offset) {
+            mRemainder[mRemainderLen++] = data[offset];
+        }
+        data += offset;
+        capacity -= offset;
+        if (mRemainderLen == bytesPerSample) {
+            inBuffer[0] = mRemainder;
+            inBufferSize[0] = bytesPerSample;
+            inargs.numInSamples = channelCount;
+            mRemainderLen = 0;
+            ALOGV("Processing remainder");
+        } else {
+            // We have exhausted the input already
+            inargs.numInSamples = 0;
+        }
+    }
+    while (encoderErr == AACENC_OK && inargs.numInSamples >= channelCount) {
         if (numFrames && !block) {
             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
             // TODO: error handling, proper usage, etc.
@@ -482,11 +512,13 @@
                 mInputSize = 0;
                 int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
                         + outargs.numInSamples;
-                c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs;
-                mNextFrameTimestampUs = work->input.ordinal.timestamp
+                ALOGV("consumed = %d, capacity = %zu, inSamples = %d, outSamples = %d",
+                      consumed, capacity, inargs.numInSamples, outargs.numInSamples);
+                c2_cntr64_t currentFrameTimestampUs = *mNextFrameTimestampUs;
+                mNextFrameTimestampUs = inputTimestampUs
                         + (consumed * 1000000ll / channelCount / sampleRate);
                 std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
-#if defined(LOG_NDEBUG) && !LOG_NDEBUG
+#if 0
                 hexdump(outPtr, std::min(outargs.numOutBytes, 256));
 #endif
                 outPtr = temp;
@@ -498,7 +530,11 @@
                 mInputSize += outargs.numInSamples * sizeof(int16_t);
             }
 
-            if (outargs.numInSamples > 0) {
+            if (inBuffer[0] == mRemainder) {
+                inBuffer[0] = const_cast<uint8_t *>(data);
+                inBufferSize[0] = capacity;
+                inargs.numInSamples = capacity / sizeof(int16_t);
+            } else if (outargs.numInSamples > 0) {
                 inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
                 inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
                 inargs.numInSamples -= outargs.numInSamples;
@@ -506,9 +542,8 @@
         }
         ALOGV("encoderErr = %d mInputSize = %zu "
               "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
-              encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll());
+              encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs->peekll());
     }
-
     if (eos && inBufferSize[0] > 0) {
         if (numFrames && !block) {
             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
@@ -539,6 +574,14 @@
                            &outBufDesc,
                            &inargs,
                            &outargs);
+        inBufferSize[0] = 0;
+    }
+
+    if (inBufferSize[0] > 0) {
+        for (size_t i = 0; i < inBufferSize[0]; ++i) {
+            mRemainder[i] = static_cast<uint8_t *>(inBuffer[0])[i];
+        }
+        mRemainderLen = inBufferSize[0];
     }
 
     while (outputBuffers.size() > 1) {
@@ -583,9 +626,9 @@
 
     (void)pool;
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mNextFrameTimestampUs = 0;
+    mNextFrameTimestampUs.reset();
+    mLastFrameEndTimestampUs.reset();
 
     // TODO: we don't have any pending work at this time to drain.
     return C2_OK;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 2655039..9a28280 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -18,6 +18,7 @@
 #define ANDROID_C2_SOFT_AAC_ENC_H_
 
 #include <atomic>
+#include <optional>
 
 #include <SimpleC2Component.h>
 
@@ -54,13 +55,17 @@
     UINT mOutBufferSize;
 
     bool mSentCodecSpecificData;
-    bool mInputTimeSet;
     size_t mInputSize;
-    c2_cntr64_t mNextFrameTimestampUs;
+    std::optional<c2_cntr64_t> mNextFrameTimestampUs;
+    std::optional<c2_cntr64_t> mLastFrameEndTimestampUs;
 
     bool mSignalledError;
     std::atomic_uint64_t mOutIndex;
 
+    // We support max 6 channels
+    uint8_t mRemainder[6 * sizeof(int16_t)];
+    size_t mRemainderLen;
+
     status_t initEncoder();
 
     status_t setAudioParams();
diff --git a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
index 18e6db2..15564d9 100644
--- a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
+++ b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
@@ -66,7 +66,7 @@
         addParameter(
                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
                 .withDefault(new C2StreamSampleRateInfo::output(0u, 48000))
-                .withFields({C2F(mSampleRate, value).inRange(8000, 96000)})
+                .withFields({C2F(mSampleRate, value).inRange(8000, 192000)})
                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
                 .build());
 
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index a52ca15..a759e8f 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -593,12 +593,10 @@
         }
     }
 
-    int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
-
     if (inSize) {
         uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
         vpx_codec_err_t err = vpx_codec_decode(
-                mCodecCtx, bitstream, inSize, &frameIndex, 0);
+                mCodecCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
         if (err != VPX_CODEC_OK) {
             ALOGE("on2 decoder failed to decode frame. err: %d", err);
             mSignalledError = true;
@@ -608,7 +606,20 @@
         }
     }
 
-    (void)outputBuffer(pool, work);
+    status_t err = outputBuffer(pool, work);
+    if (err == NOT_ENOUGH_DATA) {
+        if (inSize > 0) {
+            ALOGV("Maybe non-display frame at %lld.",
+                  work->input.ordinal.frameIndex.peekll());
+            // send the work back with empty buffer.
+            inSize = 0;
+        }
+    } else if (err != OK) {
+        ALOGD("Error while getting the output frame out");
+        // work->result would be already filled; do fillEmptyWork() below to
+        // send the work back.
+        inSize = 0;
+    }
 
     if (eos) {
         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
@@ -742,16 +753,16 @@
     }
     return;
 }
-bool C2SoftVpxDec::outputBuffer(
+status_t C2SoftVpxDec::outputBuffer(
         const std::shared_ptr<C2BlockPool> &pool,
         const std::unique_ptr<C2Work> &work)
 {
-    if (!(work && pool)) return false;
+    if (!(work && pool)) return BAD_VALUE;
 
     vpx_codec_iter_t iter = nullptr;
     vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
 
-    if (!img) return false;
+    if (!img) return NOT_ENOUGH_DATA;
 
     if (img->d_w != mWidth || img->d_h != mHeight) {
         mWidth = img->d_w;
@@ -768,7 +779,7 @@
             mSignalledError = true;
             work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
-            return false;
+            return UNKNOWN_ERROR;
         }
 
     }
@@ -791,18 +802,19 @@
     if (err != C2_OK) {
         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
         work->result = err;
-        return false;
+        return UNKNOWN_ERROR;
     }
 
     C2GraphicView wView = block->map().get();
     if (wView.error()) {
         ALOGE("graphic view map failed %d", wView.error());
         work->result = C2_CORRUPTED;
-        return false;
+        return UNKNOWN_ERROR;
     }
 
-    ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
-           block->width(), block->height(), mWidth, mHeight, (int)*(int64_t *)img->user_priv);
+    ALOGV("provided (%dx%d) required (%dx%d), out frameindex %lld",
+           block->width(), block->height(), mWidth, mHeight,
+           ((c2_cntr64_t *)img->user_priv)->peekll());
 
     uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
     size_t srcYStride = img->stride[VPX_PLANE_Y];
@@ -858,8 +870,8 @@
                 dstYStride, dstUVStride,
                 mWidth, mHeight);
     }
-    finishWork(*(int64_t *)img->user_priv, work, std::move(block));
-    return true;
+    finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
+    return OK;
 }
 
 c2_status_t C2SoftVpxDec::drainInternal(
@@ -875,7 +887,7 @@
         return C2_OMITTED;
     }
 
-    while ((outputBuffer(pool, work))) {
+    while (outputBuffer(pool, work) == OK) {
     }
 
     if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index e51bcee..2065165 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -85,7 +85,7 @@
     status_t destroyDecoder();
     void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
                     const std::shared_ptr<C2GraphicBlock> &block);
-    bool outputBuffer(
+    status_t outputBuffer(
             const std::shared_ptr<C2BlockPool> &pool,
             const std::unique_ptr<C2Work> &work);
     c2_status_t drainInternal(
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 65d7a39..78ddd6d 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1286,7 +1286,8 @@
     {
         Mutexed<Config>::Locked config(mConfig);
         inputFormat = config->mInputFormat;
-        outputFormat = config->mOutputFormat;
+        // start triggers format dup
+        outputFormat = config->mOutputFormat = config->mOutputFormat->dup();
         if (config->mInputSurface) {
             err2 = config->mInputSurface->start();
         }
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 5f969db..a4c30fa 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1073,7 +1073,7 @@
         } else {
             output->buffers.reset(new LinearOutputBuffers(mName));
         }
-        output->buffers->setFormat(outputFormat->dup());
+        output->buffers->setFormat(outputFormat);
 
 
         // Try to set output surface to created block pool if given.
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 752bc46..0470a31 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -600,7 +600,7 @@
     }
 
     std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
+        = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, getId());
     ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
@@ -622,7 +622,7 @@
     // TODO: get capacity and validate it
     const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
     std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
+        = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), getId());
     c2_status_t ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 5b2bd7b..e0408b7 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -35,6 +35,10 @@
 #include <memory>
 #include <mutex>
 
+#ifdef __ANDROID_APEX__
+#include <android-base/properties.h>
+#endif
+
 namespace android {
 
 /**
@@ -599,9 +603,33 @@
 
             struct Setter {
                 static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+#ifdef __ANDROID_APEX__
+                    static int32_t defaultHeapMask = [] {
+                        int32_t heapmask = base::GetIntProperty(
+                                "ro.com.android.media.swcodec.ion.heapmask", int32_t(0xFFFFFFFF));
+                        ALOGD("Default ION heapmask = %d", heapmask);
+                        return heapmask;
+                    }();
+                    static int32_t defaultFlags = [] {
+                        int32_t flags = base::GetIntProperty(
+                                "ro.com.android.media.swcodec.ion.flags", 0);
+                        ALOGD("Default ION flags = %d", flags);
+                        return flags;
+                    }();
+                    static uint32_t defaultAlign = [] {
+                        uint32_t align = base::GetUintProperty(
+                                "ro.com.android.media.swcodec.ion.align", 0u);
+                        ALOGD("Default ION align = %d", align);
+                        return align;
+                    }();
+                    me.set().heapMask = defaultHeapMask;
+                    me.set().allocFlags = defaultFlags;
+                    me.set().minAlignment = defaultAlign;
+#else
                     me.set().heapMask = ~0;
                     me.set().allocFlags = 0;
                     me.set().minAlignment = 0;
+#endif
                     return C2R::Ok();
                 }
             };
diff --git a/media/codec2/vndk/util/C2InterfaceUtils.cpp b/media/codec2/vndk/util/C2InterfaceUtils.cpp
index 61ec911..0c1729b 100644
--- a/media/codec2/vndk/util/C2InterfaceUtils.cpp
+++ b/media/codec2/vndk/util/C2InterfaceUtils.cpp
@@ -216,9 +216,14 @@
     if (limit.contains(minMask) && contains(minMask)) {
         values[0] = minMask;
         // keep only flags that are covered by limit
-        std::remove_if(values.begin(), values.end(), [&limit, minMask](const C2Value::Primitive &v) -> bool {
-            T value = v.ref<ValueType>() | minMask;
-            return value == minMask || !limit.contains(value); });
+        values.erase(std::remove_if(values.begin(), values.end(),
+                                    [&limit, minMask](
+                                        const C2Value::Primitive &v) -> bool {
+                                      T value = v.ref<ValueType>() | minMask;
+                                      return value == minMask ||
+                                             !limit.contains(value);
+                                    }),
+                     values.end());
         // we also need to do it vice versa
         for (const C2Value::Primitive &v : _mValues) {
             T value = v.ref<ValueType>() | minMask;
@@ -264,24 +269,33 @@
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedValueSet<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedRange<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedFlags<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index ffeff42..26431a4 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -144,6 +144,7 @@
 
 AMRExtractor::AMRExtractor(DataSourceHelper *source)
     : mDataSource(source),
+      mMeta(NULL),
       mInitCheck(NO_INIT),
       mOffsetTableLength(0) {
     float confidence;
@@ -191,7 +192,9 @@
 
 AMRExtractor::~AMRExtractor() {
     delete mDataSource;
-    AMediaFormat_delete(mMeta);
+    if (mMeta) {
+        AMediaFormat_delete(mMeta);
+    }
 }
 
 media_status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 8c8e6d1..0773387 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -700,8 +700,8 @@
     }
 
 private:
-    uint32_t mWidth;
-    uint32_t mHeight;
+    int32_t mWidth;
+    int32_t mHeight;
 };
 
 status_t IspeBox::parse(off64_t offset, size_t size) {
@@ -715,12 +715,19 @@
     if (size < 8) {
         return ERROR_MALFORMED;
     }
-    if (!source()->getUInt32(offset, &mWidth)
-            || !source()->getUInt32(offset + 4, &mHeight)) {
+    if (!source()->getUInt32(offset, (uint32_t *)&mWidth)
+            || !source()->getUInt32(offset + 4, (uint32_t *)&mHeight)) {
         return ERROR_IO;
     }
-    ALOGV("property ispe: %dx%d", mWidth, mHeight);
 
+    // Validate that the dimension doesn't cause overflow on calculated max input size.
+    // Max input size is width*height*1.5, restrict width*height to 1<<29 so that
+    // we don't need to cast to int64_t when doing mults.
+    if (mWidth <= 0 || mHeight <= 0 || mWidth > (1 << 29) / mHeight) {
+        return ERROR_MALFORMED;
+    }
+
+    ALOGV("property ispe: %dx%d", mWidth, mHeight);
     return OK;
 }
 
@@ -1524,8 +1531,9 @@
             default: break; // don't set if invalid
         }
     }
+    // we validated no overflow in IspeBox::parse()
     AMediaFormat_setInt32(meta,
-            AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 1.5);
+            AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
 
     if (!image->thumbnails.empty()) {
         ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(image->thumbnails[0]);
@@ -1561,8 +1569,9 @@
                 AMEDIAFORMAT_KEY_TILE_WIDTH, image->width);
         AMediaFormat_setInt32(meta,
                 AMEDIAFORMAT_KEY_TILE_HEIGHT, image->height);
+        // we validated no overflow in IspeBox::parse()
         AMediaFormat_setInt32(meta,
-                AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 1.5);
+                AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
     }
 
     if (image->hvcc == NULL) {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 9d5890c..86ed610 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1561,8 +1561,12 @@
         {
             *offset += chunk_size;
 
-            if (mLastTrack == NULL)
+            // the absolute minimum size of a compliant mett box is 11 bytes:
+            // 6 byte reserved, 2 byte index, null byte, one char mime_format, null byte
+            // The resulting mime_format would be invalid at that size though.
+            if (mLastTrack == NULL || chunk_data_size < 11) {
                 return ERROR_MALFORMED;
+            }
 
             auto buffer = heapbuffer<uint8_t>(chunk_data_size);
             if (buffer.get() == NULL) {
@@ -1574,10 +1578,24 @@
                 return ERROR_IO;
             }
 
+            // ISO-14496-12:
+            // int8 reserved[6];               // should be all zeroes
+            // int16_t data_reference_index;
+            // char content_encoding[];        // null terminated, optional (= just the null byte)
+            // char mime_format[];             // null terminated, mandatory
+            // optional other boxes
+            //
+            // API < 29:
+            // char mime_format[];             // null terminated
+            //
+            // API >= 29
+            // char mime_format[];             // null terminated
+            // char mime_format[];             // null terminated
+
             // Prior to API 29, the metadata track was not compliant with ISO/IEC
             // 14496-12-2015. This led to some ISO-compliant parsers failing to read the
             // metatrack. As of API 29 and onwards, a change was made to metadata track to
-            // make it compliant with the standard. The workaround is to write the
+            // make it somewhat compatible with the standard. The workaround is to write the
             // null-terminated mime_format string twice. This allows compliant parsers to
             // read the missing reserved, data_reference_index, and content_encoding fields
             // from the first mime_type string. The actual mime_format field would then be
@@ -1586,27 +1604,27 @@
             // as it would only read the first null-terminated mime_format string. To enable
             // reading metadata tracks generated from both the non-compliant and compliant
             // formats, a check needs to be done to see which format is used.
-            int null_pos = 0;
-            const unsigned char *str = buffer.get();
-            while (null_pos < chunk_data_size) {
-              if (*(str + null_pos) == '\0') {
-                break;
-              }
-              ++null_pos;
-            }
+            const char *str = (const char*) buffer.get();
+            size_t string_length = strnlen(str, chunk_data_size);
 
-            if (null_pos == chunk_data_size - 1) {
-              // This is not a standard ompliant metadata track.
-              String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
-              AMediaFormat_setString(mLastTrack->meta,
-                  AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+            if (string_length == chunk_data_size - 1) {
+                // This is likely a pre API 29 file, since it's a single null terminated
+                // string filling the entire box.
+                AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, str);
             } else {
-              // This is a standard compliant metadata track.
-              String8 contentEncoding((const char *)(buffer.get() + 8));
-              String8 mimeFormat((const char *)(buffer.get() + 8 + contentEncoding.size() + 1),
-                  chunk_data_size - 8 - contentEncoding.size() - 1);
-              AMediaFormat_setString(mLastTrack->meta,
-                  AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+                // This might be a fully compliant metadata track, a "double mime" compatibility
+                // track, or anything else, including a single non-terminated string, so we need
+                // to determine the length of each string we want to parse out of the box.
+                size_t encoding_length = strnlen(str + 8, chunk_data_size - 8);
+                if (encoding_length + 8 >= chunk_data_size - 2) {
+                    // the encoding extends to the end of the box, so there's no mime_format
+                    return ERROR_MALFORMED;
+                }
+                String8 contentEncoding(str + 8, encoding_length);
+                String8 mimeFormat(str + 8 + encoding_length + 1,
+                        chunk_data_size - 8 - encoding_length - 1);
+                AMediaFormat_setString(mLastTrack->meta,
+                        AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
             }
             break;
         }
@@ -5775,11 +5793,11 @@
                       meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
                 AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
 
-                int32_t byteOrder;
-                AMediaFormat_getInt32(mFormat,
+                int32_t byteOrder = 0;
+                bool isGetBigEndian = AMediaFormat_getInt32(mFormat,
                         AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, &byteOrder);
 
-                if (byteOrder == 1) {
+                if (isGetBigEndian && byteOrder == 1) {
                     // Big-endian -> little-endian
                     uint16_t *dstData = (uint16_t *)buf;
                     uint16_t *srcData = (uint16_t *)buf;
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index bf29bf1..9dddf2c 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -655,6 +655,7 @@
     }
 
     mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
+    memset(mSampleTimeEntries, 0, sizeof(SampleTimeEntry) * mNumSampleSizes);
     if (!mSampleTimeEntries) {
         ALOGE("Cannot allocate sample entry table with %llu entries.",
                 (unsigned long long)mNumSampleSizes);
diff --git a/media/extractors/tests/ExtractorUnitTest.cpp b/media/extractors/tests/ExtractorUnitTest.cpp
index 64eda75..fca66a4 100644
--- a/media/extractors/tests/ExtractorUnitTest.cpp
+++ b/media/extractors/tests/ExtractorUnitTest.cpp
@@ -22,6 +22,7 @@
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/foundation/OpusHeader.h>
 
 #include "aac/AACExtractor.h"
 #include "amr/AMRExtractor.h"
@@ -43,7 +44,9 @@
 #define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"
 
 constexpr int32_t kMaxCount = 10;
-constexpr int32_t kOpusSeekPreRollUs = 80000;  // 80 ms;
+constexpr int32_t kAudioDefaultSampleDuration = 20000;                       // 20ms
+constexpr int32_t kRandomSeekToleranceUs = 2 * kAudioDefaultSampleDuration;  // 40 ms;
+constexpr int32_t kRandomSeed = 700;
 
 static ExtractorUnitTestEnvironment *gEnv = nullptr;
 
@@ -168,6 +171,47 @@
     return 0;
 }
 
+void randomSeekTest(MediaTrackHelper *track, int64_t clipDuration) {
+    int32_t status = 0;
+    int32_t seekCount = 0;
+    bool hasTimestamp = false;
+    vector<int64_t> seekToTimeStamp;
+    string seekPtsString;
+
+    srand(kRandomSeed);
+    while (seekCount < kMaxCount) {
+        int64_t timeStamp = ((double)rand() / RAND_MAX) * clipDuration;
+        seekToTimeStamp.push_back(timeStamp);
+        seekPtsString.append(to_string(timeStamp));
+        seekPtsString.append(", ");
+        seekCount++;
+    }
+
+    for (int64_t seekPts : seekToTimeStamp) {
+        MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
+                CMediaTrackReadOptions::SEEK_CLOSEST | CMediaTrackReadOptions::SEEK, seekPts);
+        ASSERT_NE(options, nullptr) << "Cannot create read option";
+
+        MediaBufferHelper *buffer = nullptr;
+        status = track->read(&buffer, options);
+        if (buffer) {
+            AMediaFormat *metaData = buffer->meta_data();
+            int64_t timeStamp = 0;
+            hasTimestamp = AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+            ASSERT_TRUE(hasTimestamp) << "Extractor didn't set timestamp for the given sample";
+
+            buffer->release();
+            EXPECT_LE(abs(timeStamp - seekPts), kRandomSeekToleranceUs)
+                    << "Seek unsuccessful. Expected timestamp range ["
+                    << seekPts - kRandomSeekToleranceUs << ", " << seekPts + kRandomSeekToleranceUs
+                    << "] "
+                    << "received " << timeStamp << ", list of input seek timestamps ["
+                    << seekPtsString << "]";
+        }
+        delete options;
+    }
+}
+
 void getSeekablePoints(vector<int64_t> &seekablePoints, MediaTrackHelper *track) {
     int32_t status = 0;
     if (!seekablePoints.empty()) {
@@ -380,11 +424,7 @@
 }
 
 TEST_P(ExtractorUnitTest, SeekTest) {
-    // Flac, Midi and Wav extractor can give samples from any pts and mark the given sample as
-    // sync frame. So, this seek test is not applicable to these extractors
-    if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV || mExtractorName == MIDI) {
-        return;
-    }
+    if (mDisableTest) return;
 
     ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
     string inputFileName = gEnv->getRes() + GetParam().second;
@@ -417,6 +457,32 @@
         MediaBufferGroup *bufferGroup = new MediaBufferGroup();
         status = cTrack->start(track, bufferGroup->wrap());
         ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+        // For Flac, Wav and Midi extractor, all samples are seek points.
+        // We cannot create list of all seekable points for these.
+        // This means that if we pass a seekToTimeStamp between two seek points, we may
+        // end up getting the timestamp of next sample as a seekable timestamp.
+        // This timestamp may/may not be a part of the seekable point vector thereby failing the
+        // test. So we test these extractors using random seek test.
+        if (mExtractorName == FLAC || mExtractorName == WAV || mExtractorName == MIDI) {
+            AMediaFormat *trackMeta = AMediaFormat_new();
+            ASSERT_NE(trackMeta, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+            status = mExtractor->getTrackMetaData(trackMeta, idx, 1);
+            ASSERT_EQ(OK, (media_status_t)status) << "Failed to get trackMetaData";
+
+            int64_t clipDuration = 0;
+            AMediaFormat_getInt64(trackMeta, AMEDIAFORMAT_KEY_DURATION, &clipDuration);
+            ASSERT_GT(clipDuration, 0) << "Invalid clip duration ";
+            randomSeekTest(track, clipDuration);
+            AMediaFormat_delete(trackMeta);
+            continue;
+        }
+        // Request seekable points for remaining extractors which will be used to validate the seek
+        // accuracy for the extractors. Depending on SEEK Mode, we expect the extractors to return
+        // the expected sync frame. We don't prefer random seek test for these extractors because
+        // they aren't expected to seek to random samples. MP4 for instance can seek to
+        // next/previous sync frames but not to samples between two sync frames.
         getSeekablePoints(seekablePoints, track);
         ASSERT_GT(seekablePoints.size(), 0)
                 << "Failed to get seekable points for " << GetParam().first << " extractor";
@@ -427,9 +493,31 @@
         ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
 
         bool isOpus = false;
+        int64_t opusSeekPreRollUs = 0;
         const char *mime;
         AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
-        if (!strcmp(mime, "audio/opus")) isOpus = true;
+        if (!strcmp(mime, "audio/opus")) {
+            isOpus = true;
+            void *seekPreRollBuf = nullptr;
+            size_t size = 0;
+            if (!AMediaFormat_getBuffer(trackFormat, "csd-2", &seekPreRollBuf, &size)) {
+                size_t opusHeadSize = 0;
+                size_t codecDelayBufSize = 0;
+                size_t seekPreRollBufSize = 0;
+                void *csdBuffer = nullptr;
+                void *opusHeadBuf = nullptr;
+                void *codecDelayBuf = nullptr;
+                AMediaFormat_getBuffer(trackFormat, "csd-0", &csdBuffer, &size);
+                ASSERT_NE(csdBuffer, nullptr);
+
+                GetOpusHeaderBuffers((uint8_t *)csdBuffer, size, &opusHeadBuf, &opusHeadSize,
+                                     &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+                                     &seekPreRollBufSize);
+            }
+            ASSERT_NE(seekPreRollBuf, nullptr)
+                    << "Invalid track format. SeekPreRoll info missing for Opus file";
+            opusSeekPreRollUs = *((int64_t *)seekPreRollBuf);
+        }
         AMediaFormat_delete(trackFormat);
 
         int32_t seekIdx = 0;
@@ -450,7 +538,7 @@
                 // extractor is calculated based on (seekPts - seekPreRollUs).
                 // So we add the preRoll value to the timeStamp we want to seek to.
                 if (isOpus) {
-                    seekToTimeStamp += kOpusSeekPreRollUs;
+                    seekToTimeStamp += opusSeekPreRollUs;
                 }
 
                 MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
diff --git a/media/libaudioclient/AudioAttributes.cpp b/media/libaudioclient/AudioAttributes.cpp
index 1ee6930..ff4ba06 100644
--- a/media/libaudioclient/AudioAttributes.cpp
+++ b/media/libaudioclient/AudioAttributes.cpp
@@ -57,7 +57,7 @@
         parcel->writeInt32(0);
     } else {
         parcel->writeInt32(1);
-        parcel->writeUtf8AsUtf16(mAttributes.tags);
+        parcel->writeUtf8AsUtf16(std::string(mAttributes.tags));
     }
     parcel->writeInt32(static_cast<int32_t>(mStreamType));
     parcel->writeUint32(static_cast<uint32_t>(mGroupId));
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 480930b..481becc 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -783,6 +783,13 @@
 
 // ---------------------------------------------------------------------------
 
+void AudioSystem::onNewAudioModulesAvailable()
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return;
+    aps->onNewAudioModulesAvailable();
+}
+
 status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                                audio_policy_dev_state_t state,
                                                const char *device_address,
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 3f8b52b..53d46f1 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -1361,10 +1361,14 @@
         }
         case GET_EFFECT_DESCRIPTOR: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            effect_uuid_t uuid;
-            data.read(&uuid, sizeof(effect_uuid_t));
-            effect_uuid_t type;
-            data.read(&type, sizeof(effect_uuid_t));
+            effect_uuid_t uuid = {};
+            if (data.read(&uuid, sizeof(effect_uuid_t)) != NO_ERROR) {
+                android_errorWriteLog(0x534e4554, "139417189");
+            }
+            effect_uuid_t type = {};
+            if (data.read(&type, sizeof(effect_uuid_t)) != NO_ERROR) {
+                android_errorWriteLog(0x534e4554, "139417189");
+            }
             uint32_t preferredTypeFlag = data.readUint32();
             effect_descriptor_t desc = {};
             status_t status = getEffectDescriptor(&uuid, &type, preferredTypeFlag, &desc);
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 0facaf8..24d7c92 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -108,6 +108,7 @@
     SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
     REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
     GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+    AUDIO_MODULES_UPDATED,  // oneway
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -1336,6 +1337,13 @@
         }
         return static_cast<status_t>(reply.readInt32());
     }
+
+    virtual void onNewAudioModulesAvailable()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        remote()->transact(AUDIO_MODULES_UPDATED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1401,7 +1409,8 @@
         case SET_RTT_ENABLED:
         case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
         case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
-        case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+        case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
+        case AUDIO_MODULES_UPDATED: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -2458,6 +2467,12 @@
             return NO_ERROR;
         }
 
+        case AUDIO_MODULES_UPDATED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            onNewAudioModulesAvailable();
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index a86297d..925bc89 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -211,6 +211,7 @@
     //
     // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
     //
+    static void onNewAudioModulesAvailable();
     static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
                                              const char *device_address, const char *device_name,
                                              audio_format_t encodedFormat);
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 9b91d6d..3edac33 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -42,6 +42,7 @@
     //
     // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
     //
+    virtual void onNewAudioModulesAvailable() = 0;
     virtual status_t setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address,
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index 8dcc421..93bc4d9 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -12,7 +12,7 @@
     ],
 }
 
-cc_library_shared {
+cc_library {
     name: "libaudiofoundation",
     vendor_available: true,
     double_loadable: true,
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index e6e9688..1c0eacb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -15,12 +15,13 @@
  */
 
 #include <string.h>
-#include <vector>
+#include <set>
 
 #define LOG_TAG "DevicesFactoryHalHidl"
 //#define LOG_NDEBUG 0
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.0/IServiceNotification.h>
 #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
 #include <media/audiohal/hidl/HalDeathHandler.h>
 #include <utils/Log.h>
@@ -29,33 +30,57 @@
 #include "DeviceHalHidl.h"
 #include "DevicesFactoryHalHidl.h"
 
-#include <set>
-
 using ::android::hardware::audio::CPP_VERSION::IDevice;
 using ::android::hardware::audio::CPP_VERSION::Result;
 using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
 
 namespace android {
 namespace CPP_VERSION {
 
-DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
-    ALOG_ASSERT(devicesFactory != nullptr, "Provided IDevicesFactory service is NULL");
+class ServiceNotificationListener : public IServiceNotification {
+  public:
+    explicit ServiceNotificationListener(sp<DevicesFactoryHalHidl> factory)
+            : mFactory(factory) {}
 
-    mDeviceFactories.push_back(devicesFactory);
-    if (MAJOR_VERSION >= 4) {
-        // The MSD factory is optional and only available starting at HAL 4.0
-        sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
-        if (msdFactory) {
-            mDeviceFactories.push_back(msdFactory);
+    Return<void> onRegistration(const hidl_string& /*fully_qualified_name*/,
+            const hidl_string& instance_name,
+            bool /*pre_existing*/) override {
+        if (static_cast<std::string>(instance_name) == "default") return Void();
+        sp<DevicesFactoryHalHidl> factory = mFactory.promote();
+        if (!factory) return Void();
+        sp<IDevicesFactory> halFactory = IDevicesFactory::getService(instance_name);
+        if (halFactory) {
+            factory->addDeviceFactory(halFactory, true /*needToNotify*/);
         }
+        return Void();
     }
-    for (const auto& factory : mDeviceFactories) {
-        // It is assumed that the DevicesFactoryHalInterface instance is owned
-        // by AudioFlinger and thus have the same lifespan.
-        factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
-    }
+
+  private:
+    wp<DevicesFactoryHalHidl> mFactory;
+};
+
+DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
+    ALOG_ASSERT(devicesFactory != nullptr, "Provided default IDevicesFactory service is NULL");
+    addDeviceFactory(devicesFactory, false /*needToNotify*/);
 }
 
+void DevicesFactoryHalHidl::onFirstRef() {
+    sp<IServiceManager> sm = IServiceManager::getService();
+    ALOG_ASSERT(sm != nullptr, "Hardware service manager is not running");
+    sp<ServiceNotificationListener> listener = new ServiceNotificationListener(this);
+    Return<bool> result = sm->registerForNotifications(
+            IDevicesFactory::descriptor, "", listener);
+    if (result.isOk()) {
+        ALOGE_IF(!static_cast<bool>(result),
+                "Hardware service manager refused to register listener");
+    } else {
+        ALOGE("Failed to register for hardware service manager notifications: %s",
+                result.description().c_str());
+    }
+}
 
 #if MAJOR_VERSION == 2
 static IDevicesFactory::Device idFromHal(const char *name, status_t* status) {
@@ -83,12 +108,13 @@
 #endif
 
 status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
-    if (mDeviceFactories.empty()) return NO_INIT;
+    auto factories = copyDeviceFactories();
+    if (factories.empty()) return NO_INIT;
     status_t status;
     auto hidlId = idFromHal(name, &status);
     if (status != OK) return status;
     Result retval = Result::NOT_INITIALIZED;
-    for (const auto& factory : mDeviceFactories) {
+    for (const auto& factory : factories) {
         Return<void> ret = factory->openDevice(
                 hidlId,
                 [&](Result r, const sp<IDevice>& result) {
@@ -113,10 +139,9 @@
 
 status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
     std::set<pid_t> pidsSet;
-
-    for (const auto& factory : mDeviceFactories) {
+    auto factories = copyDeviceFactories();
+    for (const auto& factory : factories) {
         using ::android::hidl::base::V1_0::DebugInfo;
-        using android::hidl::manager::V1_0::IServiceManager;
 
         DebugInfo debugInfo;
         auto ret = factory->getDebugInfo([&] (const auto &info) {
@@ -135,5 +160,48 @@
     return NO_ERROR;
 }
 
+status_t DevicesFactoryHalHidl::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+    ALOG_ASSERT(callback != nullptr);
+    bool needToCallCallback = false;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mCallback.unsafe_get()) return INVALID_OPERATION;
+        mCallback = callback;
+        if (mHaveUndeliveredNotifications) {
+            needToCallCallback = true;
+            mHaveUndeliveredNotifications = false;
+        }
+    }
+    if (needToCallCallback) {
+        callback->onNewDevicesAvailable();
+    }
+    return NO_ERROR;
+}
+
+void DevicesFactoryHalHidl::addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify) {
+    // It is assumed that the DevicesFactoryHalInterface instance is owned
+    // by AudioFlinger and thus have the same lifespan.
+    factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+    sp<DevicesFactoryHalCallback> callback;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        mDeviceFactories.push_back(factory);
+        if (needToNotify) {
+            callback = mCallback.promote();
+            if (!callback) {
+                mHaveUndeliveredNotifications = true;
+            }
+        }
+    }
+    if (callback) {
+        callback->onNewDevicesAvailable();
+    }
+}
+
+std::vector<sp<IDevicesFactory>> DevicesFactoryHalHidl::copyDeviceFactories() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return mDeviceFactories;
+}
+
 } // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 52185c8..6f84efe 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
 #define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
 
+#include <mutex>
+#include <vector>
+
 #include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
 #include <media/audiohal/DevicesFactoryHalInterface.h>
 #include <utils/Errors.h>
@@ -32,16 +35,26 @@
 class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
 {
   public:
-    DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+    explicit DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+    void onFirstRef() override;
 
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
-    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+    status_t openDevice(const char *name, sp<DeviceHalInterface> *device) override;
 
-            status_t getHalPids(std::vector<pid_t> *pids) override;
+    status_t getHalPids(std::vector<pid_t> *pids) override;
+
+    status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
 
   private:
-    std::vector<sp<IDevicesFactory>> mDeviceFactories;
+    friend class ServiceNotificationListener;
+    void addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify);
+    std::vector<sp<IDevicesFactory>> copyDeviceFactories();
+
+    std::mutex mLock;
+    std::vector<sp<IDevicesFactory>> mDeviceFactories;  // GUARDED_BY(mLock)
+    wp<DevicesFactoryHalCallback> mCallback;  // GUARDED_BY(mLock)
+    bool mHaveUndeliveredNotifications = false;  // GUARDED_BY(mLock)
 
     virtual ~DevicesFactoryHalHidl() = default;
 };
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index 52f150a..cde8d85 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -44,6 +44,13 @@
     return INVALID_OPERATION;
 }
 
+status_t DevicesFactoryHalHybrid::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+    if (mHidlFactory) {
+        return mHidlFactory->setCallbackOnce(callback);
+    }
+    return INVALID_OPERATION;
+}
+
 } // namespace CPP_VERSION
 
 extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 2189b36..568a1fb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -38,6 +38,8 @@
 
             status_t getHalPids(std::vector<pid_t> *pids) override;
 
+            status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
+
   private:
     sp<DevicesFactoryHalInterface> mLocalFactory;
     sp<DevicesFactoryHalInterface> mHidlFactory;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
index 2b011f4..32bf362 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -37,6 +37,10 @@
                 return INVALID_OPERATION;
             }
 
+            status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback __unused) override {
+                return INVALID_OPERATION;
+            }
+
   private:
     friend class DevicesFactoryHalHybrid;
 
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index e9ac1ce..5091558 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -24,6 +24,12 @@
 
 namespace android {
 
+class DevicesFactoryHalCallback : public RefBase
+{
+  public:
+    virtual void onNewDevicesAvailable() = 0;
+};
+
 class DevicesFactoryHalInterface : public RefBase
 {
   public:
@@ -33,6 +39,10 @@
 
     virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
 
+    // Sets a DevicesFactoryHalCallback to notify the client.
+    // The callback can be only set once.
+    virtual status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) = 0;
+
     static sp<DevicesFactoryHalInterface> create();
 
   protected:
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index afdcd37..f21d2b3 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -130,29 +130,32 @@
         } else if (n < 0) {
             break;
         } else {
-            if (buffer[0] == 0x00) {
+            if (buffer[0] == 0x00) { // OK to access buffer[0] since n must be > 0 here
                 // XXX legacy
 
                 if (extra == NULL) {
                     extra = new AMessage;
                 }
 
-                uint8_t type = buffer[1];
+                uint8_t type = 0;
+                if (n > 1) {
+                    type = buffer[1];
 
-                if (type & 2) {
-                    int64_t mediaTimeUs;
-                    memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
+                    if ((type & 2) && (n >= 2 + sizeof(int64_t))) {
+                        int64_t mediaTimeUs;
+                        memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
 
-                    extra->setInt64(kATSParserKeyMediaTimeUs, mediaTimeUs);
+                        extra->setInt64(kATSParserKeyMediaTimeUs, mediaTimeUs);
+                    }
                 }
 
                 mTSParser->signalDiscontinuity(
                         ((type & 1) == 0)
-                            ? ATSParser::DISCONTINUITY_TIME
-                            : ATSParser::DISCONTINUITY_FORMATCHANGE,
+                                ? ATSParser::DISCONTINUITY_TIME
+                                : ATSParser::DISCONTINUITY_FORMATCHANGE,
                         extra);
             } else {
-                status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
+                status_t err = mTSParser->feedTSPacket(buffer, n);
 
                 if (err != OK) {
                     ALOGE("TS Parser returned error %d", err);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cfefe11..eacaea8 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6902,7 +6902,7 @@
         }
     }
 
-    if (mCodec->mMaxPtsGapUs != 0LL) {
+    if (mCodec->mIsVideo && mCodec->mMaxPtsGapUs != 0LL) {
         OMX_PARAM_U32TYPE maxPtsGapParams;
         InitOMXParams(&maxPtsGapParams);
         maxPtsGapParams.nPortIndex = kPortIndexInput;
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index ea8b073..bcf63d5 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,6 +1,7 @@
 cc_library {
     name: "libstagefright_amrnb_common",
     vendor_available: true,
+    host_supported: true,
 
     srcs: [
         "src/add.cpp",
@@ -73,6 +74,12 @@
         "-Werror",
     ],
 
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
     //addressing b/25409744
     //sanitize: {
     //    misc_undefined: [
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index e18117e..3381d2e 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -1,6 +1,7 @@
 cc_library_static {
     name: "libstagefright_amrnbdec",
     vendor_available: true,
+    host_supported: true,
 
     srcs: [
         "src/a_refl.cpp",
@@ -61,6 +62,12 @@
         "libstagefright_amrnb_common",
         "liblog",
     ],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 //###############################################################################
@@ -100,6 +107,7 @@
 cc_test {
     name: "libstagefright_amrnbdec_test",
     gtest: false,
+    host_supported: true,
 
     srcs: ["test/amrnbdec_test.cpp"],
 
@@ -118,6 +126,12 @@
         "liblog",
     ],
 
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
     //sanitize: {
     //    misc_undefined: [
     //        "signed-integer-overflow",
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/Android.bp b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
new file mode 100644
index 0000000..54de1cc
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+    name: "amrnb_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "amrnb_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_amrnbdec",
+        "libstagefright_amrnb_common",
+        "liblog",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/README.md b/media/libstagefright/codecs/amrnb/fuzzer/README.md
new file mode 100644
index 0000000..7791b83
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/README.md
@@ -0,0 +1,62 @@
+# Fuzzer for libstagefright_amrnbdec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-NB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-NB supports the following parameters:
+1. Stream format (parameter name: `input_format`)
+2. 3GPP frame type (parameter name: `frame_type`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `input_format` | 0. `MIME_IETF` 1. `IF2` | Bit 0 (LSB) of 1st byte of data. |
+| `frame_type`   | 0. `AMR_475` 1. `AMR_515` 2. `AMR_59` 3. `AMR_67`  4. `AMR_74` 5. `AMR_795` 6. `AMR_102` 7. `AMR_122`  | Bits 3, 4 and 5 of 1st byte of data. |
+
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the decode operation was successful, the input is advanced by the frame size
+which is based on `input_format` and `frame_type` selected.
+If the decode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrnb_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) amrnb_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some amrnb files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
new file mode 100644
index 0000000..d4e7e5c
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <string.h>
+#include <algorithm>
+#include "gsmamr_dec.h"
+
+// Constants for AMR-NB
+constexpr int32_t kSamplesPerFrame = L_FRAME;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const bitstream_format kBitStreamFormats[2] = {MIME_IETF, IF2};
+const int32_t kLocalWmfDecBytesPerFrame[8] = {12, 13, 15, 17, 19, 20, 26, 31};
+const int32_t kLocalIf2DecBytesPerFrame[8] = {13, 14, 16, 18, 19, 21, 26, 31};
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() { deInitDecoder(); }
+  int16_t initDecoder();
+  void deInitDecoder();
+  void decodeFrames(const uint8_t *data, size_t size);
+
+ private:
+  void *mAmrHandle = nullptr;
+};
+
+int16_t Codec::initDecoder() { return GSMInitDecode(&mAmrHandle, (Word8 *)"AMRNBDecoder"); }
+
+void Codec::deInitDecoder() { GSMDecodeFrameExit(&mAmrHandle); }
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+  while (size > 0) {
+    uint8_t mode = *data;
+    bool bit = mode & 0x01;
+    bitstream_format bitsreamFormat = kBitStreamFormats[bit];
+    int32_t frameSize = 0;
+    /* Find frame type */
+    Frame_Type_3GPP frameType = static_cast<Frame_Type_3GPP>((mode >> 3) & 0x07);
+    ++data;
+    --size;
+    if (bit) {
+      frameSize = kLocalIf2DecBytesPerFrame[frameType];
+    } else {
+      frameSize = kLocalWmfDecBytesPerFrame[frameType];
+    }
+    int16_t outputBuf[kOutputBufferSize];
+    uint8_t *inputBuf = new uint8_t[frameSize];
+    if (!inputBuf) {
+      return;
+    }
+    int32_t minSize = std::min((int32_t)size, frameSize);
+    memcpy(inputBuf, data, minSize);
+    AMRDecode(mAmrHandle, frameType, inputBuf, outputBuf, bitsreamFormat);
+    /* AMRDecode() decodes minSize number of bytes if decode is successful.
+     * AMRDecode() returns -1 if decode fails.
+     * Even if no bytes are decoded, increment by minSize to ensure fuzzer proceeds
+     * to feed next data */
+    data += minSize;
+    size -= minSize;
+    delete[] inputBuf;
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 2) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder() == 0) {
+    codec->decodeFrames(data, size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index 88cf7f2..d8cb568 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -1,6 +1,7 @@
 cc_library_static {
     name: "libstagefright_amrwbdec",
     vendor_available: true,
+    host_supported: true,
 
     srcs: [
         "src/agc2_amr_wb.cpp",
@@ -44,8 +45,6 @@
         "src/weight_amrwb_lpc.cpp",
     ],
 
-    header_libs: ["libstagefright_headers"],
-
     export_include_dirs: [
         "src",
         "include",
@@ -63,12 +62,19 @@
             "signed-integer-overflow",
         ],
     },
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 //###############################################################################
 cc_test {
     name: "libstagefright_amrwbdec_test",
     gtest: false,
+    host_supported: true,
 
     srcs: ["test/amrwbdec_test.cpp"],
 
@@ -88,4 +94,10 @@
             "signed-integer-overflow",
         ],
     },
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
diff --git a/media/libstagefright/codecs/amrwb/fuzzer/Android.bp b/media/libstagefright/codecs/amrwb/fuzzer/Android.bp
new file mode 100644
index 0000000..46f77e3
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/fuzzer/Android.bp
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+    name: "amrwb_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "amrwb_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_amrwbdec",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/amrwb/fuzzer/README.md b/media/libstagefright/codecs/amrwb/fuzzer/README.md
new file mode 100644
index 0000000..de45784
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/fuzzer/README.md
@@ -0,0 +1,61 @@
+# Fuzzer for libstagefright_amrwbdec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-WB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-WB supports the following parameters:
+1. Quality (parameter name: `quality`)
+2. Mode (parameter name: `mode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `quality` | 0. `Bad Quality` 1. `Good quality` | Bit 0 (LSB) of 1st byte of data. |
+| `mode`   | 0. `MODE_7k` 1. `MODE_9k` 2. `MODE_12k` 3. `MODE_14k`  4. `MODE_16k ` 5. `MODE_18k` 6. `MODE_20k` 7. `MODE_23k` 8. `MODE_24k` 9. `MRDTX`  | Bits 3, 4, 5 and 6 of 1st byte of data. |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the decode operation was successful, the input is advanced by the frame size
+which is based on `mode` and `quality` selected.
+If the decode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrwb_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) amrwb_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some amrwb files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/amrwb_dec_fuzzer/amrwb_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/amrwb_dec_fuzzer/amrwb_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrwb/fuzzer/amrwb_dec_fuzzer.cpp b/media/libstagefright/codecs/amrwb/fuzzer/amrwb_dec_fuzzer.cpp
new file mode 100644
index 0000000..6dc0270
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/fuzzer/amrwb_dec_fuzzer.cpp
@@ -0,0 +1,110 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <malloc.h>
+#include <string.h>
+#include <algorithm>
+#include "pvamrwbdecoder.h"
+#include "pvamrwbdecoder_api.h"
+
+// Constants for AMR-WB.
+constexpr int32_t kSamplesPerFrame = 320;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kMaxSourceDataUnitSize = KAMRWB_NB_BITS_MAX * sizeof(int16_t);
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+constexpr int32_t kFrameSizes[16] = {17, 23, 32, 36, 40, 46, 50, 58,
+                                     60, 17, 23, 32, 36, 40, 46, 50};
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() { deInitDecoder(); }
+  bool initDecoder();
+  void decodeFrames(const uint8_t *data, size_t size);
+  void deInitDecoder();
+
+ private:
+  void *mAmrHandle = nullptr;
+  int16_t *mDecoderCookie = nullptr;
+  void *mDecoderBuffer = nullptr;
+};
+
+bool Codec::initDecoder() {
+  mDecoderBuffer = malloc(pvDecoder_AmrWbMemRequirements());
+  if (mDecoderBuffer) {
+    pvDecoder_AmrWb_Init(&mAmrHandle, mDecoderBuffer, &mDecoderCookie);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void Codec::deInitDecoder() {
+  if (mDecoderBuffer) {
+    free(mDecoderBuffer);
+    mDecoderBuffer = nullptr;
+  }
+  mAmrHandle = nullptr;
+  mDecoderCookie = nullptr;
+}
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+  while (size > 0) {
+    uint8_t modeByte = *data;
+    bool quality = modeByte & 0x01;
+    int16 mode = ((modeByte >> 3) & 0x0f);
+    ++data;
+    --size;
+    int32_t frameSize = kFrameSizes[mode];
+    int16_t inputSampleBuf[kMaxSourceDataUnitSize];
+    uint8_t *inputBuf = new uint8_t[frameSize];
+    if (!inputBuf) {
+      return;
+    }
+    int32_t minSize = std::min((int32_t)size, frameSize);
+    memcpy(inputBuf, data, minSize);
+    int16 frameMode = mode;
+    int16 frameType;
+    RX_State_wb rx_state;
+    mime_unsorting(inputBuf, inputSampleBuf, &frameType, &frameMode, quality, &rx_state);
+
+    int16_t numSamplesOutput;
+    int16_t outputBuf[kOutputBufferSize];
+    pvDecoder_AmrWb(frameMode, inputSampleBuf, outputBuf, &numSamplesOutput, mDecoderBuffer,
+                    frameType, mDecoderCookie);
+    data += minSize;
+    size -= minSize;
+    delete[] inputBuf;
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 2) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder()) {
+    codec->decodeFrames(data, size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 513e41f..42ac026 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -126,12 +126,20 @@
     }
     header->num_streams = data[kOpusHeaderNumStreamsOffset];
     header->num_coupled = data[kOpusHeaderNumCoupledStreamsOffset];
-    if (header->num_streams + header->num_coupled != header->channels) {
-        ALOGV("Inconsistent channel mapping.");
+    if (header->num_coupled > header->num_streams ||
+        header->num_streams + header->num_coupled != header->channels) {
+        ALOGV("Inconsistent channel mapping, streams: %d coupled: %d channels: %d",
+        header->num_streams, header->num_coupled, header->channels);
         return false;
     }
-    for (int i = 0; i < header->channels; ++i)
-        header->stream_map[i] = data[kOpusHeaderStreamMapOffset + i];
+    for (int i = 0; i < header->channels; ++i) {
+        uint8_t value = data[kOpusHeaderStreamMapOffset + i];
+        if (value != 255 && value >= header->channels) {
+            ALOGV("Invalid channel mapping for index %i : %d", i, value);
+            return false;
+        }
+        header->stream_map[i] = value;
+    }
     return true;
 }
 
diff --git a/media/libstagefright/foundation/TEST_MAPPING b/media/libstagefright/foundation/TEST_MAPPING
new file mode 100644
index 0000000..3301c4b
--- /dev/null
+++ b/media/libstagefright/foundation/TEST_MAPPING
@@ -0,0 +1,5 @@
+{
+  "presubmit": [
+    { "name": "sf_foundation_test" }
+  ]
+}
diff --git a/media/libstagefright/foundation/tests/Android.bp b/media/libstagefright/foundation/tests/Android.bp
new file mode 100644
index 0000000..f2157c9
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Android.bp
@@ -0,0 +1,27 @@
+cc_test {
+    name: "sf_foundation_test",
+    test_suites: ["device-tests"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    include_dirs: [
+        "frameworks/av/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    srcs: [
+        "AData_test.cpp",
+        "Base64_test.cpp",
+        "Flagged_test.cpp",
+        "TypeTraits_test.cpp",
+        "Utils_test.cpp",
+    ],
+}
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
deleted file mode 100644
index a9e3c76..0000000
--- a/media/libstagefright/foundation/tests/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := sf_foundation_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	AData_test.cpp \
-	Base64_test.cpp \
-	Flagged_test.cpp \
-	TypeTraits_test.cpp \
-	Utils_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libstagefright_foundation \
-	libutils \
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/libstagefright/foundation/tests/OpusHeader/Android.bp b/media/libstagefright/foundation/tests/OpusHeader/Android.bp
new file mode 100644
index 0000000..c1251a8
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "OpusHeaderTest",
+    gtest: true,
+
+    srcs: [
+        "OpusHeaderTest.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_foundation",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libstagefright/foundation/tests/OpusHeader/AndroidTest.xml b/media/libstagefright/foundation/tests/OpusHeader/AndroidTest.xml
new file mode 100644
index 0000000..afee16a
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for opus header unit tests">
+    <option name="test-suite-tag" value="OpusHeaderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="OpusHeaderTest->/data/local/tmp/OpusHeaderTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/OpusHeader/OpusHeader.zip?unzip=true"
+            value="/data/local/tmp/OpusHeaderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="OpusHeaderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/OpusHeaderTestRes/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTest.cpp b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTest.cpp
new file mode 100644
index 0000000..d142781
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTest.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "OpusHeaderTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <stdio.h>
+#include <string.h>
+
+#include <media/stagefright/foundation/OpusHeader.h>
+
+#include "OpusHeaderTestEnvironment.h"
+
+using namespace android;
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/OpusOutput"
+
+// Opus in WebM is a well-known, yet under-documented, format. The codec private data
+// of the track is an Opus Ogg header (https://tools.ietf.org/html/rfc7845#section-5.1)
+// channel mapping offset in opus header
+constexpr size_t kOpusHeaderStreamMapOffset = 21;
+constexpr size_t kMaxOpusHeaderSize = 100;
+// AOPUSHDR + AOPUSHDRLength +
+// (8 + 8 ) +
+// Header(csd) + num_streams + num_coupled + 1
+// (19 + 1 + 1 + 1) +
+// AOPUSDLY + AOPUSDLYLength + DELAY + AOPUSPRL + AOPUSPRLLength + PRL
+// (8 + 8 + 8 + 8 + 8 + 8)
+// = 86
+constexpr size_t kOpusHeaderChannelMapOffset = 86;
+constexpr uint32_t kOpusSampleRate = 48000;
+constexpr uint64_t kOpusSeekPrerollNs = 80000000;
+constexpr int64_t kNsecPerSec = 1000000000ll;
+
+// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
+// mappings for up to 8 channels. This information is part of the Vorbis I
+// Specification:
+// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
+constexpr int kMaxChannels = 8;
+constexpr uint8_t kOpusChannelMap[kMaxChannels][kMaxChannels] = {
+        {0},
+        {0, 1},
+        {0, 2, 1},
+        {0, 1, 2, 3},
+        {0, 4, 1, 2, 3},
+        {0, 4, 1, 2, 3, 5},
+        {0, 4, 1, 2, 3, 5, 6},
+        {0, 6, 1, 2, 3, 4, 5, 7},
+};
+
+static OpusHeaderTestEnvironment *gEnv = nullptr;
+
+class OpusHeaderTest {
+  public:
+    OpusHeaderTest() : mInputBuffer(nullptr) {}
+
+    ~OpusHeaderTest() {
+        if (mEleStream.is_open()) mEleStream.close();
+        if (mInputBuffer) {
+            free(mInputBuffer);
+            mInputBuffer = nullptr;
+        }
+    }
+    ifstream mEleStream;
+    uint8_t *mInputBuffer;
+};
+
+class OpusHeaderParseTest : public OpusHeaderTest,
+                            public ::testing::TestWithParam<
+                                    tuple<string /* InputFileName */, int32_t /* ChannelCount */,
+                                          bool /* isHeaderValid */, bool /* isCodecDelayValid */,
+                                          bool /* isSeekPreRollValid */, bool /* isInputValid */>> {
+};
+
+class OpusHeaderWriteTest
+    : public OpusHeaderTest,
+      public ::testing::TestWithParam<pair<int32_t /* ChannelCount */, int32_t /* skipSamples */>> {
+};
+
+TEST_P(OpusHeaderWriteTest, WriteTest) {
+    OpusHeader writtenHeader;
+    memset(&writtenHeader, 0, sizeof(writtenHeader));
+    int32_t channels = GetParam().first;
+    writtenHeader.channels = channels;
+    writtenHeader.num_streams = channels;
+    writtenHeader.channel_mapping = ((channels > 8) ? 255 : (channels > 2));
+    int32_t skipSamples = GetParam().second;
+    writtenHeader.skip_samples = skipSamples;
+    uint64_t codecDelayNs = skipSamples * kNsecPerSec / kOpusSampleRate;
+    uint8_t headerData[kMaxOpusHeaderSize];
+    int32_t headerSize = WriteOpusHeaders(writtenHeader, kOpusSampleRate, headerData,
+                                          sizeof(headerData), codecDelayNs, kOpusSeekPrerollNs);
+    ASSERT_GT(headerSize, 0) << "failed to generate Opus header";
+    ASSERT_LE(headerSize, kMaxOpusHeaderSize)
+            << "Invalid header written. Header size can't exceed kMaxOpusHeaderSize";
+
+    ofstream ostrm;
+    ostrm.open(OUTPUT_FILE_NAME, ofstream::binary);
+    ASSERT_TRUE(ostrm.is_open()) << "Failed to open output file " << OUTPUT_FILE_NAME;
+
+    // TODO : Validate bitstream (b/150116402)
+    ostrm.write(reinterpret_cast<char *>(headerData), sizeof(headerData));
+    ostrm.close();
+
+    size_t opusHeadSize = 0;
+    size_t codecDelayBufSize = 0;
+    size_t seekPreRollBufSize = 0;
+    void *opusHeadBuf = nullptr;
+    void *codecDelayBuf = nullptr;
+    void *seekPreRollBuf = nullptr;
+    bool status = GetOpusHeaderBuffers(headerData, headerSize, &opusHeadBuf, &opusHeadSize,
+                                       &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+                                       &seekPreRollBufSize);
+    ASSERT_TRUE(status) << "Encountered error in GetOpusHeaderBuffers";
+
+    uint64_t value = *((uint64_t *)codecDelayBuf);
+    ASSERT_EQ(value, codecDelayNs);
+
+    value = *((uint64_t *)seekPreRollBuf);
+    ASSERT_EQ(value, kOpusSeekPrerollNs);
+
+    OpusHeader parsedHeader;
+    status = ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &parsedHeader);
+    ASSERT_TRUE(status) << "Encountered error while Parsing Opus Header.";
+
+    ASSERT_EQ(writtenHeader.channels, parsedHeader.channels)
+            << "Invalid header generated. Mismatch between channel counts";
+
+    ASSERT_EQ(writtenHeader.skip_samples, parsedHeader.skip_samples)
+            << "Mismatch between no of skipSamples written "
+               "and no of skipSamples got after parsing";
+
+    ASSERT_EQ(writtenHeader.channel_mapping, parsedHeader.channel_mapping)
+            << "Mismatch between channelMapping written "
+               "and channelMapping got after parsing";
+
+    if (parsedHeader.channel_mapping) {
+        ASSERT_GT(parsedHeader.channels, 2);
+        ASSERT_EQ(writtenHeader.num_streams, parsedHeader.num_streams)
+                << "Invalid header generated. Mismatch between channel counts";
+
+        ASSERT_EQ(writtenHeader.num_coupled, parsedHeader.num_coupled)
+                << "Invalid header generated. Mismatch between channel counts";
+
+        ASSERT_EQ(parsedHeader.num_coupled + parsedHeader.num_streams, parsedHeader.channels);
+
+        ASSERT_LE(parsedHeader.num_coupled, parsedHeader.num_streams)
+                << "Invalid header generated. Number of coupled streams cannot be greater than "
+                   "number "
+                   "of streams.";
+
+        ASSERT_EQ(headerSize, kOpusHeaderChannelMapOffset + writtenHeader.channels)
+                << "Invalid header written. Header size should be equal to 86 + "
+                   "writtenHeader.channels";
+
+        uint8_t mappedChannelNumber;
+        for (int32_t channelNumber = 0; channelNumber < channels; channelNumber++) {
+            mappedChannelNumber = *(reinterpret_cast<uint8_t *>(opusHeadBuf) +
+                                    kOpusHeaderStreamMapOffset + channelNumber);
+            ASSERT_LT(mappedChannelNumber, channels) << "Invalid header generated. Channel mapping "
+                                                        "cannot be greater than channel count.";
+
+            ASSERT_EQ(mappedChannelNumber, kOpusChannelMap[channels - 1][channelNumber])
+                    << "Invalid header generated. Channel mapping is not as per specification.";
+        }
+    } else {
+        ASSERT_LE(parsedHeader.channels, 2);
+    }
+}
+
+TEST_P(OpusHeaderParseTest, ParseTest) {
+    tuple<string, int32_t, bool, bool, bool, bool> params = GetParam();
+    string inputFileName = gEnv->getRes() + get<0>(params);
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << get<0>(params);
+    bool isHeaderValid = get<2>(params);
+    bool isCodecDelayValid = get<3>(params);
+    bool isSeekPreRollValid = get<4>(params);
+    bool isInputValid = get<5>(params);
+
+    struct stat buf;
+    stat(inputFileName.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    mInputBuffer = (uint8_t *)malloc(fileSize);
+    ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory. Malloc failed for size " << fileSize;
+
+    mEleStream.read(reinterpret_cast<char *>(mInputBuffer), fileSize);
+    ASSERT_EQ(mEleStream.gcount(), fileSize) << "mEleStream.gcount() != bytesCount";
+
+    OpusHeader header;
+    size_t opusHeadSize = 0;
+    size_t codecDelayBufSize = 0;
+    size_t seekPreRollBufSize = 0;
+    void *opusHeadBuf = nullptr;
+    void *codecDelayBuf = nullptr;
+    void *seekPreRollBuf = nullptr;
+    bool status = GetOpusHeaderBuffers(mInputBuffer, fileSize, &opusHeadBuf, &opusHeadSize,
+                                       &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+                                       &seekPreRollBufSize);
+    if (!isHeaderValid) {
+        ASSERT_EQ(opusHeadBuf, nullptr);
+    } else {
+        ASSERT_NE(opusHeadBuf, nullptr);
+    }
+    if (!isCodecDelayValid) {
+        ASSERT_EQ(codecDelayBuf, nullptr);
+    } else {
+        ASSERT_NE(codecDelayBuf, nullptr);
+    }
+    if (!isSeekPreRollValid) {
+        ASSERT_EQ(seekPreRollBuf, nullptr);
+    } else {
+        ASSERT_NE(seekPreRollBuf, nullptr);
+    }
+    if (!status) {
+        ASSERT_FALSE(isInputValid) << "GetOpusHeaderBuffers failed";
+        return;
+    }
+
+    status = ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &header);
+
+    if (status) {
+        ASSERT_TRUE(isInputValid) << "Parse opus header didn't fail for invalid input";
+    } else {
+        ASSERT_FALSE(isInputValid);
+        return;
+    }
+
+    int32_t channels = get<1>(params);
+    ASSERT_EQ(header.channels, channels) << "Parser returned invalid channel count";
+    ASSERT_LE(header.channels, kMaxChannels);
+
+    ASSERT_LE(header.num_coupled, header.num_streams)
+            << "Invalid header generated. Number of coupled streams cannot be greater than number "
+               "of streams.";
+
+    ASSERT_EQ(header.num_coupled + header.num_streams, header.channels);
+
+    if (header.channel_mapping) {
+        uint8_t mappedChannelNumber;
+        for (int32_t channelNumber = 0; channelNumber < channels; channelNumber++) {
+            mappedChannelNumber = *(reinterpret_cast<uint8_t *>(opusHeadBuf) +
+                                    kOpusHeaderStreamMapOffset + channelNumber);
+            ASSERT_LT(mappedChannelNumber, channels)
+                    << "Invalid header. Channel mapping cannot be greater than channel count.";
+
+            ASSERT_EQ(mappedChannelNumber, kOpusChannelMap[channels - 1][channelNumber])
+                    << "Invalid header generated. Channel mapping "
+                       "is not as per specification.";
+        }
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(OpusHeaderTestAll, OpusHeaderWriteTest,
+                         ::testing::Values(make_pair(1, 312),
+                                           make_pair(2, 312),
+                                           make_pair(5, 312),
+                                           make_pair(6, 312),
+                                           make_pair(1, 0),
+                                           make_pair(2, 0),
+                                           make_pair(5, 0),
+                                           make_pair(6, 0),
+                                           make_pair(1, 624),
+                                           make_pair(2, 624),
+                                           make_pair(5, 624),
+                                           make_pair(6, 624)));
+
+INSTANTIATE_TEST_SUITE_P(
+        OpusHeaderTestAll, OpusHeaderParseTest,
+        ::testing::Values(
+                make_tuple("2ch_valid_size83B.opus", 2, true, true, true, true),
+                make_tuple("3ch_valid_size88B.opus", 3, true, true, true, true),
+                make_tuple("5ch_valid.opus", 5, true, false, false, true),
+                make_tuple("6ch_valid.opus", 6, true, false, false, true),
+                make_tuple("1ch_valid.opus", 1, true, false, false, true),
+                make_tuple("2ch_valid.opus", 2, true, false, false, true),
+                make_tuple("3ch_invalid_size.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_streams.opus", 3, true, true, true, false),
+                make_tuple("5ch_invalid_channelmapping.opus", 5, true, false, false, false),
+                make_tuple("5ch_invalid_coupledstreams.opus", 5, true, false, false, false),
+                make_tuple("6ch_invalid_channelmapping.opus", 6, true, false, false, false),
+                make_tuple("9ch_invalid_channels.opus", 9, true, true, true, false),
+                make_tuple("2ch_invalid_header.opus", 2, false, false, false, false),
+                make_tuple("2ch_invalid_headerlength_16.opus", 2, false, false, false, false),
+                make_tuple("2ch_invalid_headerlength_256.opus", 2, false, false, false, false),
+                make_tuple("2ch_invalid_size.opus", 2, false, false, false, false),
+                make_tuple("3ch_invalid_channelmapping_0.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_coupledstreams.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_headerlength.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_headerSize1.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_headerSize2.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_headerSize3.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_nodelay.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_nopreroll.opus", 3, false, false, false, false)));
+
+int main(int argc, char **argv) {
+    gEnv = new OpusHeaderTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGD("Opus Header Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTestEnvironment.h b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTestEnvironment.h
new file mode 100644
index 0000000..d0163c3
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OPUS_HEADER_TEST_ENVIRONMENT_H__
+#define __OPUS_HEADER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class OpusHeaderTestEnvironment : public ::testing::Environment {
+  public:
+    OpusHeaderTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int OpusHeaderTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P': {
+                setRes(optarg);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __OPUS_HEADER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/foundation/tests/OpusHeader/README.md b/media/libstagefright/foundation/tests/OpusHeader/README.md
new file mode 100644
index 0000000..860c827
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### Opus Header
+The OpusHeader Test Suite validates the OPUS header available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m OpusHeaderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/OpusHeaderTest/OpusHeaderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/OpusHeaderTest/OpusHeaderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/OpusHeader/OpusHeader.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push OpusHeader /data/local/tmp/
+```
+
+usage: OpusHeaderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/OpusHeaderTest -P /data/local/tmp/OpusHeader/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest OpusHeaderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index 409f141..ff063e3 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -243,6 +243,10 @@
     sp<MetaData> trackMeta = new MetaData;
     convertMessageToMetaData(format, trackMeta);
     mCurrentTrack = new MediaAdapter(trackMeta);
+    if (mCurrentTrack == nullptr) {
+        ALOGE("MediaAdapter returned nullptr");
+        return -1;
+    }
     status_t result = mWriter->addSource(mCurrentTrack);
     return result;
 }
@@ -301,7 +305,7 @@
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
 
-    getInputBufferInfo(inputFile, inputInfo);
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
     status = addWriterSource(isAudio, param);
     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
 
@@ -338,7 +342,7 @@
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
 
-    getInputBufferInfo(inputFile, inputInfo);
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
     status = addWriterSource(isAudio, param);
     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
 
@@ -397,7 +401,7 @@
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
 
-    getInputBufferInfo(inputFile, inputInfo);
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
     status = addWriterSource(isAudio, param);
     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 10a9c63..9e36f77 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -29,6 +29,7 @@
 #include <string>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <thread>
 
 #include <android/os/IExternalVibratorService.h>
 #include <binder/IPCThreadState.h>
@@ -143,6 +144,19 @@
     return sExternalVibratorService;
 }
 
+class DevicesFactoryHalCallbackImpl : public DevicesFactoryHalCallback {
+  public:
+    void onNewDevicesAvailable() override {
+        // Start a detached thread to execute notification in parallel.
+        // This is done to prevent mutual blocking of audio_flinger and
+        // audio_policy services during system initialization.
+        std::thread notifier([]() {
+            AudioSystem::onNewAudioModulesAvailable();
+        });
+        notifier.detach();
+    }
+};
+
 // ----------------------------------------------------------------------------
 
 std::string formatToString(audio_format_t format) {
@@ -221,6 +235,9 @@
     mMode = AUDIO_MODE_NORMAL;
 
     gAudioFlinger = this;
+
+    mDevicesFactoryHalCallback = new DevicesFactoryHalCallbackImpl;
+    mDevicesFactoryHal->setCallbackOnce(mDevicesFactoryHalCallback);
 }
 
 status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index a43a6dc..115bbb8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -103,6 +103,7 @@
 class AudioBuffer;
 class AudioResampler;
 class DeviceHalInterface;
+class DevicesFactoryHalCallback;
 class DevicesFactoryHalInterface;
 class EffectsFactoryHalInterface;
 class FastMixer;
@@ -827,6 +828,7 @@
                 DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;
 
                 sp<DevicesFactoryHalInterface> mDevicesFactoryHal;
+                sp<DevicesFactoryHalCallback> mDevicesFactoryHalCallback;
 
     // for dump, indicates which hardware operation is currently in progress (but not stream ops)
     enum hardware_call_state {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 1fe60d4..9676d09 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -75,6 +75,10 @@
     // configuration functions
     //
 
+    // Informs APM that new HAL modules are available. This typically happens
+    // due to registration of an audio HAL service.
+    virtual void onNewAudioModulesAvailable() = 0;
+
     // indicate a change in device connection status
     virtual status_t setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 56596f5..47c6e68 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -37,13 +37,13 @@
 {
 public:
     AudioPolicyConfig(HwModuleCollection &hwModules,
-                      DeviceVector &availableOutputDevices,
-                      DeviceVector &availableInputDevices,
+                      DeviceVector &outputDevices,
+                      DeviceVector &inputDevices,
                       sp<DeviceDescriptor> &defaultOutputDevice)
         : mEngineLibraryNameSuffix(kDefaultEngineLibraryNameSuffix),
           mHwModules(hwModules),
-          mAvailableOutputDevices(availableOutputDevices),
-          mAvailableInputDevices(availableInputDevices),
+          mOutputDevices(outputDevices),
+          mInputDevices(inputDevices),
           mDefaultOutputDevice(defaultOutputDevice),
           mIsSpeakerDrcEnabled(false)
     {}
@@ -69,23 +69,23 @@
         mHwModules = hwModules;
     }
 
-    void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
+    void addDevice(const sp<DeviceDescriptor> &device)
     {
-        if (audio_is_output_device(availableDevice->type())) {
-            mAvailableOutputDevices.add(availableDevice);
-        } else if (audio_is_input_device(availableDevice->type())) {
-            mAvailableInputDevices.add(availableDevice);
+        if (audio_is_output_device(device->type())) {
+            mOutputDevices.add(device);
+        } else if (audio_is_input_device(device->type())) {
+            mInputDevices.add(device);
         }
     }
 
-    void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+    void addInputDevices(const DeviceVector &inputDevices)
     {
-        mAvailableInputDevices.add(availableInputDevices);
+        mInputDevices.add(inputDevices);
     }
 
-    void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+    void addOutputDevices(const DeviceVector &outputDevices)
     {
-        mAvailableOutputDevices.add(availableOutputDevices);
+        mOutputDevices.add(outputDevices);
     }
 
     bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
@@ -97,14 +97,14 @@
 
     const HwModuleCollection getHwModules() const { return mHwModules; }
 
-    const DeviceVector &getAvailableInputDevices() const
+    const DeviceVector &getInputDevices() const
     {
-        return mAvailableInputDevices;
+        return mInputDevices;
     }
 
-    const DeviceVector &getAvailableOutputDevices() const
+    const DeviceVector &getOutputDevices() const
     {
-        return mAvailableOutputDevices;
+        return mOutputDevices;
     }
 
     void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
@@ -125,13 +125,11 @@
         sp<AudioProfile> micProfile = new AudioProfile(
                 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
         defaultInputDevice->addAudioProfile(micProfile);
-        mAvailableOutputDevices.add(mDefaultOutputDevice);
-        mAvailableInputDevices.add(defaultInputDevice);
+        mOutputDevices.add(mDefaultOutputDevice);
+        mInputDevices.add(defaultInputDevice);
 
         sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
         mHwModules.add(module);
-        mDefaultOutputDevice->attach(module);
-        defaultInputDevice->attach(module);
 
         sp<OutputProfile> outProfile = new OutputProfile("primary");
         outProfile->addAudioProfile(
@@ -182,8 +180,8 @@
     std::string mSource;
     std::string mEngineLibraryNameSuffix;
     HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
-    DeviceVector &mAvailableOutputDevices;
-    DeviceVector &mAvailableInputDevices;
+    DeviceVector &mOutputDevices;
+    DeviceVector &mInputDevices;
     sp<DeviceDescriptor> &mDefaultOutputDevice;
     // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
     // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index f0bb28e..b8e1cbd 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -652,7 +652,7 @@
                         sp<DeviceDescriptor> device = module->getDeclaredDevices().
                                 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
                                                         attachedDevice.get())));
-                        ctx->addAvailableDevice(device);
+                        ctx->addDevice(device);
                     }
                 }
             }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b747dd6..8de8ecd 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4340,7 +4340,7 @@
     mpClientInterface(clientInterface),
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
-    mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice),
+    mConfig(mHwModulesAll, mOutputDevicesAll, mInputDevicesAll, mDefaultOutputDevice),
     mAudioPortGeneration(1),
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
@@ -4385,141 +4385,9 @@
         return status;
     }
 
-    // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
+    // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
     // open all output streams needed to access attached devices
-    for (const auto& hwModule : mHwModulesAll) {
-        hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
-        if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
-            ALOGW("could not open HW module %s", hwModule->getName());
-            continue;
-        }
-        mHwModules.push_back(hwModule);
-        // open all output streams needed to access attached devices
-        // except for direct output streams that are only opened when they are actually
-        // required by an app.
-        // This also validates mAvailableOutputDevices list
-        for (const auto& outProfile : hwModule->getOutputProfiles()) {
-            if (!outProfile->canOpenNewIo()) {
-                ALOGE("Invalid Output profile max open count %u for profile %s",
-                      outProfile->maxOpenCount, outProfile->getTagName().c_str());
-                continue;
-            }
-            if (!outProfile->hasSupportedDevices()) {
-                ALOGW("Output profile contains no device on module %s", hwModule->getName());
-                continue;
-            }
-            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
-                mTtsOutputAvailable = true;
-            }
-
-            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
-                continue;
-            }
-            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
-            DeviceVector availProfileDevices = supportedDevices.filter(mAvailableOutputDevices);
-            sp<DeviceDescriptor> supportedDevice = 0;
-            if (supportedDevices.contains(mDefaultOutputDevice)) {
-                supportedDevice = mDefaultOutputDevice;
-            } else {
-                // choose first device present in profile's SupportedDevices also part of
-                // mAvailableOutputDevices.
-                if (availProfileDevices.isEmpty()) {
-                    continue;
-                }
-                supportedDevice = availProfileDevices.itemAt(0);
-            }
-            if (!mAvailableOutputDevices.contains(supportedDevice)) {
-                continue;
-            }
-            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
-                                                                                 mpClientInterface);
-            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-            status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
-                                               AUDIO_STREAM_DEFAULT,
-                                               AUDIO_OUTPUT_FLAG_NONE, &output);
-            if (status != NO_ERROR) {
-                ALOGW("Cannot open output stream for devices %s on hw module %s",
-                      supportedDevice->toString().c_str(), hwModule->getName());
-                continue;
-            }
-            for (const auto &device : availProfileDevices) {
-                // give a valid ID to an attached device once confirmed it is reachable
-                if (!device->isAttached()) {
-                    device->attach(hwModule);
-                }
-            }
-            if (mPrimaryOutput == 0 &&
-                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
-                mPrimaryOutput = outputDesc;
-            }
-            addOutput(output, outputDesc);
-            setOutputDevices(outputDesc,
-                             DeviceVector(supportedDevice),
-                             true,
-                             0,
-                             NULL);
-        }
-        // open input streams needed to access attached devices to validate
-        // mAvailableInputDevices list
-        for (const auto& inProfile : hwModule->getInputProfiles()) {
-            if (!inProfile->canOpenNewIo()) {
-                ALOGE("Invalid Input profile max open count %u for profile %s",
-                      inProfile->maxOpenCount, inProfile->getTagName().c_str());
-                continue;
-            }
-            if (!inProfile->hasSupportedDevices()) {
-                ALOGW("Input profile contains no device on module %s", hwModule->getName());
-                continue;
-            }
-            // chose first device present in profile's SupportedDevices also part of
-            // available input devices
-            const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
-            DeviceVector availProfileDevices = supportedDevices.filter(mAvailableInputDevices);
-            if (availProfileDevices.isEmpty()) {
-                ALOGE("%s: Input device list is empty!", __FUNCTION__);
-                continue;
-            }
-            sp<AudioInputDescriptor> inputDesc =
-                    new AudioInputDescriptor(inProfile, mpClientInterface);
-
-            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-            status_t status = inputDesc->open(nullptr,
-                                              availProfileDevices.itemAt(0),
-                                              AUDIO_SOURCE_MIC,
-                                              AUDIO_INPUT_FLAG_NONE,
-                                              &input);
-            if (status != NO_ERROR) {
-                ALOGW("Cannot open input stream for device %s on hw module %s",
-                      availProfileDevices.toString().c_str(),
-                      hwModule->getName());
-                continue;
-            }
-            for (const auto &device : availProfileDevices) {
-                // give a valid ID to an attached device once confirmed it is reachable
-                if (!device->isAttached()) {
-                    device->attach(hwModule);
-                    device->importAudioPortAndPickAudioProfile(inProfile, true);
-                }
-            }
-            inputDesc->close();
-        }
-    }
-    // make sure all attached devices have been allocated a unique ID
-    auto checkAndSetAvailable = [this](auto& devices) {
-        for (size_t i = 0; i < devices.size();) {
-            const auto &device = devices[i];
-            if (!device->isAttached()) {
-                ALOGW("device %s is unreachable", device->toString().c_str());
-                devices.remove(device);
-                continue;
-            }
-            // Device is now validated and can be appended to the available devices of the engine
-            setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-            i++;
-        }
-    };
-    checkAndSetAvailable(mAvailableOutputDevices);
-    checkAndSetAvailable(mAvailableInputDevices);
+    onNewAudioModulesAvailable();
 
     // make sure default device is reachable
     if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
@@ -4574,6 +4442,134 @@
 
 // ---
 
+void AudioPolicyManager::onNewAudioModulesAvailable()
+{
+    for (const auto& hwModule : mHwModulesAll) {
+        if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
+            continue;
+        }
+        hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
+        if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
+            ALOGW("could not open HW module %s", hwModule->getName());
+            continue;
+        }
+        mHwModules.push_back(hwModule);
+        // open all output streams needed to access attached devices
+        // except for direct output streams that are only opened when they are actually
+        // required by an app.
+        // This also validates mAvailableOutputDevices list
+        for (const auto& outProfile : hwModule->getOutputProfiles()) {
+            if (!outProfile->canOpenNewIo()) {
+                ALOGE("Invalid Output profile max open count %u for profile %s",
+                      outProfile->maxOpenCount, outProfile->getTagName().c_str());
+                continue;
+            }
+            if (!outProfile->hasSupportedDevices()) {
+                ALOGW("Output profile contains no device on module %s", hwModule->getName());
+                continue;
+            }
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+                mTtsOutputAvailable = true;
+            }
+
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+                continue;
+            }
+            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+            DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
+            sp<DeviceDescriptor> supportedDevice = 0;
+            if (supportedDevices.contains(mDefaultOutputDevice)) {
+                supportedDevice = mDefaultOutputDevice;
+            } else {
+                // choose first device present in profile's SupportedDevices also part of
+                // mAvailableOutputDevices.
+                if (availProfileDevices.isEmpty()) {
+                    continue;
+                }
+                supportedDevice = availProfileDevices.itemAt(0);
+            }
+            if (!mOutputDevicesAll.contains(supportedDevice)) {
+                continue;
+            }
+            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
+                                                                                 mpClientInterface);
+            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+            status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
+                                               AUDIO_STREAM_DEFAULT,
+                                               AUDIO_OUTPUT_FLAG_NONE, &output);
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open output stream for devices %s on hw module %s",
+                      supportedDevice->toString().c_str(), hwModule->getName());
+                continue;
+            }
+            for (const auto &device : availProfileDevices) {
+                // give a valid ID to an attached device once confirmed it is reachable
+                if (!device->isAttached()) {
+                    device->attach(hwModule);
+                    mAvailableOutputDevices.add(device);
+                    setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+                }
+            }
+            if (mPrimaryOutput == 0 &&
+                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                mPrimaryOutput = outputDesc;
+            }
+            addOutput(output, outputDesc);
+            setOutputDevices(outputDesc,
+                             DeviceVector(supportedDevice),
+                             true,
+                             0,
+                             NULL);
+        }
+        // open input streams needed to access attached devices to validate
+        // mAvailableInputDevices list
+        for (const auto& inProfile : hwModule->getInputProfiles()) {
+            if (!inProfile->canOpenNewIo()) {
+                ALOGE("Invalid Input profile max open count %u for profile %s",
+                      inProfile->maxOpenCount, inProfile->getTagName().c_str());
+                continue;
+            }
+            if (!inProfile->hasSupportedDevices()) {
+                ALOGW("Input profile contains no device on module %s", hwModule->getName());
+                continue;
+            }
+            // chose first device present in profile's SupportedDevices also part of
+            // available input devices
+            const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+            DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
+            if (availProfileDevices.isEmpty()) {
+                ALOGE("%s: Input device list is empty!", __FUNCTION__);
+                continue;
+            }
+            sp<AudioInputDescriptor> inputDesc =
+                    new AudioInputDescriptor(inProfile, mpClientInterface);
+
+            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+            status_t status = inputDesc->open(nullptr,
+                                              availProfileDevices.itemAt(0),
+                                              AUDIO_SOURCE_MIC,
+                                              AUDIO_INPUT_FLAG_NONE,
+                                              &input);
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open input stream for device %s on hw module %s",
+                      availProfileDevices.toString().c_str(),
+                      hwModule->getName());
+                continue;
+            }
+            for (const auto &device : availProfileDevices) {
+                // give a valid ID to an attached device once confirmed it is reachable
+                if (!device->isAttached()) {
+                    device->attach(hwModule);
+                    device->importAudioPortAndPickAudioProfile(inProfile, true);
+                    mAvailableInputDevices.add(device);
+                    setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+                }
+            }
+            inputDesc->close();
+        }
+    }
+}
+
 void AudioPolicyManager::addOutput(audio_io_handle_t output,
                                    const sp<SwAudioOutputDescriptor>& outputDesc)
 {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 634eb31..4604676 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -315,6 +315,8 @@
             return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
         }
 
+        void onNewAudioModulesAvailable() override;
+
         status_t initialize();
 
 protected:
@@ -717,6 +719,8 @@
         SwAudioOutputCollection mPreviousOutputs;
         AudioInputCollection mInputs;     // list of input descriptors
 
+        DeviceVector  mOutputDevicesAll; // all output devices from the config
+        DeviceVector  mInputDevicesAll;  // all input devices from the config
         DeviceVector  mAvailableOutputDevices; // all available output devices
         DeviceVector  mAvailableInputDevices;  // all available input devices
 
@@ -727,9 +731,8 @@
 
         EffectDescriptorCollection mEffects;  // list of registered audio effects
         sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
-        HwModuleCollection mHwModules; // contains only modules that have been loaded successfully
-        HwModuleCollection mHwModulesAll; // normally not needed, used during construction and for
-                                          // dumps
+        HwModuleCollection mHwModules; // contains modules that have been loaded successfully
+        HwModuleCollection mHwModulesAll; // contains all modules declared in the config
 
         AudioPolicyConfig mConfig;
 
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index c1190be..227adc7 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -28,6 +28,14 @@
 
 // ----------------------------------------------------------------------------
 
+void AudioPolicyService::doOnNewAudioModulesAvailable()
+{
+    if (mAudioPolicyManager == NULL) return;
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    mAudioPolicyManager->onNewAudioModulesAvailable();
+}
+
 status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
                                                   audio_policy_dev_state_t state,
                                                   const char *device_address,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 90939ce..3d9278b 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1278,6 +1278,16 @@
                         mLock.lock();
                     }
                     } break;
+                case AUDIO_MODULES_UPDATE: {
+                    ALOGV("AudioCommandThread() processing audio modules update");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnNewAudioModulesAvailable();
+                    mLock.lock();
+                    } break;
 
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
@@ -1567,6 +1577,13 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::audioModulesUpdateCommand()
+{
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = AUDIO_MODULES_UPDATE;
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
 {
     {
@@ -1814,6 +1831,11 @@
     mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
 }
 
+void AudioPolicyService::onNewAudioModulesAvailable()
+{
+    mAudioCommandThread->audioModulesUpdateCommand();
+}
+
 
 extern "C" {
 audio_module_handle_t aps_load_hw_module(void *service __unused,
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 7b72dc1..0370438 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -60,6 +60,7 @@
     // BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
     //
 
+    void onNewAudioModulesAvailable() override;
     virtual status_t setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address,
@@ -268,6 +269,7 @@
 
     virtual status_t setRttEnabled(bool enabled);
 
+            void doOnNewAudioModulesAvailable();
             status_t doStopOutput(audio_port_handle_t portId);
             void doReleaseOutput(audio_port_handle_t portId);
 
@@ -450,6 +452,7 @@
             DYN_POLICY_MIX_STATE_UPDATE,
             RECORDING_CONFIGURATION_UPDATE,
             SET_EFFECT_SUSPENDED,
+            AUDIO_MODULES_UPDATE,
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -495,6 +498,7 @@
                     void        setEffectSuspendedCommand(int effectId,
                                                           audio_session_t sessionId,
                                                           bool suspended);
+                    void        audioModulesUpdateCommand();
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
     private:
         class AudioCommandData;
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index c2a92d7..af69466 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -15,6 +15,7 @@
  */
 
 #include <map>
+#include <set>
 
 #include <system/audio.h>
 #include <utils/Log.h>
@@ -27,7 +28,10 @@
 class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
 public:
     // AudioPolicyClientInterface implementation
-    audio_module_handle_t loadHwModule(const char * /*name*/) override {
+    audio_module_handle_t loadHwModule(const char* name) override {
+        if (!mAllowedModuleNames.empty() && !mAllowedModuleNames.count(name)) {
+            return AUDIO_MODULE_HANDLE_NONE;
+        }
         return mNextModuleHandle++;
     }
 
@@ -101,11 +105,18 @@
         return &it->second;
     };
 
+    audio_module_handle_t peekNextModuleHandle() const { return mNextModuleHandle; }
+
+    void swapAllowedModuleNames(std::set<std::string>&& names = {}) {
+        mAllowedModuleNames.swap(names);
+    }
+
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
     audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
     std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+    std::set<std::string> mAllowedModuleNames;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index c77dcdc..e8c2d33 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -26,6 +26,8 @@
     using AudioPolicyManager::getConfig;
     using AudioPolicyManager::loadConfig;
     using AudioPolicyManager::initialize;
+    using AudioPolicyManager::getAvailableOutputDevices;
+    using AudioPolicyManager::getAvailableInputDevices;
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index 8736cf1..b5c67a1 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -67,10 +67,10 @@
     manager.loadConfig();
     ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
 
-    for (auto desc : manager.getConfig().getAvailableInputDevices()) {
+    for (auto desc : manager.getConfig().getInputDevices()) {
         ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
     }
-    for (auto desc : manager.getConfig().getAvailableOutputDevices()) {
+    for (auto desc : manager.getConfig().getOutputDevices()) {
         ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
     }
 }
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 0263597..acd61ed 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -292,9 +292,9 @@
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
     uid_t uid = 42;
     const PatchCountCheck patchCount = snapshotPatchCount();
-    ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
+    ASSERT_FALSE(mManager->getAvailableInputDevices().isEmpty());
     PatchBuilder patchBuilder;
-    patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
+    patchBuilder.addSource(mManager->getAvailableInputDevices()[0]).
             addSink(mManager->getConfig().getDefaultOutputDevice());
     ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
     ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
@@ -328,15 +328,13 @@
     sp<AudioProfile> pcmInputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
     mMsdInputDevice->addAudioProfile(pcmInputProfile);
-    config.addAvailableDevice(mMsdOutputDevice);
-    config.addAvailableDevice(mMsdInputDevice);
+    config.addDevice(mMsdOutputDevice);
+    config.addDevice(mMsdInputDevice);
 
     sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
     HwModuleCollection modules = config.getHwModules();
     modules.add(msdModule);
     config.setHwModules(modules);
-    mMsdOutputDevice->attach(msdModule);
-    mMsdInputDevice->attach(msdModule);
 
     sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
     msdOutputProfile->addAudioProfile(pcmOutputProfile);
@@ -1058,3 +1056,40 @@
                                             "hfp_client_out"})
                 )
         );
+
+class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+    void SetUpManagerConfig() override;
+};
+
+void AudioPolicyManagerDynamicHwModulesTest::SetUpManagerConfig() {
+    AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig();
+    // Only allow successful opening of "primary" hw module during APM initialization.
+    mClient->swapAllowedModuleNames({"primary"});
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, DynamicAddition) {
+    const auto handleBefore = mClient->peekNextModuleHandle();
+    mManager->onNewAudioModulesAvailable();
+    ASSERT_EQ(handleBefore, mClient->peekNextModuleHandle());
+    // Reset module loading restrictions.
+    mClient->swapAllowedModuleNames();
+    mManager->onNewAudioModulesAvailable();
+    const auto handleAfter = mClient->peekNextModuleHandle();
+    ASSERT_GT(handleAfter, handleBefore);
+    mManager->onNewAudioModulesAvailable();
+    ASSERT_EQ(handleAfter, mClient->peekNextModuleHandle());
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, AddedDeviceAvailable) {
+    ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, mManager->getDeviceConnectionState(
+                    AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+    mClient->swapAllowedModuleNames({"primary", "r_submix"});
+    mManager->onNewAudioModulesAvailable();
+    ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, mManager->getDeviceConnectionState(
+                    AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 1283148..4e04f0e 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -50,6 +50,7 @@
 #include <string>
 #include <map>
 #include <memory>
+#include <optional>
 #include <utility>
 #include <unordered_map>
 #include <unordered_set>
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index c7a4f2b..3587db3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -2004,6 +2004,15 @@
         }
     }
 
+    for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+        auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
+        if (ret != OK) {
+            ALOGE("%s: Failed removing composite stream  %s (%d)", __FUNCTION__,
+                    strerror(-ret), ret);
+        }
+    }
+    mCompositeStreamMap.clear();
+
     Camera2ClientBase::detachDevice();
 }
 
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 8ebaa2b..0b91016 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -247,7 +247,7 @@
     return ret;
 }
 
-status_t DepthCompositeStream::processInputFrame(const InputFrame &inputFrame) {
+status_t DepthCompositeStream::processInputFrame(nsecs_t ts, const InputFrame &inputFrame) {
     status_t res;
     sp<ANativeWindow> outputANW = mOutputSurface;
     ANativeWindowBuffer *anb;
@@ -370,6 +370,13 @@
         return NO_MEMORY;
     }
 
+    res = native_window_set_buffers_timestamp(mOutputSurface.get(), ts);
+    if (res != OK) {
+        ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__,
+                getStreamId(), strerror(-res), res);
+        return res;
+    }
+
     ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegSize);
     uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
         (gb->getWidth() - sizeof(struct camera3_jpeg_blob));
@@ -459,7 +466,7 @@
         }
     }
 
-    auto res = processInputFrame(mPendingInputFrames[currentTs]);
+    auto res = processInputFrame(currentTs, mPendingInputFrames[currentTs]);
     Mutex::Autolock l(mMutex);
     if (res != OK) {
         ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)", __FUNCTION__,
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 975c59b..28a7826 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -97,7 +97,7 @@
             size_t maxJpegSize, uint8_t jpegQuality,
             std::vector<std::unique_ptr<Item>>* items /*out*/);
     std::unique_ptr<ImagingModel> getImagingModel();
-    status_t processInputFrame(const InputFrame &inputFrame);
+    status_t processInputFrame(nsecs_t ts, const InputFrame &inputFrame);
 
     // Buffer/Results handling
     void compilePendingInputLocked();
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index d21641c..9790e32 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -31,7 +31,6 @@
 #include <mediadrm/ICrypto.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/MediaCodecConstants.h>
 
@@ -61,12 +60,13 @@
         mUseGrid(false),
         mAppSegmentStreamId(-1),
         mAppSegmentSurfaceId(-1),
-        mAppSegmentBufferAcquired(false),
         mMainImageStreamId(-1),
         mMainImageSurfaceId(-1),
         mYuvBufferAcquired(false),
         mProducerListener(new ProducerListener()),
-        mOutputBufferCounter(0),
+        mDequeuedOutputBufferCnt(0),
+        mLockedAppSegmentBufferCnt(0),
+        mCodecOutputCounter(0),
         mGridTimestampUs(0) {
 }
 
@@ -132,7 +132,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    mAppSegmentConsumer = new CpuConsumer(consumer, 1);
+    mAppSegmentConsumer = new CpuConsumer(consumer, kMaxAcquiredAppSegment);
     mAppSegmentConsumer->setFrameAvailableListener(this);
     mAppSegmentConsumer->setName(String8("Camera3-HeicComposite-AppSegmentStream"));
     mAppSegmentSurface = new Surface(producer);
@@ -231,6 +231,8 @@
     if (bufferInfo.mError) return;
 
     mCodecOutputBufferTimestamps.push(bufferInfo.mTimestamp);
+    ALOGV("%s: [%" PRId64 "]: Adding codecOutputBufferTimestamp (%zu timestamps in total)",
+            __FUNCTION__, bufferInfo.mTimestamp, mCodecOutputBufferTimestamps.size());
 }
 
 // We need to get the settings early to handle the case where the codec output
@@ -361,6 +363,8 @@
             mCodecOutputBuffers.push_back(outputBufferInfo);
             mInputReadyCondition.signal();
         } else {
+            ALOGV("%s: Releasing output buffer: size %d flags: 0x%x ", __FUNCTION__,
+                outputBufferInfo.size, outputBufferInfo.flags);
             mCodec->releaseOutputBuffer(outputBufferInfo.index);
         }
     } else {
@@ -414,8 +418,10 @@
         mNumOutputTiles = 1;
     }
 
-    ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
     mFormat = newFormat;
+
+    ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
+    mInputReadyCondition.signal();
 }
 
 void HeicCompositeStream::onHeicCodecError() {
@@ -459,9 +465,8 @@
 
     // Cannot use SourceSurface buffer count since it could be codec's 512*512 tile
     // buffer count.
-    int maxProducerBuffers = 1;
     if ((res = native_window_set_buffer_count(
-                    anwConsumer, maxProducerBuffers + maxConsumerBuffers)) != OK) {
+                    anwConsumer, kMaxOutputSurfaceProducerCount + maxConsumerBuffers)) != OK) {
         ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
         return res;
     }
@@ -505,6 +510,8 @@
     }
 
     if (mSettingsByFrameNumber.find(resultExtras.frameNumber) != mSettingsByFrameNumber.end()) {
+        ALOGV("%s: [%" PRId64 "]: frameNumber %" PRId64, __FUNCTION__,
+                timestamp, resultExtras.frameNumber);
         mFrameNumberMap.emplace(resultExtras.frameNumber, timestamp);
         mSettingsByTimestamp[timestamp] = mSettingsByFrameNumber[resultExtras.frameNumber];
         mSettingsByFrameNumber.erase(resultExtras.frameNumber);
@@ -520,12 +527,12 @@
         mSettingsByTimestamp.erase(it);
     }
 
-    while (!mInputAppSegmentBuffers.empty() && !mAppSegmentBufferAcquired) {
+    while (!mInputAppSegmentBuffers.empty()) {
         CpuConsumer::LockedBuffer imgBuffer;
         auto it = mInputAppSegmentBuffers.begin();
         auto res = mAppSegmentConsumer->lockNextBuffer(&imgBuffer);
         if (res == NOT_ENOUGH_DATA) {
-            // Canot not lock any more buffers.
+            // Can not lock any more buffers.
             break;
         } else if ((res != OK) || (*it != imgBuffer.timestamp)) {
             if (res != OK) {
@@ -535,6 +542,7 @@
                 ALOGE("%s: Expecting JPEG_APP_SEGMENTS buffer with time stamp: %" PRId64
                         " received buffer with time stamp: %" PRId64, __FUNCTION__,
                         *it, imgBuffer.timestamp);
+                mAppSegmentConsumer->unlockBuffer(imgBuffer);
             }
             mPendingInputFrames[*it].error = true;
             mInputAppSegmentBuffers.erase(it);
@@ -546,7 +554,7 @@
             mAppSegmentConsumer->unlockBuffer(imgBuffer);
         } else {
             mPendingInputFrames[imgBuffer.timestamp].appSegmentBuffer = imgBuffer;
-            mAppSegmentBufferAcquired = true;
+            mLockedAppSegmentBufferCnt++;
         }
         mInputAppSegmentBuffers.erase(it);
     }
@@ -556,7 +564,7 @@
         auto it = mInputYuvBuffers.begin();
         auto res = mMainImageConsumer->lockNextBuffer(&imgBuffer);
         if (res == NOT_ENOUGH_DATA) {
-            // Canot not lock any more buffers.
+            // Can not lock any more buffers.
             break;
         } else if (res != OK) {
             ALOGE("%s: Error locking YUV_888 image buffer: %s (%d)", __FUNCTION__,
@@ -589,17 +597,20 @@
         // to look up timestamp.
         int64_t bufferTime = -1;
         if (mCodecOutputBufferTimestamps.empty()) {
-            ALOGE("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+            ALOGV("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+            break;
         } else {
             // Direct mapping between camera timestamp (in ns) and codec timestamp (in us).
             bufferTime = mCodecOutputBufferTimestamps.front();
-            mOutputBufferCounter++;
-            if (mOutputBufferCounter == mNumOutputTiles) {
+            mCodecOutputCounter++;
+            if (mCodecOutputCounter == mNumOutputTiles) {
                 mCodecOutputBufferTimestamps.pop();
-                mOutputBufferCounter = 0;
+                mCodecOutputCounter = 0;
             }
 
             mPendingInputFrames[bufferTime].codecOutputBuffers.push_back(*it);
+            ALOGV("%s: [%" PRId64 "]: Pushing codecOutputBuffers (time %" PRId64 " us)",
+                    __FUNCTION__, bufferTime, it->timeUs);
         }
         mCodecOutputBuffers.erase(it);
     }
@@ -607,6 +618,7 @@
     while (!mFrameNumberMap.empty()) {
         auto it = mFrameNumberMap.begin();
         mPendingInputFrames[it->second].frameNumber = it->first;
+        ALOGV("%s: [%" PRId64 "]: frameNumber is %" PRId64, __FUNCTION__, it->second, it->first);
         mFrameNumberMap.erase(it);
     }
 
@@ -675,16 +687,29 @@
     }
 
     bool newInputAvailable = false;
-    for (const auto& it : mPendingInputFrames) {
+    for (auto& it : mPendingInputFrames) {
+        // New input is considered to be available only if:
+        // 1. input buffers are ready, or
+        // 2. App segment and muxer is created, or
+        // 3. A codec output tile is ready, and an output buffer is available.
+        // This makes sure that muxer gets created only when an output tile is
+        // generated, because right now we only handle 1 HEIC output buffer at a
+        // time (max dequeued buffer count is 1).
         bool appSegmentReady = (it.second.appSegmentBuffer.data != nullptr) &&
-                !it.second.appSegmentWritten && it.second.result != nullptr;
+                !it.second.appSegmentWritten && it.second.result != nullptr &&
+                it.second.muxer != nullptr;
         bool codecOutputReady = !it.second.codecOutputBuffers.empty();
         bool codecInputReady = (it.second.yuvBuffer.data != nullptr) &&
                 (!it.second.codecInputBuffers.empty());
+        bool hasOutputBuffer = it.second.muxer != nullptr ||
+                (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
         if ((!it.second.error) &&
                 (it.first < *currentTs) &&
-                (appSegmentReady || codecOutputReady || codecInputReady)) {
+                (appSegmentReady || (codecOutputReady && hasOutputBuffer) || codecInputReady)) {
             *currentTs = it.first;
+            if (it.second.format == nullptr && mFormat != nullptr) {
+                it.second.format = mFormat->dup();
+            }
             newInputAvailable = true;
             break;
         }
@@ -716,15 +741,17 @@
     status_t res = OK;
 
     bool appSegmentReady = inputFrame.appSegmentBuffer.data != nullptr &&
-            !inputFrame.appSegmentWritten && inputFrame.result != nullptr;
+            !inputFrame.appSegmentWritten && inputFrame.result != nullptr &&
+            inputFrame.muxer != nullptr;
     bool codecOutputReady = inputFrame.codecOutputBuffers.size() > 0;
     bool codecInputReady = inputFrame.yuvBuffer.data != nullptr &&
-           !inputFrame.codecInputBuffers.empty();
+            !inputFrame.codecInputBuffers.empty();
+    bool hasOutputBuffer = inputFrame.muxer != nullptr ||
+            (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
 
-    if (!appSegmentReady && !codecOutputReady && !codecInputReady) {
-        ALOGW("%s: No valid appSegmentBuffer/codec input/outputBuffer available!", __FUNCTION__);
-        return OK;
-    }
+    ALOGV("%s: [%" PRId64 "]: appSegmentReady %d, codecOutputReady %d, codecInputReady %d,"
+            " dequeuedOutputBuffer %d", __FUNCTION__, timestamp, appSegmentReady,
+            codecOutputReady, codecInputReady, mDequeuedOutputBufferCnt);
 
     // Handle inputs for Hevc tiling
     if (codecInputReady) {
@@ -736,7 +763,13 @@
         }
     }
 
-    // Initialize and start muxer if not yet done so
+    if (!(codecOutputReady && hasOutputBuffer) && !appSegmentReady) {
+        return OK;
+    }
+
+    // Initialize and start muxer if not yet done so. In this case,
+    // codecOutputReady must be true. Otherwise, appSegmentReady is guaranteed
+    // to be false, and the function must have returned early.
     if (inputFrame.muxer == nullptr) {
         res = startMuxerForInputFrame(timestamp, inputFrame);
         if (res != OK) {
@@ -747,7 +780,7 @@
     }
 
     // Write JPEG APP segments data to the muxer.
-    if (appSegmentReady && inputFrame.muxer != nullptr) {
+    if (appSegmentReady) {
         res = processAppSegment(timestamp, inputFrame);
         if (res != OK) {
             ALOGE("%s: Failed to process JPEG APP segments: %s (%d)", __FUNCTION__,
@@ -766,12 +799,18 @@
         }
     }
 
-    if (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0) {
-        res = processCompletedInputFrame(timestamp, inputFrame);
-        if (res != OK) {
-            ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
-                    strerror(-res), res);
-            return res;
+    if (inputFrame.pendingOutputTiles == 0) {
+        if (inputFrame.appSegmentWritten) {
+            res = processCompletedInputFrame(timestamp, inputFrame);
+            if (res != OK) {
+                ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
+                        strerror(-res), res);
+                return res;
+            }
+        } else if (mLockedAppSegmentBufferCnt == kMaxAcquiredAppSegment) {
+            ALOGE("%s: Out-of-order app segment buffers reaches limit %u", __FUNCTION__,
+                    kMaxAcquiredAppSegment);
+            return INVALID_OPERATION;
         }
     }
 
@@ -780,11 +819,6 @@
 
 status_t HeicCompositeStream::startMuxerForInputFrame(nsecs_t timestamp, InputFrame &inputFrame) {
     sp<ANativeWindow> outputANW = mOutputSurface;
-    if (inputFrame.codecOutputBuffers.size() == 0) {
-        // No single codec output buffer has been generated. Continue to
-        // wait.
-        return OK;
-    }
 
     auto res = outputANW->dequeueBuffer(mOutputSurface.get(), &inputFrame.anb, &inputFrame.fenceFd);
     if (res != OK) {
@@ -792,6 +826,7 @@
                 res);
         return res;
     }
+    mDequeuedOutputBufferCnt++;
 
     // Combine current thread id, stream id and timestamp to uniquely identify image.
     std::ostringstream tempOutputFile;
@@ -828,7 +863,7 @@
         }
     }
 
-    ssize_t trackId = inputFrame.muxer->addTrack(mFormat);
+    ssize_t trackId = inputFrame.muxer->addTrack(inputFrame.format);
     if (trackId < 0) {
         ALOGE("%s: Failed to addTrack to the muxer: %zd", __FUNCTION__, trackId);
         return NO_INIT;
@@ -844,6 +879,8 @@
         return res;
     }
 
+    ALOGV("%s: [%" PRId64 "]: Muxer started for inputFrame", __FUNCTION__,
+            timestamp);
     return OK;
 }
 
@@ -852,9 +889,6 @@
     auto appSegmentSize = findAppSegmentsSize(inputFrame.appSegmentBuffer.data,
             inputFrame.appSegmentBuffer.width * inputFrame.appSegmentBuffer.height,
             &app1Size);
-    ALOGV("%s: appSegmentSize is %zu, width %d, height %d, app1Size %zu", __FUNCTION__,
-          appSegmentSize, inputFrame.appSegmentBuffer.width,
-          inputFrame.appSegmentBuffer.height, app1Size);
     if (appSegmentSize == 0) {
         ALOGE("%s: Failed to find JPEG APP segment size", __FUNCTION__);
         return NO_INIT;
@@ -910,7 +944,16 @@
                 __FUNCTION__, strerror(-res), res);
         return res;
     }
+
+    ALOGV("%s: [%" PRId64 "]: appSegmentSize is %zu, width %d, height %d, app1Size %zu",
+          __FUNCTION__, timestamp, appSegmentSize, inputFrame.appSegmentBuffer.width,
+          inputFrame.appSegmentBuffer.height, app1Size);
+
     inputFrame.appSegmentWritten = true;
+    // Release the buffer now so any pending input app segments can be processed
+    mAppSegmentConsumer->unlockBuffer(inputFrame.appSegmentBuffer);
+    inputFrame.appSegmentBuffer.data = nullptr;
+    mLockedAppSegmentBufferCnt--;
 
     return OK;
 }
@@ -934,8 +977,9 @@
                 mOutputWidth - tileX * mGridWidth : mGridWidth;
         size_t height = (tileY == static_cast<size_t>(mGridRows) - 1) ?
                 mOutputHeight - tileY * mGridHeight : mGridHeight;
-        ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu",
-                __FUNCTION__, tileX, tileY, top, left, width, height);
+        ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu,"
+                " timeUs %" PRId64, __FUNCTION__, tileX, tileY, top, left, width, height,
+                inputBuffer.timeUs);
 
         res = copyOneYuvTile(buffer, inputFrame.yuvBuffer, top, left, width, height);
         if (res != OK) {
@@ -990,6 +1034,9 @@
     }
 
     inputFrame.codecOutputBuffers.erase(inputFrame.codecOutputBuffers.begin());
+
+    ALOGV("%s: [%" PRId64 "]: Output buffer index %d",
+        __FUNCTION__, timestamp, it->index);
     return OK;
 }
 
@@ -1046,7 +1093,9 @@
         return res;
     }
     inputFrame.anb = nullptr;
+    mDequeuedOutputBufferCnt--;
 
+    ALOGV("%s: [%" PRId64 "]", __FUNCTION__, timestamp);
     ATRACE_ASYNC_END("HEIC capture", inputFrame.frameNumber);
     return OK;
 }
@@ -1060,7 +1109,6 @@
     if (inputFrame->appSegmentBuffer.data != nullptr) {
         mAppSegmentConsumer->unlockBuffer(inputFrame->appSegmentBuffer);
         inputFrame->appSegmentBuffer.data = nullptr;
-        mAppSegmentBufferAcquired = false;
     }
 
     while (!inputFrame->codecOutputBuffers.empty()) {
@@ -1098,11 +1146,13 @@
     }
 }
 
-void HeicCompositeStream::releaseInputFramesLocked(int64_t currentTs) {
+void HeicCompositeStream::releaseInputFramesLocked() {
     auto it = mPendingInputFrames.begin();
     while (it != mPendingInputFrames.end()) {
-        if (it->first <= currentTs) {
-            releaseInputFrameLocked(&it->second);
+        auto& inputFrame = it->second;
+        if (inputFrame.error ||
+            (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0)) {
+            releaseInputFrameLocked(&inputFrame);
             it = mPendingInputFrames.erase(it);
         } else {
             it++;
@@ -1506,7 +1556,7 @@
             // In case we landed in error state, return any pending buffers and
             // halt all further processing.
             compilePendingInputLocked();
-            releaseInputFramesLocked(currentTs);
+            releaseInputFramesLocked();
             return false;
         }
 
@@ -1548,11 +1598,7 @@
         mPendingInputFrames[currentTs].error = true;
     }
 
-    if (mPendingInputFrames[currentTs].error ||
-            (mPendingInputFrames[currentTs].appSegmentWritten &&
-            mPendingInputFrames[currentTs].pendingOutputTiles == 0)) {
-        releaseInputFramesLocked(currentTs);
-    }
+    releaseInputFramesLocked();
 
     return true;
 }
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index 260c68e..04e7b83 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -25,6 +25,7 @@
 #include <media/hardware/VideoAPI.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaMuxer.h>
 
@@ -157,6 +158,7 @@
         bool                      errorNotified;
         int64_t                   frameNumber;
 
+        sp<AMessage>              format;
         sp<MediaMuxer>            muxer;
         int                       fenceFd;
         int                       fileFd;
@@ -187,7 +189,7 @@
     status_t processCompletedInputFrame(nsecs_t timestamp, InputFrame &inputFrame);
 
     void releaseInputFrameLocked(InputFrame *inputFrame /*out*/);
-    void releaseInputFramesLocked(int64_t currentTs);
+    void releaseInputFramesLocked();
 
     size_t findAppSegmentsSize(const uint8_t* appSegmentBuffer, size_t maxSize,
             size_t* app1SegmentSize);
@@ -205,11 +207,13 @@
             static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS);
     static const android_dataspace kHeifDataSpace =
             static_cast<android_dataspace>(HAL_DATASPACE_HEIF);
+    // Use the limit of pipeline depth in the API sepc as maximum number of acquired
+    // app segment buffers.
+    static const uint32_t kMaxAcquiredAppSegment = 8;
 
     int               mAppSegmentStreamId, mAppSegmentSurfaceId;
     sp<CpuConsumer>   mAppSegmentConsumer;
     sp<Surface>       mAppSegmentSurface;
-    bool              mAppSegmentBufferAcquired;
     size_t            mAppSegmentMaxSize;
     CameraMetadata    mStaticInfo;
 
@@ -218,9 +222,10 @@
     sp<CpuConsumer>   mMainImageConsumer; // Only applicable for HEVC codec.
     bool              mYuvBufferAcquired; // Only applicable to HEVC codec
 
+    static const int32_t kMaxOutputSurfaceProducerCount = 1;
     sp<Surface>       mOutputSurface;
     sp<ProducerListener> mProducerListener;
-
+    int32_t           mDequeuedOutputBufferCnt;
 
     // Map from frame number to JPEG setting of orientation+quality
     std::map<int64_t, std::pair<int32_t, int32_t>> mSettingsByFrameNumber;
@@ -229,11 +234,12 @@
 
     // Keep all incoming APP segment Blob buffer pending further processing.
     std::vector<int64_t> mInputAppSegmentBuffers;
+    int32_t           mLockedAppSegmentBufferCnt;
 
     // Keep all incoming HEIC blob buffer pending further processing.
     std::vector<CodecOutputBufferInfo> mCodecOutputBuffers;
     std::queue<int64_t> mCodecOutputBufferTimestamps;
-    size_t mOutputBufferCounter;
+    size_t mCodecOutputCounter;
 
     // Keep all incoming Yuv buffer pending tiling and encoding (for HEVC YUV tiling only)
     std::vector<int64_t> mInputYuvBuffers;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index acb8b3c..e1d35e8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -54,9 +54,8 @@
         mState = STATE_ERROR;
     }
 
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
 
 Camera3OutputStream::Camera3OutputStream(int id,
@@ -87,9 +86,8 @@
         mState = STATE_ERROR;
     }
 
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
 
 Camera3OutputStream::Camera3OutputStream(int id,
@@ -124,10 +122,8 @@
     }
 
     mConsumerName = String8("Deferred");
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
-
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
 
 Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
@@ -151,9 +147,8 @@
         mDropBuffers(false),
         mDequeueBufferLatency(kDequeueLatencyBinSize) {
 
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 
     // Subclasses expected to initialize mConsumer themselves
 }
@@ -261,7 +256,7 @@
         notifyBufferReleased(anwBuffer);
         if (mUseBufferManager) {
             // Return this buffer back to buffer manager.
-            mBufferReleasedListener->onBufferReleased();
+            mBufferProducerListener->onBufferReleased();
         }
     } else {
         if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
@@ -387,8 +382,8 @@
     // Configure consumer-side ANativeWindow interface. The listener may be used
     // to notify buffer manager (if it is used) of the returned buffers.
     res = mConsumer->connect(NATIVE_WINDOW_API_CAMERA,
-            /*listener*/mBufferReleasedListener,
-            /*reportBufferRemoval*/true);
+            /*reportBufferRemoval*/true,
+            /*listener*/mBufferProducerListener);
     if (res != OK) {
         ALOGE("%s: Unable to connect to native window for stream %d",
                 __FUNCTION__, mId);
@@ -790,7 +785,7 @@
     return INVALID_OPERATION;
 }
 
-void Camera3OutputStream::BufferReleasedListener::onBufferReleased() {
+void Camera3OutputStream::BufferProducerListener::onBufferReleased() {
     sp<Camera3OutputStream> stream = mParent.promote();
     if (stream == nullptr) {
         ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
@@ -823,6 +818,25 @@
     }
 }
 
+void Camera3OutputStream::BufferProducerListener::onBuffersDiscarded(
+        const std::vector<sp<GraphicBuffer>>& buffers) {
+    sp<Camera3OutputStream> stream = mParent.promote();
+    if (stream == nullptr) {
+        ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
+        return;
+    }
+
+    if (buffers.size() > 0) {
+        Mutex::Autolock l(stream->mLock);
+        stream->onBuffersRemovedLocked(buffers);
+        if (stream->mUseBufferManager) {
+            stream->mBufferManager->onBuffersRemoved(stream->getId(),
+                    stream->getStreamSetId(), buffers.size());
+        }
+        ALOGV("Stream %d: %zu Buffers discarded.", stream->getId(), buffers.size());
+    }
+}
+
 void Camera3OutputStream::onBuffersRemovedLocked(
         const std::vector<sp<GraphicBuffer>>& removedBuffers) {
     sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote();
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 729c655..b4e49f9 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -146,18 +146,22 @@
      */
     virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
-    class BufferReleasedListener : public BnProducerListener {
+    class BufferProducerListener : public SurfaceListener {
         public:
-          BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
+            BufferProducerListener(wp<Camera3OutputStream> parent, bool needsReleaseNotify)
+                    : mParent(parent), mNeedsReleaseNotify(needsReleaseNotify) {}
 
-          /**
-          * Implementation of IProducerListener, used to notify this stream that the consumer
-          * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
-          */
-          virtual void onBufferReleased();
+            /**
+            * Implementation of IProducerListener, used to notify this stream that the consumer
+            * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
+            */
+            virtual void onBufferReleased();
+            virtual bool needsReleaseNotify() { return mNeedsReleaseNotify; }
+            virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers);
 
         private:
-          wp<Camera3OutputStream> mParent;
+            wp<Camera3OutputStream> mParent;
+            bool mNeedsReleaseNotify;
     };
 
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
@@ -262,10 +266,10 @@
     sp<Camera3BufferManager> mBufferManager;
 
     /**
-     * Buffer released listener, used to notify the buffer manager that a buffer is released
-     * from consumer side.
+     * Buffer producer listener, used to handle notification when a buffer is released
+     * from consumer side, or a set of buffers are discarded by the consumer.
      */
-    sp<BufferReleasedListener> mBufferReleasedListener;
+    sp<BufferProducerListener> mBufferProducerListener;
 
     /**
      * Flag indicating if the buffer manager is used to allocate the stream buffers
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index 765ac99..fa5bc4a 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -14,7 +14,6 @@
         "libbase",
         "libcodec2_hidl@1.0",
         "libcodec2_vndk",
-        "libhidlbase",
         "libutils",
     ],
 
diff --git a/services/mediacodec/registrant/CodecServiceRegistrant.cpp b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
index 7f7ceca..706ebee 100644
--- a/services/mediacodec/registrant/CodecServiceRegistrant.cpp
+++ b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
@@ -18,411 +18,21 @@
 #define LOG_TAG "CodecServiceRegistrant"
 
 #include <android-base/logging.h>
-#include <android-base/properties.h>
 
-#include <C2Component.h>
 #include <C2PlatformSupport.h>
 #include <codec2/hidl/1.0/ComponentStore.h>
-#include <codec2/hidl/1.0/Configurable.h>
-#include <codec2/hidl/1.0/types.h>
-#include <hidl/HidlSupport.h>
 #include <media/CodecServiceRegistrant.h>
 
-namespace /* unnamed */ {
-
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-using namespace ::android::hardware::media::c2::V1_0;
-using namespace ::android::hardware::media::c2::V1_0::utils;
-
-constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
-
-// Converter from IComponentStore to C2ComponentStore.
-class H2C2ComponentStore : public C2ComponentStore {
-protected:
-    sp<IComponentStore> mStore;
-    sp<IConfigurable> mConfigurable;
-public:
-    explicit H2C2ComponentStore(sp<IComponentStore> const& store)
-          : mStore{store},
-            mConfigurable{[store]() -> sp<IConfigurable>{
-                if (!store) {
-                    return nullptr;
-                }
-                Return<sp<IConfigurable>> transResult =
-                    store->getConfigurable();
-                return transResult.isOk() ?
-                        static_cast<sp<IConfigurable>>(transResult) :
-                        nullptr;
-            }()} {
-        if (!mConfigurable) {
-            LOG(ERROR) << "Preferred store is corrupted.";
-        }
-    }
-
-    virtual ~H2C2ComponentStore() override = default;
-
-    virtual c2_status_t config_sm(
-            std::vector<C2Param*> const &params,
-            std::vector<std::unique_ptr<C2SettingResult>>* const failures
-            ) override {
-        Params hidlParams;
-        if (!createParamsBlob(&hidlParams, params)) {
-            LOG(ERROR) << "config -- bad input.";
-            return C2_TRANSACTION_FAILED;
-        }
-        c2_status_t status{};
-        Return<void> transResult = mConfigurable->config(
-                hidlParams,
-                true,
-                [&status, &params, failures](
-                        Status s,
-                        const hidl_vec<SettingResult> f,
-                        const Params& o) {
-                    status = static_cast<c2_status_t>(s);
-                    if (status != C2_OK && status != C2_BAD_INDEX) {
-                        LOG(DEBUG) << "config -- call failed: "
-                                   << status << ".";
-                    }
-                    size_t i = failures->size();
-                    failures->resize(i + f.size());
-                    for (const SettingResult& sf : f) {
-                        if (!objcpy(&(*failures)[i++], sf)) {
-                            LOG(ERROR) << "config -- "
-                                       << "invalid SettingResult returned.";
-                            return;
-                        }
-                    }
-                    if (!updateParamsFromBlob(params, o)) {
-                        LOG(ERROR) << "config -- "
-                                   << "failed to parse returned params.";
-                        status = C2_CORRUPTED;
-                    }
-                });
-        if (!transResult.isOk()) {
-            LOG(ERROR) << "config -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
-        return status;
-    };
-
-    virtual c2_status_t copyBuffer(
-            std::shared_ptr<C2GraphicBuffer>,
-            std::shared_ptr<C2GraphicBuffer>) override {
-        LOG(ERROR) << "copyBuffer -- not supported.";
-        return C2_OMITTED;
-    }
-
-    virtual c2_status_t createComponent(
-            C2String, std::shared_ptr<C2Component> *const component) override {
-        component->reset();
-        LOG(ERROR) << "createComponent -- not supported.";
-        return C2_OMITTED;
-    }
-
-    virtual c2_status_t createInterface(
-            C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
-        interface->reset();
-        LOG(ERROR) << "createInterface -- not supported.";
-        return C2_OMITTED;
-    }
-
-    virtual c2_status_t query_sm(
-            const std::vector<C2Param *> &stackParams,
-            const std::vector<C2Param::Index> &heapParamIndices,
-            std::vector<std::unique_ptr<C2Param>> *const heapParams) const
-            override {
-        hidl_vec<ParamIndex> indices(
-                stackParams.size() + heapParamIndices.size());
-        size_t numIndices = 0;
-        for (C2Param* const& stackParam : stackParams) {
-            if (!stackParam) {
-                LOG(WARNING) << "query -- null stack param encountered.";
-                continue;
-            }
-            indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
-        }
-        size_t numStackIndices = numIndices;
-        for (const C2Param::Index& index : heapParamIndices) {
-            indices[numIndices++] =
-                    static_cast<ParamIndex>(static_cast<uint32_t>(index));
-        }
-        indices.resize(numIndices);
-        if (heapParams) {
-            heapParams->reserve(heapParams->size() + numIndices);
-        }
-        c2_status_t status;
-        Return<void> transResult = mConfigurable->query(
-                indices,
-                true,
-                [&status, &numStackIndices, &stackParams, heapParams](
-                        Status s, const Params& p) {
-                    status = static_cast<c2_status_t>(s);
-                    if (status != C2_OK && status != C2_BAD_INDEX) {
-                        LOG(DEBUG) << "query -- call failed: "
-                                   << status << ".";
-                        return;
-                    }
-                    std::vector<C2Param*> paramPointers;
-                    if (!parseParamsBlob(&paramPointers, p)) {
-                        LOG(ERROR) << "query -- error while parsing params.";
-                        status = C2_CORRUPTED;
-                        return;
-                    }
-                    size_t i = 0;
-                    for (auto it = paramPointers.begin();
-                            it != paramPointers.end(); ) {
-                        C2Param* paramPointer = *it;
-                        if (numStackIndices > 0) {
-                            --numStackIndices;
-                            if (!paramPointer) {
-                                LOG(WARNING) << "query -- null stack param.";
-                                ++it;
-                                continue;
-                            }
-                            for (; i < stackParams.size() && !stackParams[i]; ) {
-                                ++i;
-                            }
-                            if (i >= stackParams.size()) {
-                                LOG(ERROR) << "query -- unexpected error.";
-                                status = C2_CORRUPTED;
-                                return;
-                            }
-                            if (stackParams[i]->index() != paramPointer->index()) {
-                                LOG(WARNING) << "query -- param skipped: "
-                                                "index = "
-                                             << stackParams[i]->index() << ".";
-                                stackParams[i++]->invalidate();
-                                continue;
-                            }
-                            if (!stackParams[i++]->updateFrom(*paramPointer)) {
-                                LOG(WARNING) << "query -- param update failed: "
-                                                "index = "
-                                             << paramPointer->index() << ".";
-                            }
-                        } else {
-                            if (!paramPointer) {
-                                LOG(WARNING) << "query -- null heap param.";
-                                ++it;
-                                continue;
-                            }
-                            if (!heapParams) {
-                                LOG(WARNING) << "query -- "
-                                                "unexpected extra stack param.";
-                            } else {
-                                heapParams->emplace_back(
-                                        C2Param::Copy(*paramPointer));
-                            }
-                        }
-                        ++it;
-                    }
-                });
-        if (!transResult.isOk()) {
-            LOG(ERROR) << "query -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
-        return status;
-    }
-
-    virtual c2_status_t querySupportedParams_nb(
-            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
-        c2_status_t status;
-        Return<void> transResult = mConfigurable->querySupportedParams(
-                std::numeric_limits<uint32_t>::min(),
-                std::numeric_limits<uint32_t>::max(),
-                [&status, params](
-                        Status s,
-                        const hidl_vec<ParamDescriptor>& p) {
-                    status = static_cast<c2_status_t>(s);
-                    if (status != C2_OK) {
-                        LOG(DEBUG) << "querySupportedParams -- call failed: "
-                                   << status << ".";
-                        return;
-                    }
-                    size_t i = params->size();
-                    params->resize(i + p.size());
-                    for (const ParamDescriptor& sp : p) {
-                        if (!objcpy(&(*params)[i++], sp)) {
-                            LOG(ERROR) << "querySupportedParams -- "
-                                       << "invalid returned ParamDescriptor.";
-                            return;
-                        }
-                    }
-                });
-        if (!transResult.isOk()) {
-            LOG(ERROR) << "querySupportedParams -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
-        return status;
-    }
-
-    virtual c2_status_t querySupportedValues_sm(
-            std::vector<C2FieldSupportedValuesQuery> &fields) const {
-        hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
-        for (size_t i = 0; i < fields.size(); ++i) {
-            if (!objcpy(&inFields[i], fields[i])) {
-                LOG(ERROR) << "querySupportedValues -- bad input";
-                return C2_TRANSACTION_FAILED;
-            }
-        }
-
-        c2_status_t status;
-        Return<void> transResult = mConfigurable->querySupportedValues(
-                inFields,
-                true,
-                [&status, &inFields, &fields](
-                        Status s,
-                        const hidl_vec<FieldSupportedValuesQueryResult>& r) {
-                    status = static_cast<c2_status_t>(s);
-                    if (status != C2_OK) {
-                        LOG(DEBUG) << "querySupportedValues -- call failed: "
-                                   << status << ".";
-                        return;
-                    }
-                    if (r.size() != fields.size()) {
-                        LOG(ERROR) << "querySupportedValues -- "
-                                      "input and output lists "
-                                      "have different sizes.";
-                        status = C2_CORRUPTED;
-                        return;
-                    }
-                    for (size_t i = 0; i < fields.size(); ++i) {
-                        if (!objcpy(&fields[i], inFields[i], r[i])) {
-                            LOG(ERROR) << "querySupportedValues -- "
-                                          "invalid returned value.";
-                            status = C2_CORRUPTED;
-                            return;
-                        }
-                    }
-                });
-        if (!transResult.isOk()) {
-            LOG(ERROR) << "querySupportedValues -- transaction failed.";
-            return C2_TRANSACTION_FAILED;
-        }
-        return status;
-    }
-
-    virtual C2String getName() const {
-        C2String outName;
-        Return<void> transResult = mConfigurable->getName(
-                [&outName](const hidl_string& name) {
-                    outName = name.c_str();
-                });
-        if (!transResult.isOk()) {
-            LOG(ERROR) << "getName -- transaction failed.";
-        }
-        return outName;
-    }
-
-    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const
-            override {
-        struct SimpleParamReflector : public C2ParamReflector {
-            virtual std::unique_ptr<C2StructDescriptor> describe(
-                    C2Param::CoreIndex coreIndex) const {
-                hidl_vec<ParamIndex> indices(1);
-                indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
-                std::unique_ptr<C2StructDescriptor> descriptor;
-                Return<void> transResult = mBase->getStructDescriptors(
-                        indices,
-                        [&descriptor](
-                                Status s,
-                                const hidl_vec<StructDescriptor>& sd) {
-                            c2_status_t status = static_cast<c2_status_t>(s);
-                            if (status != C2_OK) {
-                                LOG(DEBUG) << "SimpleParamReflector -- "
-                                              "getStructDescriptors() failed: "
-                                           << status << ".";
-                                descriptor.reset();
-                                return;
-                            }
-                            if (sd.size() != 1) {
-                                LOG(DEBUG) << "SimpleParamReflector -- "
-                                              "getStructDescriptors() "
-                                              "returned vector of size "
-                                           << sd.size() << ". "
-                                              "It should be 1.";
-                                descriptor.reset();
-                                return;
-                            }
-                            if (!objcpy(&descriptor, sd[0])) {
-                                LOG(DEBUG) << "SimpleParamReflector -- "
-                                              "getStructDescriptors() returned "
-                                              "corrupted data.";
-                                descriptor.reset();
-                                return;
-                            }
-                        });
-                return descriptor;
-            }
-
-            explicit SimpleParamReflector(sp<IComponentStore> base)
-                : mBase(base) { }
-
-            sp<IComponentStore> mBase;
-        };
-
-        return std::make_shared<SimpleParamReflector>(mStore);
-    }
-
-    virtual std::vector<std::shared_ptr<const C2Component::Traits>>
-            listComponents() override {
-        LOG(ERROR) << "listComponents -- not supported.";
-        return {};
-    }
-};
-
-bool ionPropertiesDefined() {
-    using namespace ::android::base;
-    std::string heapMask =
-        GetProperty("ro.com.android.media.swcodec.ion.heapmask", "undefined");
-    std::string flags =
-        GetProperty("ro.com.android.media.swcodec.ion.flags", "undefined");
-    std::string align =
-        GetProperty("ro.com.android.media.swcodec.ion.align", "undefined");
-    if (heapMask != "undefined" ||
-            flags != "undefined" ||
-            align != "undefined") {
-        LOG(INFO)
-                << "Some system properties for mediaswcodec ION usage are set: "
-                << "heapmask = " << heapMask << ", "
-                << "flags = " << flags << ", "
-                << "align = " << align << ". "
-                << "Preferred Codec2 store is defaulted to \"software\".";
-        return true;
-    }
-    return false;
-}
-
-} // unnamed namespace
-
 extern "C" void RegisterCodecServices() {
-    using ComponentStore = ::android::hardware::media::c2::V1_0::utils::
-            ComponentStore;
+    using namespace ::android::hardware::media::c2::V1_0;
     LOG(INFO) << "Creating software Codec2 service...";
-    sp<ComponentStore> store =
-        new ComponentStore(::android::GetCodec2PlatformComponentStore());
+    android::sp<IComponentStore> store =
+        new utils::ComponentStore(
+                android::GetCodec2PlatformComponentStore());
     if (store == nullptr) {
         LOG(ERROR) <<
                 "Cannot create software Codec2 service.";
     } else {
-        if (!ionPropertiesDefined()) {
-            std::string preferredStoreName = "default";
-            sp<IComponentStore> preferredStore =
-                IComponentStore::getService(preferredStoreName.c_str());
-            if (preferredStore) {
-                ::android::SetPreferredCodec2ComponentStore(
-                        std::make_shared<H2C2ComponentStore>(preferredStore));
-                LOG(INFO) <<
-                        "Preferred Codec2 store is set to \"" <<
-                        preferredStoreName << "\".";
-            } else {
-                LOG(INFO) <<
-                        "Preferred Codec2 store is defaulted to \"software\".";
-            }
-        }
         if (store->registerAsService("software") != android::OK) {
             LOG(ERROR) <<
                     "Cannot register software Codec2 service.";
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 16b036f..e906500 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -29,9 +29,6 @@
         "liblog",
         "libavservices_minijail",
     ],
-    header_libs: [
-        "bionic_libc_platform_headers",
-    ],
     target: {
         android: {
             product_variables: {
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index afb7692..3c4125b 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -28,8 +28,6 @@
 #include <android-base/properties.h>
 #include <utils/misc.h>
 
-#include <bionic/reserved_signals.h>
-
 // from LOCAL_C_INCLUDES
 #include "MediaExtractorService.h"
 #include "MediaUtils.h"
@@ -51,10 +49,6 @@
 
     signal(SIGPIPE, SIG_IGN);
 
-    // Do not assist platform profilers (relevant only on debug builds).
-    // Otherwise, the signal handler can violate the seccomp policy.
-    signal(BIONIC_SIGNAL_PROFILER, SIG_IGN);
-
     //b/62255959: this forces libutis.so to dlopen vendor version of libutils.so
     //before minijail is on. This is dirty but required since some syscalls such
     //as pread64 are used by linker but aren't allowed in the minijail. By