Merge "aaudio: set buffer size to at least one burst"
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 09b85d5..691996b 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -287,3 +287,16 @@
     }
     return device->createCaptureSession(outputs, sessionParameters, callbacks, session);
 }
+
+EXPORT
+camera_status_t ACameraDevice_isSessionConfigurationSupported(
+        const ACameraDevice* device,
+        const ACaptureSessionOutputContainer* sessionOutputContainer) {
+    ATRACE_CALL();
+    if (device == nullptr || sessionOutputContainer == nullptr) {
+        ALOGE("%s: Error: invalid input: device %p, sessionOutputContainer %p",
+                __FUNCTION__, device, sessionOutputContainer);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return device->isSessionConfigurationSupported(sessionOutputContainer);
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 5e4fcd0..c9db01e 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -227,6 +227,55 @@
     return ACAMERA_OK;
 }
 
+camera_status_t CameraDevice::isSessionConfigurationSupported(
+        const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+    Mutex::Autolock _l(mDeviceLock);
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        return ret;
+    }
+
+    SessionConfiguration sessionConfiguration(0 /*inputWidth*/, 0 /*inputHeight*/,
+            -1 /*inputFormat*/, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE);
+    for (const auto& output : sessionOutputContainer->mOutputs) {
+        sp<IGraphicBufferProducer> iGBP(nullptr);
+        ret = getIGBPfromAnw(output.mWindow, iGBP);
+        if (ret != ACAMERA_OK) {
+            ALOGE("Camera device %s failed to extract graphic producer from native window",
+                    getId());
+            return ret;
+        }
+
+        String16 physicalId16(output.mPhysicalCameraId.c_str());
+        OutputConfiguration outConfig(iGBP, output.mRotation, physicalId16,
+                OutputConfiguration::INVALID_SET_ID, true);
+
+        for (auto& anw : output.mSharedWindows) {
+            ret = getIGBPfromAnw(anw, iGBP);
+            if (ret != ACAMERA_OK) {
+                ALOGE("Camera device %s failed to extract graphic producer from native window",
+                        getId());
+                return ret;
+            }
+            outConfig.addGraphicProducer(iGBP);
+        }
+
+        sessionConfiguration.addOutputConfiguration(outConfig);
+    }
+
+    bool supported = false;
+    binder::Status remoteRet = mRemote->isSessionConfigurationSupported(
+            sessionConfiguration, &supported);
+    if (remoteRet.serviceSpecificErrorCode() ==
+            hardware::ICameraService::ERROR_INVALID_OPERATION) {
+        return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+    } else if (!remoteRet.isOk()) {
+        return ACAMERA_ERROR_UNKNOWN;
+    } else {
+        return supported ? ACAMERA_OK : ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
+    }
+}
+
 camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
     camera_status_t ret = checkCameraClosedOrErrorLocked();
     if (ret != ACAMERA_OK) {
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 103efd5..56741ce 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -35,6 +35,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <camera/CaptureResult.h>
 #include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/SessionConfiguration.h>
 #include <camera/camera2/CaptureRequest.h>
 
 #include <camera/NdkCameraManager.h>
@@ -77,6 +78,9 @@
             const ACameraCaptureSession_stateCallbacks* callbacks,
             /*out*/ACameraCaptureSession** session);
 
+    camera_status_t isSessionConfigurationSupported(
+            const ACaptureSessionOutputContainer* sessionOutputContainer) const;
+
     // Callbacks from camera service
     class ServiceCallback : public hardware::camera2::BnCameraDeviceCallbacks {
       public:
@@ -369,6 +373,11 @@
         return mDevice->createCaptureSession(outputs, sessionParameters, callbacks, session);
     }
 
+    camera_status_t isSessionConfigurationSupported(
+            const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+        return mDevice->isSessionConfigurationSupported(sessionOutputContainer);
+    }
+
     /***********************
      * Device interal APIs *
      ***********************/
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index cedf83a..bc544e3 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -845,6 +845,43 @@
         const ACameraIdList* physicalIdList,
         /*out*/ACaptureRequest** request) __INTRODUCED_IN(29);
 
+/**
+ * Check whether a particular {@ACaptureSessionOutputContainer} is supported by
+ * the camera device.
+ *
+ * <p>This method performs a runtime check of a given {@link
+ * ACaptureSessionOutputContainer}. The result confirms whether or not the
+ * passed CaptureSession outputs can be successfully used to create a camera
+ * capture session using {@link ACameraDevice_createCaptureSession}.</p>
+ *
+ * <p>This method can be called at any point before, during and after active
+ * capture session. It must not impact normal camera behavior in any way and
+ * must complete significantly faster than creating a capture session.</p>
+ *
+ * <p>Although this method is faster than creating a new capture session, it is not intended
+ * to be used for exploring the entire space of supported stream combinations.</p>
+ *
+ * @param device the camera device of interest
+ * @param sessionOutputContainer the {@link ACaptureSessionOutputContainer} of
+ *                               interest.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the given {@link ACaptureSessionOutputContainer}
+ *                                is supported by the camera device.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if device, or sessionOutputContainer
+ *                                                     is NULL.</li>
+ *         <li>{@link ACAMERA_ERROR_STREAM_CONFIGURE_FAIL} if the given
+ *                                                         {@link ACaptureSessionOutputContainer}
+ *                                                         is not supported by
+ *                                                         the camera
+ *                                                         device.</li>
+ *        <li>{@link ACAMERA_ERROR_UNSUPPORTED_OPERATION} if the query operation is not
+ *                                                        supported by the camera device.</li>
+ */
+camera_status_t ACameraDevice_isSessionConfigurationSupported(
+        const ACameraDevice* device,
+        const ACaptureSessionOutputContainer* sessionOutputContainer) __INTRODUCED_IN(29);
+
 #endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
diff --git a/camera/ndk/include/camera/NdkCameraError.h b/camera/ndk/include/camera/NdkCameraError.h
index 6b58155..fc618ee 100644
--- a/camera/ndk/include/camera/NdkCameraError.h
+++ b/camera/ndk/include/camera/NdkCameraError.h
@@ -106,7 +106,8 @@
 
     /**
      * Camera device does not support the stream configuration provided by application in
-     * {@link ACameraDevice_createCaptureSession}.
+     * {@link ACameraDevice_createCaptureSession} or {@link
+     * ACameraDevice_isSessionConfigurationSupported}.
      */
     ACAMERA_ERROR_STREAM_CONFIGURE_FAIL = ACAMERA_ERROR_BASE - 9,
 
@@ -130,6 +131,11 @@
      * The application does not have permission to open camera.
      */
     ACAMERA_ERROR_PERMISSION_DENIED     = ACAMERA_ERROR_BASE - 13,
+
+    /**
+     * The operation is not supported by the camera device.
+     */
+    ACAMERA_ERROR_UNSUPPORTED_OPERATION = ACAMERA_ERROR_BASE - 14,
 } camera_status_t;
 
 #endif /* __ANDROID_API__ >= 24 */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 946a98e..b6f1553 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -14,6 +14,7 @@
     ACameraDevice_createCaptureRequest_withPhysicalIds; # introduced=29
     ACameraDevice_createCaptureSession;
     ACameraDevice_createCaptureSessionWithSessionParameters; # introduced=28
+    ACameraDevice_isSessionConfigurationSupported; # introduced=29
     ACameraDevice_getId;
     ACameraManager_create;
     ACameraManager_delete;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index a38a31e..d7d774b 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -38,6 +38,7 @@
 
 using HCameraMetadata = frameworks::cameraservice::device::V2_0::CameraMetadata;
 using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
+using SessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
 using hardware::Void;
 
 // Static member definitions
@@ -216,6 +217,47 @@
     return ACAMERA_OK;
 }
 
+camera_status_t CameraDevice::isSessionConfigurationSupported(
+        const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+    Mutex::Autolock _l(mDeviceLock);
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        return ret;
+    }
+
+    SessionConfiguration sessionConfig;
+    sessionConfig.inputWidth = 0;
+    sessionConfig.inputHeight = 0;
+    sessionConfig.inputFormat = -1;
+    sessionConfig.operationMode = StreamConfigurationMode::NORMAL_MODE;
+    sessionConfig.outputStreams.resize(sessionOutputContainer->mOutputs.size());
+    size_t index = 0;
+    for (const auto& output : sessionOutputContainer->mOutputs) {
+        sessionConfig.outputStreams[index].rotation = utils::convertToHidl(output.mRotation);
+        sessionConfig.outputStreams[index].windowGroupId = -1;
+        sessionConfig.outputStreams[index].windowHandles.resize(output.mSharedWindows.size() + 1);
+        sessionConfig.outputStreams[index].windowHandles[0] = output.mWindow;
+        sessionConfig.outputStreams[index].physicalCameraId = output.mPhysicalCameraId;
+        index++;
+    }
+
+    bool configSupported = false;
+    Status status = Status::NO_ERROR;
+    auto remoteRet = mRemote->isSessionConfigurationSupported(sessionConfig,
+        [&status, &configSupported](auto s, auto supported) {
+            status = s;
+            configSupported = supported;
+        });
+
+    if (status == Status::INVALID_OPERATION) {
+        return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+    } else if (!remoteRet.isOk()) {
+        return ACAMERA_ERROR_UNKNOWN;
+    } else {
+        return configSupported ? ACAMERA_OK : ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
+    }
+}
+
 void CameraDevice::addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
         sp<CaptureRequest> &req) {
     CameraMetadata metadataCopy = aCaptureRequest->settings->getInternalData();
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 28092fd..47e6f56 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -101,6 +101,9 @@
             const ACameraCaptureSession_stateCallbacks* callbacks,
             /*out*/ACameraCaptureSession** session);
 
+    camera_status_t isSessionConfigurationSupported(
+            const ACaptureSessionOutputContainer* sessionOutputContainer) const;
+
     // Callbacks from camera service
     class ServiceCallback : public ICameraDeviceCallback {
       public:
@@ -397,6 +400,11 @@
         return mDevice->createCaptureSession(outputs, sessionParameters, callbacks, session);
     }
 
+    camera_status_t isSessionConfigurationSupported(
+            const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+        return mDevice->isSessionConfigurationSupported(sessionOutputContainer);
+    }
+
     /***********************
      * Device interal APIs *
      ***********************/
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 2398922..c51f93b 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -121,6 +121,12 @@
         cameraIdList.numCameras = idPointerList.size();
         cameraIdList.cameraIds = idPointerList.data();
 
+        ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs);
+        if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION) {
+            ALOGE("ACameraDevice_isSessionConfigurationSupported failed, ret=%d", ret);
+            return ret;
+        }
+
         ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
         if (ret != AMEDIA_OK) {
             ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
diff --git a/media/codec2/components/base/Android.bp b/media/codec2/components/base/Android.bp
index 78a444b..f10835f 100644
--- a/media/codec2/components/base/Android.bp
+++ b/media/codec2/components/base/Android.bp
@@ -36,13 +36,18 @@
     ldflags: ["-Wl,-Bsymbolic"],
 }
 
+filegroup {
+    name: "codec2_soft_exports",
+    srcs: [ "exports.lds" ],
+}
+
 // public dependency for software codec implementation
 // to be used by code under media/codecs/* only as its stability is not guaranteed
 cc_defaults {
     name: "libcodec2_soft-defaults",
     defaults: ["libcodec2-impl-defaults"],
     vendor_available: true,
-
+    version_script: ":codec2_soft_exports",
     export_shared_lib_headers: [
         "libsfplugin_ccodec_utils",
     ],
diff --git a/media/codec2/components/base/exports.lds b/media/codec2/components/base/exports.lds
new file mode 100644
index 0000000..641bae8
--- /dev/null
+++ b/media/codec2/components/base/exports.lds
@@ -0,0 +1,7 @@
+{
+    global:
+        CreateCodec2Factory;
+        DestroyCodec2Factory;
+    local: *;
+};
+
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 7045b6a..402d9aa 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -94,6 +94,20 @@
 
         // matches limits in codec library
         addParameter(
+            DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
+                .withDefault(new C2StreamBitrateModeTuning::output(
+                        0u, C2Config::BITRATE_VARIABLE))
+                .withFields({
+                    C2F(mBitrateMode, value).oneOf({
+                        C2Config::BITRATE_CONST,
+                        C2Config::BITRATE_VARIABLE,
+                        C2Config::BITRATE_IGNORE})
+                })
+                .withSetter(
+                    Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
+                .build());
+
+        addParameter(
             DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
                 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
                 .withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
@@ -102,6 +116,20 @@
 
         // matches levels allowed within codec library
         addParameter(
+                DefineParam(mComplexity, C2_PARAMKEY_COMPLEXITY)
+                .withDefault(new C2StreamComplexityTuning::output(0u, 0))
+                .withFields({C2F(mComplexity, value).inRange(0, 10)})
+                .withSetter(Setter<decltype(*mComplexity)>::NonStrictValueWithNoDeps)
+                .build());
+
+        addParameter(
+                DefineParam(mQuality, C2_PARAMKEY_QUALITY)
+                .withDefault(new C2StreamQualityTuning::output(0u, 80))
+                .withFields({C2F(mQuality, value).inRange(0, 100)})
+                .withSetter(Setter<decltype(*mQuality)>::NonStrictValueWithNoDeps)
+                .build());
+
+        addParameter(
             DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
                 .withDefault(new C2StreamProfileLevelInfo::output(
                     0u, PROFILE_HEVC_MAIN, LEVEL_HEVC_MAIN_1))
@@ -287,12 +315,21 @@
     std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const {
         return mFrameRate;
     }
+    std::shared_ptr<C2StreamBitrateModeTuning::output> getBitrateMode_l() const {
+        return mBitrateMode;
+    }
     std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const {
         return mBitrate;
     }
     std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const {
         return mRequestSync;
     }
+    std::shared_ptr<C2StreamComplexityTuning::output> getComplexity_l() const {
+        return mComplexity;
+    }
+    std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
+        return mQuality;
+    }
 
    private:
     std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
@@ -304,6 +341,9 @@
     std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
     std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
+    std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
+    std::shared_ptr<C2StreamQualityTuning::output> mQuality;
     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
     std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
 };
@@ -387,6 +427,19 @@
     work->workletsProcessed = 1u;
 }
 
+static int getQpFromQuality(int quality) {
+    int qp;
+#define MIN_QP 4
+#define MAX_QP 50
+    /* Quality: 100 -> Qp : MIN_QP
+     * Quality: 0 -> Qp : MAX_QP
+     * Qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
+     */
+    qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
+    qp = std::min(qp, MAX_QP);
+    qp = std::max(qp, MIN_QP);
+    return qp;
+}
 c2_status_t C2SoftHevcEnc::initEncParams() {
     mCodecCtx = nullptr;
     mNumCores = std::min(GetCPUCoreCount(), (size_t) CODEC_MAX_CORES);
@@ -416,9 +469,37 @@
     mIvVideoColorFormat = IV_YUV_420P;
     mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
     mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
-    mEncParams.s_config_prms.i4_rate_control_mode = 2;
     mEncParams.s_lap_prms.i4_rc_look_ahead_pics = 0;
 
+    switch (mBitrateMode->value) {
+        case C2Config::BITRATE_IGNORE:
+            mEncParams.s_config_prms.i4_rate_control_mode = 3;
+            mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
+                getQpFromQuality(mQuality->value);
+            break;
+        case C2Config::BITRATE_CONST:
+            mEncParams.s_config_prms.i4_rate_control_mode = 5;
+            break;
+        case C2Config::BITRATE_VARIABLE:
+            [[fallthrough]];
+        default:
+            mEncParams.s_config_prms.i4_rate_control_mode = 2;
+            break;
+        break;
+    }
+
+    if (mComplexity->value == 10) {
+        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P0;
+    } else if (mComplexity->value >= 8) {
+        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P2;
+    } else if (mComplexity->value >= 7) {
+        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P3;
+    } else if (mComplexity->value >= 5) {
+        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P4;
+    } else {
+        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
+    }
+
     return C2_OK;
 }
 
@@ -447,11 +528,14 @@
     {
         IntfImpl::Lock lock = mIntf->lock();
         mSize = mIntf->getSize_l();
+        mBitrateMode = mIntf->getBitrateMode_l();
         mBitrate = mIntf->getBitrate_l();
         mFrameRate = mIntf->getFrameRate_l();
         mHevcEncProfile = mIntf->getProfile_l();
         mHevcEncLevel = mIntf->getLevel_l();
         mIDRInterval = mIntf->getSyncFramePeriod_l();
+        mComplexity = mIntf->getComplexity_l();
+        mQuality = mIntf->getQuality_l();
     }
 
     c2_status_t status = initEncParams();
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index 9d90b95..8569a3e 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -77,6 +77,9 @@
     std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
     std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
+    std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
+    std::shared_ptr<C2StreamQualityTuning::output> mQuality;
 
 #ifdef FILE_DUMP_ENABLE
     char mInFile[200];
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index f5aa65b..97dde71 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -27,15 +27,18 @@
 
     shared_libs: [
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.media@1.0",
         "android.hardware.media.bufferpool@2.0",
         "android.hardware.media.c2@1.0",
         "android.hardware.media.omx@1.0",
+        "android.hidl.safe_union@1.0",
         "libbase",
         "libcodec2",
         "libcodec2_vndk",
         "libcutils",
+        "libgui",
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index f3bf6f7..5897dce 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -272,7 +272,7 @@
 
 Return<Status> Component::setOutputSurface(
         uint64_t blockPoolId,
-        const sp<HGraphicBufferProducer>& surface) {
+        const sp<HGraphicBufferProducer2>& surface) {
     std::shared_ptr<C2BlockPool> pool;
     GetCodec2BlockPool(blockPoolId, mComponent, &pool);
     if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
@@ -312,7 +312,7 @@
 }
 
 Return<void> Component::connectToOmxInputSurface(
-        const sp<HGraphicBufferProducer>& producer,
+        const sp<HGraphicBufferProducer1>& producer,
         const sp<::android::hardware::media::omx::V1_0::
         IGraphicBufferSource>& source,
         connectToOmxInputSurface_cb _hidl_cb) {
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index bb5faa5..53bb6d2 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -23,7 +23,7 @@
 #include <codec2/hidl/1.0/types.h>
 
 #include <android-base/file.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 #include <utils/Errors.h>
 
@@ -219,13 +219,11 @@
         _hidl_cb(Status::CORRUPTED, nullptr);
         return Void();
     }
-    typedef ::android::hardware::graphics::bufferqueue::V1_0::
-            IGraphicBufferProducer HGbp;
-    typedef ::android::TWGraphicBufferProducer<HGbp> B2HGbp;
     sp<InputSurface> inputSurface = new InputSurface(
             this,
             std::make_shared<C2ReflectorHelper>(),
-            new B2HGbp(source->getIGraphicBufferProducer()),
+            new ::android::hardware::graphics::bufferqueue::V2_0::utils::
+                B2HGraphicBufferProducer(source->getIGraphicBufferProducer()),
             source);
     _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
              inputSurface);
diff --git a/media/codec2/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index 85c44c3..2b4ca85 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -151,8 +151,6 @@
     return Void();
 }
 
-// Derived methods from IGraphicBufferProducer
-
 // Constructor is exclusive to ComponentStore.
 InputSurface::InputSurface(
         const sp<ComponentStore>& store,
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
index e444013..86dccd0 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
@@ -68,7 +68,9 @@
     c2_status_t status() const;
 
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
-            IGraphicBufferProducer HGraphicBufferProducer;
+            IGraphicBufferProducer HGraphicBufferProducer1;
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer2;
 
     // Methods from IComponent follow.
     virtual Return<Status> queue(const WorkBundle& workBundle) override;
@@ -76,12 +78,12 @@
     virtual Return<Status> drain(bool withEos) override;
     virtual Return<Status> setOutputSurface(
             uint64_t blockPoolId,
-            const sp<HGraphicBufferProducer>& surface) override;
+            const sp<HGraphicBufferProducer2>& surface) override;
     virtual Return<void> connectToInputSurface(
             const sp<IInputSurface>& inputSurface,
             connectToInputSurface_cb _hidl_cb) override;
     virtual Return<void> connectToOmxInputSurface(
-            const sp<HGraphicBufferProducer>& producer,
+            const sp<HGraphicBufferProducer1>& producer,
             const sp<::android::hardware::media::omx::V1_0::
             IGraphicBufferSource>& source,
             connectToOmxInputSurface_cb _hidl_cb) override;
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index 2682c13..34ea959 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -19,7 +19,7 @@
 
 #include <codec2/hidl/1.0/ComponentStore.h>
 
-#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 #include <android/hardware/media/c2/1.0/IInputSink.h>
 #include <android/hardware/media/c2/1.0/IInputSurface.h>
 #include <gui/IGraphicBufferProducer.h>
@@ -44,7 +44,7 @@
 
 struct InputSurface : public IInputSurface {
 
-    typedef ::android::hardware::graphics::bufferqueue::V1_0::
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
             IGraphicBufferProducer HGraphicBufferProducer;
 
     typedef ::android::
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index b9f3aa8..817d148 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -22,6 +22,7 @@
 #include <android/hardware/media/bufferpool/2.0/types.h>
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
 #include <android/hardware/media/c2/1.0/types.h>
+#include <android/hidl/safe_union/1.0/types.h>
 #include <gui/IGraphicBufferProducer.h>
 
 #include <C2Component.h>
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 343bcb5..74320e7 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -18,9 +18,9 @@
 #define LOG_TAG "Codec2-types"
 #include <android-base/logging.h>
 
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 #include <codec2/hidl/1.0/types.h>
-
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
 #include <media/stagefright/foundation/AUtils.h>
 
 #include <C2AllocatorIon.h>
@@ -46,7 +46,6 @@
 namespace V1_0 {
 namespace utils {
 
-using namespace ::android;
 using ::android::hardware::Return;
 using ::android::hardware::media::bufferpool::BufferPoolData;
 using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
@@ -55,7 +54,10 @@
         ClientManager;
 using ::android::hardware::media::bufferpool::V2_0::implementation::
         TransactionId;
-using ::android::TWGraphicBufferProducer;
+using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+        V2_0::IGraphicBufferProducer;
+using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+        V2_0::utils::B2HGraphicBufferProducer;
 
 const char* asString(Status status, const char* def) {
     return asString(static_cast<c2_status_t>(status), def);
@@ -118,9 +120,9 @@
     return true;
 }
 
-// C2FieldSupportedValues::range's type -> FieldSupportedValues::Range
+// C2FieldSupportedValues::range's type -> ValueRange
 bool objcpy(
-        FieldSupportedValues::Range* d,
+        ValueRange* d,
         const decltype(C2FieldSupportedValues::range)& s) {
     d->min = static_cast<PrimitiveValue>(s.min.u64);
     d->max = static_cast<PrimitiveValue>(s.max.u64);
@@ -133,45 +135,45 @@
 // C2FieldSupportedValues -> FieldSupportedValues
 bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
     switch (s.type) {
-    case C2FieldSupportedValues::EMPTY:
-        d->type = FieldSupportedValues::Type::EMPTY;
-        d->values.resize(0);
-        break;
-    case C2FieldSupportedValues::RANGE:
-        d->type = FieldSupportedValues::Type::RANGE;
-        if (!objcpy(&d->range, s.range)) {
-            LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
-            return false;
+    case C2FieldSupportedValues::EMPTY: {
+            d->empty(::android::hidl::safe_union::V1_0::Monostate{});
+            break;
         }
-        d->values.resize(0);
-        break;
-    default:
-        switch (s.type) {
-        case C2FieldSupportedValues::VALUES:
-            d->type = FieldSupportedValues::Type::VALUES;
-            break;
-        case C2FieldSupportedValues::FLAGS:
-            d->type = FieldSupportedValues::Type::FLAGS;
-            break;
-        default:
-            LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
-                       << "with underlying value " << underlying_value(s.type)
-                       << ".";
-            d->type = static_cast<FieldSupportedValues::Type>(s.type);
-            if (!objcpy(&d->range, s.range)) {
+    case C2FieldSupportedValues::RANGE: {
+            ValueRange range{};
+            if (!objcpy(&range, s.range)) {
                 LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+                d->range(range);
                 return false;
             }
+            d->range(range);
+            break;
         }
-        copyVector<uint64_t>(&d->values, s.values);
+    case C2FieldSupportedValues::VALUES: {
+            hidl_vec<PrimitiveValue> values;
+            copyVector<uint64_t>(&values, s.values);
+            d->values(values);
+            break;
+        }
+    case C2FieldSupportedValues::FLAGS: {
+            hidl_vec<PrimitiveValue> flags;
+            copyVector<uint64_t>(&flags, s.values);
+            d->flags(flags);
+            break;
+        }
+    default:
+        LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+                   << "with underlying value " << underlying_value(s.type)
+                   << ".";
+        return false;
     }
     return true;
 }
 
-// FieldSupportedValues::Range -> C2FieldSupportedValues::range's type
+// ValueRange -> C2FieldSupportedValues::range's type
 bool objcpy(
         decltype(C2FieldSupportedValues::range)* d,
-        const FieldSupportedValues::Range& s) {
+        const ValueRange& s) {
     d->min.u64 = static_cast<uint64_t>(s.min);
     d->max.u64 = static_cast<uint64_t>(s.max);
     d->step.u64 = static_cast<uint64_t>(s.step);
@@ -182,37 +184,33 @@
 
 // FieldSupportedValues -> C2FieldSupportedValues
 bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
-    switch (s.type) {
-    case FieldSupportedValues::Type::EMPTY:
-        d->type = C2FieldSupportedValues::EMPTY;
-        break;
-    case FieldSupportedValues::Type::RANGE:
-        d->type = C2FieldSupportedValues::RANGE;
-        if (!objcpy(&d->range, s.range)) {
-            LOG(ERROR) << "Invalid FieldSupportedValues::range.";
-            return false;
+    switch (s.getDiscriminator()) {
+    case FieldSupportedValues::hidl_discriminator::empty: {
+            d->type = C2FieldSupportedValues::EMPTY;
+            break;
         }
-        d->values.resize(0);
-        break;
-    default:
-        switch (s.type) {
-        case FieldSupportedValues::Type::VALUES:
-            d->type = C2FieldSupportedValues::VALUES;
-            break;
-        case FieldSupportedValues::Type::FLAGS:
-            d->type = C2FieldSupportedValues::FLAGS;
-            break;
-        default:
-            LOG(DEBUG) << "Unrecognized FieldSupportedValues::Type "
-                       << "with underlying value " << underlying_value(s.type)
-                       << ".";
-            d->type = static_cast<C2FieldSupportedValues::type_t>(s.type);
-            if (!objcpy(&d->range, s.range)) {
+    case FieldSupportedValues::hidl_discriminator::range: {
+            d->type = C2FieldSupportedValues::RANGE;
+            if (!objcpy(&d->range, s.range())) {
                 LOG(ERROR) << "Invalid FieldSupportedValues::range.";
                 return false;
             }
+            d->values.resize(0);
+            break;
         }
-        copyVector<uint64_t>(&d->values, s.values);
+    case FieldSupportedValues::hidl_discriminator::values: {
+            d->type = C2FieldSupportedValues::VALUES;
+            copyVector<uint64_t>(&d->values, s.values());
+            break;
+        }
+    case FieldSupportedValues::hidl_discriminator::flags: {
+            d->type = C2FieldSupportedValues::FLAGS;
+            copyVector<uint64_t>(&d->values, s.flags());
+            break;
+        }
+    default:
+        LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+        return false;
     }
     return true;
 }
@@ -1806,7 +1804,7 @@
     sp<HGraphicBufferProducer> hgbp =
             igbp->getHalInterface<HGraphicBufferProducer>();
     return hgbp ? hgbp :
-            new TWGraphicBufferProducer<HGraphicBufferProducer>(igbp);
+            new B2HGraphicBufferProducer(igbp);
 }
 
 } // unnamed namespace
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index 1f36270..d73b731 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -127,4 +127,12 @@
             queueCondition.notify_all();
         }
     }
-}
\ No newline at end of file
+}
+
+// Return current time in micro seconds
+int64_t getNowUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
+}
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index fca2902..c577dac 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -201,4 +201,6 @@
     std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
     uint32_t& framesReceived);
 
+int64_t getNowUs();
+
 #endif  // MEDIA_C2_HIDL_TEST_COMMON_H
diff --git a/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
index ec803d7..74548b5 100644
--- a/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
@@ -26,6 +26,32 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include "media_c2_hidl_test_common.h"
 
+/* Time_Out for start(), stop(), reset(), release(), flush(), queue() are
+ * defined in hardware/interfaces/media/c2/1.0/IComponent.hal. Adding 50ms
+ * extra in case of timeout is 500ms, 1ms extra in case timeout is 1ms/5ms. All
+ * timeout is calculated in us.
+ */
+#define START_TIME_OUT                  550000
+#define STOP_TIME_OUT                   550000
+#define RESET_TIME_OUT                  550000
+#define RELEASE_TIME_OUT                550000
+#define FLUSH_TIME_OUT                  6000
+#define QUEUE_TIME_OUT                  2000
+
+// Time_Out for config(), query(), querySupportedParams() are defined in
+// hardware/interfaces/media/c2/1.0/IConfigurable.hal.
+#define CONFIG_TIME_OUT                 6000
+#define QUERY_TIME_OUT                  6000
+#define QUERYSUPPORTEDPARAMS_TIME_OUT   2000
+
+#define CHECK_TIMEOUT(timeConsumed, TIME_OUT, FuncName)          \
+    if (timeConsumed > TIME_OUT) {                               \
+        ALOGW(                                                   \
+            "TIMED_OUT %s  timeConsumed=%" PRId64 " us is "      \
+            "greater than threshold %d us",                      \
+            FuncName, timeConsumed, TIME_OUT);                   \
+    }
+
 static ComponentTestEnvironment* gEnv = nullptr;
 
 namespace {
@@ -244,6 +270,93 @@
     std::make_pair(C2FrameData::FLAG_CODEC_CONFIG, false),
     std::make_pair(C2FrameData::FLAG_END_OF_STREAM, false)));
 
+// Test API's Timeout
+TEST_F(Codec2ComponentHidlTest, Timeout) {
+    ALOGV("Timeout Test");
+    c2_status_t err = C2_OK;
+
+    int64_t startTime = getNowUs();
+    err = mComponent->start();
+    int64_t timeConsumed = getNowUs() - startTime;
+    CHECK_TIMEOUT(timeConsumed, START_TIME_OUT, "start()");
+    ALOGV("mComponent->start() timeConsumed=%" PRId64 " us", timeConsumed);
+    ASSERT_EQ(err, C2_OK);
+
+    startTime = getNowUs();
+    err = mComponent->reset();
+    timeConsumed = getNowUs() - startTime;
+    CHECK_TIMEOUT(timeConsumed, RESET_TIME_OUT, "reset()");
+    ALOGV("mComponent->reset() timeConsumed=%" PRId64 " us", timeConsumed);
+    ASSERT_EQ(err, C2_OK);
+
+    err = mComponent->start();
+    ASSERT_EQ(err, C2_OK);
+
+    // Query supported params by the component
+    std::vector<std::shared_ptr<C2ParamDescriptor>> params;
+    startTime = getNowUs();
+    err = mComponent->querySupportedParams(&params);
+    timeConsumed = getNowUs() - startTime;
+    CHECK_TIMEOUT(timeConsumed, QUERYSUPPORTEDPARAMS_TIME_OUT,
+                  "querySupportedParams()");
+    ALOGV("mComponent->querySupportedParams() timeConsumed=%" PRId64 " us",
+          timeConsumed);
+    ASSERT_EQ(err, C2_OK);
+
+    std::vector<std::unique_ptr<C2Param>> queried;
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    // Query and config all the supported params
+    for (std::shared_ptr<C2ParamDescriptor> p : params) {
+        startTime = getNowUs();
+        err = mComponent->query({}, {p->index()}, C2_DONT_BLOCK, &queried);
+        timeConsumed = getNowUs() - startTime;
+        CHECK_TIMEOUT(timeConsumed, QUERY_TIME_OUT, "query()");
+        EXPECT_NE(queried.size(), 0u);
+        EXPECT_EQ(err, C2_OK);
+        ALOGV("mComponent->query() for %s timeConsumed=%" PRId64 " us",
+              p->name().c_str(), timeConsumed);
+
+        startTime = getNowUs();
+        err = mComponent->config({queried[0].get()}, C2_DONT_BLOCK, &failures);
+        timeConsumed = getNowUs() - startTime;
+        CHECK_TIMEOUT(timeConsumed, CONFIG_TIME_OUT, "config()");
+        ASSERT_EQ(err, C2_OK);
+        ASSERT_EQ(failures.size(), 0u);
+        ALOGV("mComponent->config() for %s timeConsumed=%" PRId64 " us",
+              p->name().c_str(), timeConsumed);
+    }
+
+    std::list<std::unique_ptr<C2Work>> workList;
+    startTime = getNowUs();
+    err = mComponent->queue(&workList);
+    timeConsumed = getNowUs() - startTime;
+    ALOGV("mComponent->queue() timeConsumed=%" PRId64 " us", timeConsumed);
+    CHECK_TIMEOUT(timeConsumed, QUEUE_TIME_OUT, "queue()");
+    ASSERT_EQ(err, C2_OK);
+
+    startTime = getNowUs();
+    err = mComponent->flush(C2Component::FLUSH_COMPONENT, &workList);
+    timeConsumed = getNowUs() - startTime;
+    ALOGV("mComponent->flush() timeConsumed=%" PRId64 " us", timeConsumed);
+    CHECK_TIMEOUT(timeConsumed, FLUSH_TIME_OUT, "flush()");
+    ASSERT_EQ(err, C2_OK);
+
+    startTime = getNowUs();
+    err = mComponent->stop();
+    timeConsumed = getNowUs() - startTime;
+    ALOGV("mComponent->stop() timeConsumed=%" PRId64 " us", timeConsumed);
+    CHECK_TIMEOUT(timeConsumed, STOP_TIME_OUT, "stop()");
+    ASSERT_EQ(err, C2_OK);
+
+    startTime = getNowUs();
+    err = mComponent->release();
+    timeConsumed = getNowUs() - startTime;
+    ALOGV("mComponent->release() timeConsumed=%" PRId64 " us", timeConsumed);
+    CHECK_TIMEOUT(timeConsumed, RELEASE_TIME_OUT, "release()");
+    ASSERT_EQ(err, C2_OK);
+
+}
+
 }  // anonymous namespace
 
 // TODO: Add test for Invalid work,
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 7a2e549..0fe8376 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -29,9 +29,9 @@
 #include <android-base/properties.h>
 #include <bufferpool/ClientManager.h>
 #include <cutils/native_handle.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
 #include <hidl/HidlSupport.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
 #include <android/hardware/media/c2/1.0/IComponent.h>
@@ -50,13 +50,21 @@
 using ::android::hardware::hidl_string;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::TWGraphicBufferProducer;
 
 using namespace ::android::hardware::media::c2::V1_0;
 using namespace ::android::hardware::media::c2::V1_0::utils;
 using namespace ::android::hardware::media::bufferpool::V2_0;
 using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
 
+using HGraphicBufferProducer1 = ::android::hardware::graphics::bufferqueue::
+        V1_0::IGraphicBufferProducer;
+using HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
+        V2_0::IGraphicBufferProducer;
+using B2HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
+        V2_0::utils::B2HGraphicBufferProducer;
+using H2BGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
+        V2_0::utils::H2BGraphicBufferProducer;
+
 namespace /* unnamed */ {
 
 // c2_status_t value that corresponds to hwbinder transaction failure.
@@ -1064,11 +1072,11 @@
         C2BlockPool::local_id_t blockPoolId,
         const sp<IGraphicBufferProducer>& surface,
         uint32_t generation) {
-    sp<HGraphicBufferProducer> igbp =
-            surface->getHalInterface<HGraphicBufferProducer>();
+    sp<HGraphicBufferProducer2> igbp =
+            surface->getHalInterface<HGraphicBufferProducer2>();
 
     if (!igbp) {
-        igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
+        igbp = new B2HGraphicBufferProducer2(surface);
     }
 
     Return<Status> transStatus = mBase->setOutputSurface(
@@ -1195,7 +1203,7 @@
 }
 
 c2_status_t Codec2Client::Component::connectToOmxInputSurface(
-        const sp<HGraphicBufferProducer>& producer,
+        const sp<HGraphicBufferProducer1>& producer,
         const sp<HGraphicBufferSource>& source,
         std::shared_ptr<InputSurfaceConnection>* connection) {
     c2_status_t status;
@@ -1284,12 +1292,11 @@
         },
         mBase{base},
         mGraphicBufferProducer{new
-            ::android::hardware::graphics::bufferqueue::V1_0::utils::
-            H2BGraphicBufferProducer([base]() -> sp<HGraphicBufferProducer> {
-                Return<sp<HGraphicBufferProducer>> transResult =
+            H2BGraphicBufferProducer2([base]() -> sp<HGraphicBufferProducer2> {
+                Return<sp<HGraphicBufferProducer2>> transResult =
                         base->getGraphicBufferProducer();
                 return transResult.isOk() ?
-                        static_cast<sp<HGraphicBufferProducer>>(transResult) :
+                        static_cast<sp<HGraphicBufferProducer2>>(transResult) :
                         nullptr;
             }())} {
 }
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 478ce6e..cd42205 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -63,55 +63,29 @@
  * Codec2Client are all subclasses of Configurable.
  */
 
-// Forward declaration of Codec2.0 HIDL interfaces
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
+// Forward declaration of relevant HIDL interfaces
+
+namespace android::hardware::media::c2::V1_0 {
 struct IConfigurable;
 struct IComponent;
 struct IComponentInterface;
 struct IComponentStore;
+struct IInputSink;
 struct IInputSurface;
 struct IInputSurfaceConnection;
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
+}  // namespace android::hardware::media::c2::V1_0
 
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V2_0 {
+namespace android::hardware::media::bufferpool::V2_0 {
 struct IClientManager;
-} // namespace V2_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
+}  // namespace android::hardware::media::bufferpool::V2_0
 
-// Forward declarations of other classes
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace bufferqueue {
-namespace V1_0 {
+namespace android::hardware::graphics::bufferqueue::V1_0 {
 struct IGraphicBufferProducer;
-} // namespace V1_0
-} // namespace bufferqueue
-} // namespace graphics
-namespace media {
-namespace omx {
-namespace V1_0 {
+}  // android::hardware::graphics::bufferqueue::V1_0
+
+namespace android::hardware::media::omx::V1_0 {
 struct IGraphicBufferSource;
-} // namespace V1_0
-} // namespace omx
-} // namespace media
-} // namespace hardware
-} // namespace android
+}  // namespace android::hardware::media::omx::V1_0
 
 namespace android {
 
@@ -324,7 +298,9 @@
             QueueBufferOutput QueueBufferOutput;
 
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
-            IGraphicBufferProducer HGraphicBufferProducer;
+            IGraphicBufferProducer HGraphicBufferProducer1;
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer2;
     typedef ::android::hardware::media::omx::V1_0::
             IGraphicBufferSource HGraphicBufferSource;
 
@@ -362,7 +338,7 @@
             std::shared_ptr<InputSurfaceConnection>* connection);
 
     c2_status_t connectToOmxInputSurface(
-            const sp<HGraphicBufferProducer>& producer,
+            const sp<HGraphicBufferProducer1>& producer,
             const sp<HGraphicBufferSource>& source,
             std::shared_ptr<InputSurfaceConnection>* connection);
 
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 03d859a..962df0f 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -272,19 +272,14 @@
     work->input.buffers.clear();
     if (block) {
         std::shared_ptr<C2Buffer> c2Buffer(
-                // TODO: fence
                 new Buffer2D(block->share(
-                        C2Rect(block->width(), block->height()), ::C2Fence())),
-                [buffer, source = getSource()](C2Buffer *ptr) {
-                    delete ptr;
-                    // TODO: fence
-                    (void)source->onInputBufferEmptied(buffer, -1);
-                });
+                        C2Rect(block->width(), block->height()), ::C2Fence())));
         work->input.buffers.push_back(c2Buffer);
     }
     work->worklets.clear();
     work->worklets.emplace_back(new C2Worklet);
     std::list<std::unique_ptr<C2Work>> items;
+    uint64_t index = work->input.ordinal.frameIndex.peeku();
     items.push_back(std::move(work));
 
     c2_status_t err = comp->queue(&items);
@@ -292,6 +287,7 @@
         return UNKNOWN_ERROR;
     }
 
+    (void)mBufferIdsInUse.emplace(index, buffer);
     return OK;
 }
 
@@ -326,4 +322,18 @@
     mHeight = height;
 }
 
+void C2OMXNode::onInputBufferDone(c2_cntr64_t index) {
+    if (!mBufferSource) {
+        ALOGD("Buffer source not set (index=%llu)", index.peekull());
+        return;
+    }
+    auto it = mBufferIdsInUse.find(index.peeku());
+    if (it == mBufferIdsInUse.end()) {
+        ALOGV("Untracked input index %llu (maybe already removed)", index.peekull());
+        return;
+    }
+    (void)mBufferSource->onInputBufferEmptied(it->second, -1);
+    (void)mBufferIdsInUse.erase(it);
+}
+
 }  // namespace android
diff --git a/media/codec2/sfplugin/C2OMXNode.h b/media/codec2/sfplugin/C2OMXNode.h
index b5a815e..b7bd696 100644
--- a/media/codec2/sfplugin/C2OMXNode.h
+++ b/media/codec2/sfplugin/C2OMXNode.h
@@ -75,9 +75,23 @@
             OMX_INDEXTYPE *index) override;
     status_t dispatchMessage(const omx_message &msg) override;
 
+    /**
+     * Returns underlying IOMXBufferSource object.
+     */
     sp<IOMXBufferSource> getSource();
+
+    /**
+     * Configure the frame size.
+     */
     void setFrameSize(uint32_t width, uint32_t height);
 
+    /**
+     * Clean up work item reference.
+     *
+     * \param index input work index
+     */
+    void onInputBufferDone(c2_cntr64_t index);
+
 private:
     std::weak_ptr<Codec2Client::Component> mComp;
     sp<IOMXBufferSource> mBufferSource;
@@ -96,6 +110,8 @@
     bool mFirstInputFrame; // true for first input
     c2_cntr64_t mPrevInputTimestamp; // input timestamp for previous frame
     c2_cntr64_t mPrevCodecTimestamp; // adjusted (codec) timestamp for previous frame
+
+    std::map<uint64_t, buffer_id> mBufferIdsInUse;
 };
 
 }  // namespace android
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 2d10c67..8474ce8 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -271,9 +271,12 @@
             if (mNode != nullptr) {
                 OMX_PARAM_U32TYPE ptrGapParam = {};
                 ptrGapParam.nSize = sizeof(OMX_PARAM_U32TYPE);
-                ptrGapParam.nU32 = (config.mMinAdjustedFps > 0)
+                float gap = (config.mMinAdjustedFps > 0)
                         ? c2_min(INT32_MAX + 0., 1e6 / config.mMinAdjustedFps + 0.5)
                         : c2_max(0. - INT32_MAX, -1e6 / config.mFixedAdjustedFps - 0.5);
+                // float -> uint32_t is undefined if the value is negative.
+                // First convert to int32_t to ensure the expected behavior.
+                ptrGapParam.nU32 = int32_t(gap);
                 (void)mNode->setParameter(
                         (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
                         &ptrGapParam, sizeof(ptrGapParam));
@@ -282,7 +285,7 @@
 
         // max fps
         // TRICKY: we do not unset max fps to 0 unless using fixed fps
-        if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == 0))
+        if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == -1))
                 && config.mMaxFps != mConfig.mMaxFps) {
             status_t res = GetStatus(mSource->setMaxFps(config.mMaxFps));
             status << " maxFps=" << config.mMaxFps;
@@ -367,6 +370,10 @@
         return err;
     }
 
+    void onInputBufferDone(c2_cntr64_t index) override {
+        mNode->onInputBufferDone(index);
+    }
+
 private:
     sp<BGraphicBufferSource> mSource;
     sp<C2OMXNode> mNode;
@@ -739,10 +746,21 @@
                 return BAD_VALUE;
             }
             if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
-                if (!msg->findInt32(KEY_BIT_RATE, &i32)
-                        && !msg->findFloat(KEY_BIT_RATE, &flt)) {
-                    ALOGD("bitrate is missing, which is required for video encoders.");
-                    return BAD_VALUE;
+                C2Config::bitrate_mode_t mode = C2Config::BITRATE_VARIABLE;
+                if (msg->findInt32(KEY_BITRATE_MODE, &i32)) {
+                    mode = (C2Config::bitrate_mode_t) i32;
+                }
+                if (mode == BITRATE_MODE_CQ) {
+                    if (!msg->findInt32(KEY_QUALITY, &i32)) {
+                        ALOGD("quality is missing, which is required for video encoders in CQ.");
+                        return BAD_VALUE;
+                    }
+                } else {
+                    if (!msg->findInt32(KEY_BIT_RATE, &i32)
+                            && !msg->findFloat(KEY_BIT_RATE, &flt)) {
+                        ALOGD("bitrate is missing, which is required for video encoders.");
+                        return BAD_VALUE;
+                    }
                 }
                 if (!msg->findInt32(KEY_I_FRAME_INTERVAL, &i32)
                         && !msg->findFloat(KEY_I_FRAME_INTERVAL, &flt)) {
@@ -764,13 +782,16 @@
                 if (msg->findInt64(KEY_REPEAT_PREVIOUS_FRAME_AFTER, &value) && value > 0) {
                     config->mISConfig->mMinFps = 1e6 / value;
                 }
-                (void)msg->findFloat(
-                        KEY_MAX_FPS_TO_ENCODER, &config->mISConfig->mMaxFps);
+                if (!msg->findFloat(
+                        KEY_MAX_FPS_TO_ENCODER, &config->mISConfig->mMaxFps)) {
+                    config->mISConfig->mMaxFps = -1;
+                }
                 config->mISConfig->mMinAdjustedFps = 0;
                 config->mISConfig->mFixedAdjustedFps = 0;
                 if (msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &value)) {
                     if (value < 0 && value >= INT32_MIN) {
                         config->mISConfig->mFixedAdjustedFps = -1e6 / value;
+                        config->mISConfig->mMaxFps = -1;
                     } else if (value > 0 && value <= INT32_MAX) {
                         config->mISConfig->mMinAdjustedFps = 1e6 / value;
                     }
@@ -1566,6 +1587,13 @@
 
 void CCodec::onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) {
     mChannel->onInputBufferDone(frameIndex, arrayIndex);
+    if (arrayIndex == 0) {
+        // We always put no more than one buffer per work, if we use an input surface.
+        Mutexed<Config>::Locked config(mConfig);
+        if (config->mInputSurface) {
+            config->mInputSurface->onInputBufferDone(frameIndex);
+        }
+    }
 }
 
 void CCodec::onMessageReceived(const sp<AMessage> &msg) {
@@ -1698,6 +1726,9 @@
                     ++stream;
                 }
             }
+            if (config->mInputSurface) {
+                config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
+            }
             mChannel->onWorkDone(
                     std::move(work), changed ? config->mOutputFormat : nullptr,
                     initData.hasChanged() ? initData.update().get() : nullptr);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index fb6af93..d1fa920 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1525,6 +1525,7 @@
     mPending.splice(mPending.end(), mStash);
     mDepth = depth;
 }
+
 void CCodecBufferChannel::ReorderStash::setKey(C2Config::ordinal_key_t key) {
     mPending.splice(mPending.end(), mStash);
     mKey = key;
@@ -1547,13 +1548,25 @@
         int64_t timestamp,
         int32_t flags,
         const C2WorkOrdinalStruct &ordinal) {
-    auto it = mStash.begin();
-    for (; it != mStash.end(); ++it) {
-        if (less(ordinal, it->ordinal)) {
-            break;
+    bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
+    if (!buffer && eos) {
+        // TRICKY: we may be violating ordering of the stash here. Because we
+        // don't expect any more emplace() calls after this, the ordering should
+        // not matter.
+        mStash.emplace_back(buffer, timestamp, flags, ordinal);
+    } else {
+        flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
+        auto it = mStash.begin();
+        for (; it != mStash.end(); ++it) {
+            if (less(ordinal, it->ordinal)) {
+                break;
+            }
+        }
+        mStash.emplace(it, buffer, timestamp, flags, ordinal);
+        if (eos) {
+            mStash.back().flags = mStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
         }
     }
-    mStash.emplace(it, buffer, timestamp, flags, ordinal);
     while (!mStash.empty() && mStash.size() > mDepth) {
         mPending.push_back(mStash.front());
         mStash.pop_front();
@@ -2483,6 +2496,7 @@
             bool post = true;
             if (!configs->empty()) {
                 sp<ABuffer> config = configs->front();
+                configs->pop_front();
                 if (buffer->capacity() >= config->size()) {
                     memcpy(buffer->base(), config->data(), config->size());
                     buffer->setRange(0, config->size());
@@ -2593,9 +2607,9 @@
         return false;
     }
 
-    if (work->worklets.size() != 1u
+    if (mInputSurface == nullptr && (work->worklets.size() != 1u
             || !work->worklets.front()
-            || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE)) {
+            || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE))) {
         mPipelineWatcher.lock()->onWorkDone(work->input.ordinal.frameIndex.peeku());
     }
 
@@ -2709,6 +2723,10 @@
     c2_cntr64_t timestamp =
         worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
                 - work->input.ordinal.timestamp;
+    if (mInputSurface != nullptr) {
+        // When using input surface we need to restore the original input timestamp.
+        timestamp = work->input.ordinal.customOrdinal;
+    }
     ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
           mName,
           work->input.ordinal.customOrdinal.peekll(),
@@ -2810,8 +2828,9 @@
 
         outBuffer->meta()->setInt64("timeUs", entry.timestamp);
         outBuffer->meta()->setInt32("flags", entry.flags);
-        ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu",
-                mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size());
+        ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu (%lld)",
+                mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size(),
+                (long long)entry.timestamp);
         mCallback->onOutputBufferAvailable(index, outBuffer);
     }
 }
diff --git a/media/codec2/sfplugin/InputSurfaceWrapper.h b/media/codec2/sfplugin/InputSurfaceWrapper.h
index d9c4eec..8341fd5 100644
--- a/media/codec2/sfplugin/InputSurfaceWrapper.h
+++ b/media/codec2/sfplugin/InputSurfaceWrapper.h
@@ -98,6 +98,13 @@
         mDataSpace = dataSpace;
     }
 
+    /**
+     * Clean up C2Work related references if necessary. No-op by default.
+     *
+     * \param index index of input work.
+     */
+    virtual void onInputBufferDone(c2_cntr64_t /* index */) {}
+
 protected:
     android_dataspace mDataSpace;
 };
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 6da131f..d62944a 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -589,6 +589,21 @@
     bool mIsHdr10Plus;
 };
 
+struct Av1ProfileLevelMapper : ProfileLevelMapperHelper {
+    virtual bool simpleMap(C2Config::level_t from, int32_t *to) {
+        return sAv1Levels.map(from, to);
+    }
+    virtual bool simpleMap(int32_t from, C2Config::level_t *to) {
+        return sAv1Levels.map(from, to);
+    }
+    virtual bool simpleMap(C2Config::profile_t from, int32_t *to) {
+        return sAv1Profiles.map(from, to);
+    }
+    virtual bool simpleMap(int32_t from, C2Config::profile_t *to) {
+        return sAv1Profiles.map(from, to);
+    }
+};
+
 } // namespace
 
 // static
@@ -613,6 +628,8 @@
         return std::make_shared<Vp8ProfileLevelMapper>();
     } else if (mediaType == MIMETYPE_VIDEO_VP9) {
         return std::make_shared<Vp9ProfileLevelMapper>();
+    } else if (mediaType == MIMETYPE_VIDEO_AV1) {
+        return std::make_shared<Av1ProfileLevelMapper>();
     }
     return nullptr;
 }
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index ab6a105..c6ca670 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -38,6 +38,7 @@
 
     export_shared_lib_headers: [
         "libbase",
+        "libgui",
         "android.hardware.media.bufferpool@2.0",
     ],
 
@@ -52,13 +53,14 @@
 
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.media.bufferpool@2.0",
         "libbase",
         "libbinder",
         "libcutils",
         "libdl",
+        "libgui",
         "libhardware",
         "libhidlbase",
         "libion",
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index 9271a71..e1a8138 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -17,10 +17,11 @@
 #ifndef STAGEFRIGHT_CODEC2_BQ_BUFFER_PRIV_H_
 #define STAGEFRIGHT_CODEC2_BQ_BUFFER_PRIV_H_
 
-#include <functional>
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 
 #include <C2Buffer.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+
+#include <functional>
 
 class C2BufferQueueBlockPool : public C2BlockPool {
 public:
@@ -52,6 +53,8 @@
      */
     virtual void setRenderCallback(const OnRenderCallback &renderCallback = OnRenderCallback());
 
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer;
     /**
      * Configures an IGBP in order to create blocks. A newly created block is
      * dequeued from the configured IGBP. Unique Id of IGBP and the slot number of
@@ -62,7 +65,7 @@
      *
      * \param producer      the IGBP, which will be used to fetch blocks
      */
-    virtual void configureProducer(const android::sp<android::HGraphicBufferProducer> &producer);
+    virtual void configureProducer(const android::sp<HGraphicBufferProducer> &producer);
 
 private:
     const std::shared_ptr<C2Allocator> mAllocator;
diff --git a/media/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
index 2abf3ac..84ce70a 100644
--- a/media/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
 #define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
 
-#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 
 #include <C2Buffer.h>
 
@@ -291,7 +291,7 @@
     bool AssignBlockToBufferQueue(
             const std::shared_ptr<_C2BlockPoolData>& poolData,
             const ::android::sp<::android::hardware::graphics::bufferqueue::
-                                V1_0::IGraphicBufferProducer>& igbp,
+                                V2_0::IGraphicBufferProducer>& igbp,
             uint32_t generation,
             uint64_t bqId,
             int32_t bqSlot,
@@ -314,7 +314,7 @@
     bool HoldBlockFromBufferQueue(
             const std::shared_ptr<_C2BlockPoolData>& poolData,
             const ::android::sp<::android::hardware::graphics::bufferqueue::
-                                V1_0::IGraphicBufferProducer>& igbp = nullptr);
+                                V2_0::IGraphicBufferProducer>& igbp = nullptr);
 
     /**
      * Yield a block to the designated bufferqueue. This causes the destruction
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 41a5b3f..9cc5677 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -19,29 +19,37 @@
 #include <utils/Log.h>
 
 #include <gui/BufferQueueDefs.h>
-#include <list>
-#include <map>
-#include <mutex>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <hidl/HidlSupport.h>
 
 #include <C2AllocatorGralloc.h>
 #include <C2BqBufferPriv.h>
 #include <C2BlockInternal.h>
 
-using ::android::AnwBuffer;
+#include <list>
+#include <map>
+#include <mutex>
+
 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
 using ::android::C2AllocatorGralloc;
 using ::android::C2AndroidMemoryUsage;
 using ::android::Fence;
 using ::android::GraphicBuffer;
-using ::android::HGraphicBufferProducer;
 using ::android::IGraphicBufferProducer;
-using ::android::hidl_handle;
 using ::android::sp;
 using ::android::status_t;
 using ::android::wp;
-
+using ::android::hardware::hidl_handle;
 using ::android::hardware::Return;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer;
+using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper;
+
+using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::V2_0
+        ::IGraphicBufferProducer;
 
 struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
 
@@ -185,57 +193,67 @@
             C2MemoryUsage usage,
             std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
         // We have an IGBP now.
-        sp<Fence> fence = new Fence();
         C2AndroidMemoryUsage androidUsage = usage;
-        status_t status;
-        PixelFormat pixelFormat = static_cast<PixelFormat>(format);
-        int slot;
+        status_t status{};
+        int slot{};
+        bool bufferNeedsReallocation{};
+        sp<Fence> fence = new Fence();
         ALOGV("tries to dequeue buffer");
-        Return<void> transStatus = mProducer->dequeueBuffer(
-                width, height, pixelFormat, androidUsage.asGrallocUsage(), false,
-                [&status, &slot, &fence](
-                        int32_t tStatus, int32_t tSlot, hidl_handle const& tFence,
-                        HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
-                    status = tStatus;
-                    slot = tSlot;
-                    if (!android::conversion::convertTo(fence.get(), tFence) &&
-                            status == android::NO_ERROR) {
-                        status = android::BAD_VALUE;
+
+        { // Call dequeueBuffer().
+            using Input = HGraphicBufferProducer::DequeueBufferInput;
+            using Output = HGraphicBufferProducer::DequeueBufferOutput;
+            Return<void> transResult = mProducer->dequeueBuffer(
+                    Input{
+                        width,
+                        height,
+                        format,
+                        androidUsage.asGrallocUsage()},
+                    [&status, &slot, &bufferNeedsReallocation,
+                     &fence](HStatus hStatus,
+                             int32_t hSlot,
+                             Output const& hOutput) {
+                        slot = static_cast<int>(hSlot);
+                        if (!h2b(hStatus, &status) ||
+                                !h2b(hOutput.fence, &fence)) {
+                            status = ::android::BAD_VALUE;
+                        } else {
+                            bufferNeedsReallocation =
+                                    hOutput.bufferNeedsReallocation;
+                        }
+                    });
+            if (!transResult.isOk() || status != android::OK) {
+                ALOGD("cannot dequeue buffer %d", status);
+                if (transResult.isOk()) {
+                    if (status == android::INVALID_OPERATION ||
+                        status == android::TIMED_OUT ||
+                        status == android::WOULD_BLOCK) {
+                        // Dequeue buffer is blocked temporarily. Retrying is
+                        // required.
+                        return C2_BLOCKING;
                     }
-                    (void) tTs;
-                });
-        // dequeueBuffer returns flag.
-        if (!transStatus.isOk() || status < android::OK) {
-            ALOGD("cannot dequeue buffer %d", status);
-            if (transStatus.isOk()) {
-                if (status == android::INVALID_OPERATION ||
-                    status == android::TIMED_OUT ||
-                    status == android::WOULD_BLOCK) {
-                    // Dequeue buffer is blocked temporarily. Retrying is
-                    // required.
-                    return C2_BLOCKING;
                 }
+                return C2_BAD_VALUE;
             }
+        }
+        HFenceWrapper hFenceWrapper{};
+        if (!b2h(fence, &hFenceWrapper)) {
+            ALOGE("Invalid fence received from dequeueBuffer.");
             return C2_BAD_VALUE;
         }
         ALOGV("dequeued a buffer successfully");
-        native_handle_t* nh = nullptr;
-        hidl_handle fenceHandle;
-        if (fence) {
-            android::conversion::wrapAs(&fenceHandle, &nh, *fence);
-        }
         if (fence) {
             static constexpr int kFenceWaitTimeMs = 10;
 
             status_t status = fence->wait(kFenceWaitTimeMs);
             if (status == -ETIME) {
                 // fence is not signalled yet.
-                (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+                (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
                 return C2_BLOCKING;
             }
             if (status != android::NO_ERROR) {
                 ALOGD("buffer fence wait error %d", status);
-                (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+                (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
                 return C2_BAD_VALUE;
             } else if (mRenderCallback) {
                 nsecs_t signalTime = fence->getSignalTime();
@@ -248,27 +266,31 @@
         }
 
         sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
-        if (status & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || !slotBuffer) {
+        if (bufferNeedsReallocation || !slotBuffer) {
             if (!slotBuffer) {
                 slotBuffer = new GraphicBuffer();
             }
             // N.B. This assumes requestBuffer# returns an existing allocation
             // instead of a new allocation.
-            Return<void> transStatus = mProducer->requestBuffer(
+            Return<void> transResult = mProducer->requestBuffer(
                     slot,
-                    [&status, &slotBuffer](int32_t tStatus, AnwBuffer const& tBuffer){
-                        status = tStatus;
-                        if (!android::conversion::convertTo(slotBuffer.get(), tBuffer) &&
-                                status == android::NO_ERROR) {
+                    [&status, &slotBuffer](
+                            HStatus hStatus,
+                            HBuffer const& hBuffer,
+                            uint32_t generationNumber){
+                        if (h2b(hStatus, &status) &&
+                                h2b(hBuffer, &slotBuffer) &&
+                                slotBuffer) {
+                            slotBuffer->setGenerationNumber(generationNumber);
+                        } else {
                             status = android::BAD_VALUE;
                         }
                     });
-
-            if (!transStatus.isOk()) {
+            if (!transResult.isOk()) {
                 return C2_BAD_VALUE;
             } else if (status != android::NO_ERROR) {
                 slotBuffer.clear();
-                (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+                (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
                 return C2_BAD_VALUE;
             }
         }
@@ -292,13 +314,14 @@
                 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
                         std::make_shared<C2BufferQueueBlockPoolData>(
                                 slotBuffer->getGenerationNumber(),
-                                mProducerId, slot, shared_from_this());
+                                mProducerId, slot,
+                                shared_from_this());
                 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
                 return C2_OK;
             }
             // Block was not created. call requestBuffer# again next time.
             slotBuffer.clear();
-            (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+            (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
         }
         return C2_BAD_VALUE;
     }
@@ -312,10 +335,10 @@
         bool noInit = false;
         for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
             if (!noInit && mProducer) {
-                Return<int32_t> transResult =
+                Return<HStatus> transResult =
                         mProducer->detachBuffer(static_cast<int32_t>(i));
                 noInit = !transResult.isOk() ||
-                         static_cast<int32_t>(transResult) == android::NO_INIT;
+                         static_cast<HStatus>(transResult) == HStatus::NO_INIT;
             }
             mBuffers[i].clear();
         }
@@ -373,32 +396,28 @@
     }
 
     void configureProducer(const sp<HGraphicBufferProducer> &producer) {
-        int32_t status = android::OK;
         uint64_t producerId = 0;
         if (producer) {
-            Return<void> transStatus = producer->getUniqueId(
-                    [&status, &producerId](int32_t tStatus, int64_t tProducerId) {
-                        status = tStatus;
-                        producerId = tProducerId;
-                    });
-            if (!transStatus.isOk()) {
+            Return<uint64_t> transResult = producer->getUniqueId();
+            if (!transResult.isOk()) {
                 ALOGD("configureProducer -- failed to connect to the producer");
                 return;
             }
+            producerId = static_cast<uint64_t>(transResult);
         }
         {
             std::lock_guard<std::mutex> lock(mMutex);
             bool noInit = false;
             for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
                 if (!noInit && mProducer) {
-                    Return<int32_t> transResult =
+                    Return<HStatus> transResult =
                             mProducer->detachBuffer(static_cast<int32_t>(i));
                     noInit = !transResult.isOk() ||
-                             static_cast<int32_t>(transResult) == android::NO_INIT;
+                             static_cast<HStatus>(transResult) == HStatus::NO_INIT;
                 }
                 mBuffers[i].clear();
             }
-            if (producer && status == android::OK) {
+            if (producer) {
                 mProducer = producer;
                 mProducerId = producerId;
             } else {
@@ -414,7 +433,7 @@
     void cancel(uint64_t igbp_id, int32_t igbp_slot) {
         std::lock_guard<std::mutex> lock(mMutex);
         if (igbp_id == mProducerId && mProducer) {
-            (void)mProducer->cancelBuffer(igbp_slot, nullptr).isOk();
+            (void)mProducer->cancelBuffer(igbp_slot, hidl_handle{}).isOk();
         }
     }
 
@@ -455,7 +474,7 @@
     if (local && localPool) {
         localPool->cancel(bqId, bqSlot);
     } else if (igbp) {
-        igbp->cancelBuffer(bqSlot, nullptr);
+        igbp->cancelBuffer(bqSlot, hidl_handle{}).isOk();
     }
 }
 
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 20cc643..d6d24c1 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1336,6 +1336,13 @@
     mReader = NULL;
 
     delete mDataSource;
+
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        TrackInfo *info = &mTracks.editItemAt(i);
+        if (info->mMeta) {
+            AMediaFormat_delete(info->mMeta);
+        }
+    }
 }
 
 size_t MatroskaExtractor::countTracks() {
@@ -1808,6 +1815,8 @@
 void MatroskaExtractor::addTracks() {
     const mkvparser::Tracks *tracks = mSegment->GetTracks();
 
+    AMediaFormat *meta = nullptr;
+
     for (size_t index = 0; index < tracks->GetTracksCount(); ++index) {
         const mkvparser::Track *track = tracks->GetTrackByIndex(index);
 
@@ -1832,7 +1841,11 @@
 
         enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
 
-        AMediaFormat *meta = AMediaFormat_new();
+        if (meta) {
+            AMediaFormat_clear(meta);
+        } else {
+            meta = AMediaFormat_new();
+        }
 
         status_t err = OK;
         int32_t nalSize = -1;
@@ -2067,21 +2080,26 @@
         long long durationNs = mSegment->GetDuration();
         AMediaFormat_setInt64(meta, AMEDIAFORMAT_KEY_DURATION, (durationNs + 500) / 1000);
 
+        const char *mimetype = "";
+        if (!AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mimetype)) {
+            // do not add this track to the track list
+            ALOGW("ignoring track with unknown mime");
+            continue;
+        }
+
         mTracks.push();
         size_t n = mTracks.size() - 1;
         TrackInfo *trackInfo = &mTracks.editItemAt(n);
         initTrackInfo(track, meta, trackInfo);
         trackInfo->mNalLengthSize = nalSize;
 
-        const char *mimetype = "";
-        AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mimetype);
-
         if ((!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) ||
             (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_AVC) && isSetCsdFrom1stFrame)) {
             // Attempt to recover from AVC track without codec private data
             err = synthesizeAVCC(trackInfo, n);
             if (err != OK) {
                 mTracks.pop();
+                continue;
             }
         } else if ((!strcmp("V_MPEG2", codecID) && codecPrivateSize == 0) ||
             (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG2) && isSetCsdFrom1stFrame)) {
@@ -2089,6 +2107,7 @@
             err = synthesizeMPEG2(trackInfo, n);
             if (err != OK) {
                 mTracks.pop();
+                continue;
             }
         } else if ((!strcmp("V_MPEG4/ISO/ASP", codecID) && codecPrivateSize == 0) ||
             (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG4) && isSetCsdFrom1stFrame) ||
@@ -2099,9 +2118,14 @@
             err = synthesizeMPEG4(trackInfo, n);
             if (err != OK) {
                 mTracks.pop();
+                continue;
             }
         }
-
+        // the TrackInfo owns the metadata now
+        meta = nullptr;
+    }
+    if (meta) {
+        AMediaFormat_delete(meta);
     }
 }
 
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index d53d9e3..99fad17 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -61,10 +61,8 @@
         TrackInfo() {
             mMeta = NULL;
         }
+
         ~TrackInfo() {
-            if (mMeta) {
-                AMediaFormat_delete(mMeta);
-            }
         }
         unsigned long mTrackNum;
         bool mEncrypted;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 22819cb..5ff1c59 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -3675,8 +3675,10 @@
 
     void *tmpData;
     size_t tmpDataSize;
+    const char *s;
     if (size >= 8 && metadataKey &&
-            !AMediaFormat_getBuffer(mFileMetaData, metadataKey, &tmpData, &tmpDataSize)) {
+            !AMediaFormat_getBuffer(mFileMetaData, metadataKey, &tmpData, &tmpDataSize) &&
+            !AMediaFormat_getString(mFileMetaData, metadataKey, &s)) {
         if (!strcmp(metadataKey, "albumart")) {
             AMediaFormat_setBuffer(mFileMetaData, metadataKey,
                     buffer + 8, size - 8);
@@ -3918,10 +3920,9 @@
         };
         static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
-        void *tmpData;
-        size_t tmpDataSize;
         for (size_t i = 0; i < kNumMapEntries; ++i) {
-            if (!AMediaFormat_getBuffer(mFileMetaData, kMap[i].key, &tmpData, &tmpDataSize)) {
+            const char *ss;
+            if (!AMediaFormat_getString(mFileMetaData, kMap[i].key, &ss)) {
                 ID3::Iterator *it = new ID3::Iterator(id3, kMap[i].tag1);
                 if (it->done()) {
                     delete it;
@@ -5318,7 +5319,9 @@
 }
 
 int32_t MPEG4Source::parseHEVCLayerId(const uint8_t *data, size_t size) {
-    CHECK(data != nullptr && size >= (mNALLengthSize + 2));
+    if (data == nullptr || size < mNALLengthSize + 2) {
+        return -1;
+    }
 
     // HEVC NAL-header (16-bit)
     //  1   6      6     3
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index d99493d..b63ae6b 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -1280,7 +1280,7 @@
         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
     }
 
-    AMediaFormat_getInt32(mFileMeta, "haptic", &mHapticChannelCount);
+    AMediaFormat_getInt32(mFileMeta, AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT, &mHapticChannelCount);
 }
 
 void MyOggExtractor::setChannelMask(int channelCount) {
@@ -1297,6 +1297,8 @@
             const audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(
                     audioChannelCount) | hapticChannelMask;
             AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, channelMask);
+            AMediaFormat_setInt32(
+                    mMeta, AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT, mHapticChannelCount);
         }
     } else {
         AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK,
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index f5ed7aa..755ecc5 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -36,11 +36,14 @@
                                 aaudio_content_type_t contentType) = nullptr;
 static void (*s_setInputPreset)(AAudioStreamBuilder* builder,
                                 aaudio_input_preset_t inputPreset) = nullptr;
+static void (*s_setAllowedCapturePolicy)(AAudioStreamBuilder* builder,
+                                          aaudio_allowed_capture_policy_t usage) = nullptr;
 
 static bool s_loadAttempted = false;
 static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
 static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
 static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
+static aaudio_allowed_capture_policy_t (*s_getAllowedCapturePolicy)(AAudioStream *stream) = nullptr;
 
 // Link to test functions in shared library.
 static void loadFutureFunctions() {
@@ -61,6 +64,10 @@
                 dlsym(handle, "AAudioStreamBuilder_setInputPreset");
         if (s_setInputPreset == nullptr) goto error;
 
+        s_setAllowedCapturePolicy = (void (*)(AAudioStreamBuilder *, aaudio_input_preset_t))
+                dlsym(handle, "AAudioStreamBuilder_setAllowedCapturePolicy");
+        if (s_setAllowedCapturePolicy == nullptr) goto error;
+
         s_getUsage = (aaudio_usage_t (*)(AAudioStream *))
                 dlsym(handle, "AAudioStream_getUsage");
         if (s_getUsage == nullptr) goto error;
@@ -72,6 +79,10 @@
         s_getInputPreset = (aaudio_input_preset_t (*)(AAudioStream *))
                 dlsym(handle, "AAudioStream_getInputPreset");
         if (s_getInputPreset == nullptr) goto error;
+
+        s_getAllowedCapturePolicy = (aaudio_input_preset_t (*)(AAudioStream *))
+                dlsym(handle, "AAudioStream_getAllowedCapturePolicy");
+        if (s_getAllowedCapturePolicy == nullptr) goto error;
     }
     return;
 
@@ -169,6 +180,14 @@
         mInputPreset = inputPreset;
     }
 
+    aaudio_allowed_capture_policy_t getAllowedCapturePolicy() const {
+        return mAllowedCapturePolicy;
+    }
+
+    void setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy) {
+        mAllowedCapturePolicy = policy;
+    }
+
     int32_t getDeviceId() const {
         return mDeviceId;
     }
@@ -223,6 +242,13 @@
         } else if (mUsage != AAUDIO_UNSPECIFIED){
             printf("WARNING: setInputPreset not supported");
         }
+
+        // Call Q functions if supported.
+        if (s_setAllowedCapturePolicy != nullptr) {
+            s_setAllowedCapturePolicy(builder, mAllowedCapturePolicy);
+        } else if (mAllowedCapturePolicy != AAUDIO_UNSPECIFIED){
+            printf("WARNING: setAllowedCapturePolicy not supported");
+        }
     }
 
 private:
@@ -238,6 +264,7 @@
     aaudio_usage_t             mUsage           = AAUDIO_UNSPECIFIED;
     aaudio_content_type_t      mContentType     = AAUDIO_UNSPECIFIED;
     aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
+    aaudio_allowed_capture_policy_t mAllowedCapturePolicy     = AAUDIO_UNSPECIFIED;
 
     int32_t                    mNumberOfBursts  = AAUDIO_UNSPECIFIED;
     int32_t                    mFramesPerCallback = AAUDIO_UNSPECIFIED;
@@ -267,6 +294,9 @@
                 case 'c':
                     setChannelCount(atoi(&arg[2]));
                     break;
+                case 'C':
+                    setAllowedCapturePolicy(parseAllowedCapturePolicy(arg[2]));
+                    break;
                 case 'd':
                     setDeviceId(atoi(&arg[2]));
                     break;
@@ -341,6 +371,10 @@
         printf("      Default values are UNSPECIFIED unless otherwise stated.\n");
         printf("      -b{bufferCapacity} frames\n");
         printf("      -c{channels} for example 2 for stereo\n");
+        printf("      -C{a|s|n} set playback capture policy\n");
+        printf("          a = _ALL (default)\n");
+        printf("          s = _SYSTEM\n");
+        printf("          n = _NONE\n");
         printf("      -d{deviceId} default is %d\n", AAUDIO_UNSPECIFIED);
         printf("      -f{0|1|2} set format\n");
         printf("          0 = UNSPECIFIED\n");
@@ -365,6 +399,25 @@
         printf("      -z{callbackSize} or block size, in frames, default = 0\n");
     }
 
+    static aaudio_performance_mode_t parseAllowedCapturePolicy(char c) {
+        aaudio_allowed_capture_policy_t policy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
+        switch (c) {
+            case 'a':
+                policy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
+                break;
+            case 's':
+                policy = AAUDIO_ALLOW_CAPTURE_BY_SYSTEM;
+                break;
+            case 'n':
+                policy = AAUDIO_ALLOW_CAPTURE_BY_NONE;
+                break;
+            default:
+                printf("ERROR: invalid playback capture policy %c\n", c);
+                break;
+        }
+        return policy;
+    }
+
     static aaudio_performance_mode_t parsePerformanceMode(char c) {
         aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
         switch (c) {
@@ -449,6 +502,11 @@
         printf("  Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
                ? "yes" : "no");
 
+        if (s_getAllowedCapturePolicy != nullptr) {
+            printf("  ContentType:  requested = %d, actual = %d\n",
+                   getAllowedCapturePolicy(), s_getAllowedCapturePolicy(stream));
+        }
+
     }
 
     int32_t getDurationSeconds() const {
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 8e36c77..1c1df6c 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -37,7 +37,7 @@
 
 /**
  * This is used to represent a value that has not been specified.
- * For example, an application could use AAUDIO_UNSPECIFIED to indicate
+ * For example, an application could use {@link #AAUDIO_UNSPECIFIED} to indicate
  * that is did not not care what the specific value of a parameter was
  * and would accept whatever it was given.
  */
@@ -232,7 +232,8 @@
  * This information is used by certain platforms or routing policies
  * to make more refined volume or routing decisions.
  *
- * Note that these match the equivalent values in AudioAttributes in the Android Java API.
+ * Note that these match the equivalent values in {@link android.media.AudioAttributes}
+ * in the Android Java API.
  *
  * Added in API level 28.
  */
@@ -303,12 +304,13 @@
 /**
  * The CONTENT_TYPE attribute describes "what" you are playing.
  * It expresses the general category of the content. This information is optional.
- * But in case it is known (for instance {@link #AAUDIO_CONTENT_TYPE_MOVIE} for a
- * movie streaming service or {@link #AAUDIO_CONTENT_TYPE_SPEECH} for
+ * But in case it is known (for instance AAUDIO_CONTENT_TYPE_MOVIE for a
+ * movie streaming service or AAUDIO_CONTENT_TYPE_SPEECH for
  * an audio book application) this information might be used by the audio framework to
  * enforce audio focus.
  *
- * Note that these match the equivalent values in AudioAttributes in the Android Java API.
+ * Note that these match the equivalent values in {@link android.media.AudioAttributes}
+ * in the Android Java API.
  *
  * Added in API level 28.
  */
@@ -384,6 +386,48 @@
 typedef int32_t aaudio_input_preset_t;
 
 /**
+ * Specifying if audio may or may not be captured by other apps or the system.
+ *
+ * Note that these match the equivalent values in {@link android.media.AudioAttributes}
+ * in the Android Java API.
+ *
+ * Added in API level 29.
+ */
+enum {
+    /**
+     * Indicates that the audio may be captured by any app.
+     *
+     * For privacy, the following usages can not be recorded: AAUDIO_VOICE_COMMUNICATION*,
+     * AAUDIO_USAGE_NOTIFICATION*, AAUDIO_USAGE_ASSISTANCE* and {@link #AAUDIO_USAGE_ASSISTANT}.
+     *
+     * On {@link android.os.Build.VERSION_CODES#Q}, this means only {@link #AAUDIO_USAGE_MEDIA}
+     * and {@link #AAUDIO_USAGE_GAME} may be captured.
+     *
+     * See {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
+     */
+    AAUDIO_ALLOW_CAPTURE_BY_ALL = 1,
+    /**
+     * Indicates that the audio may only be captured by system apps.
+     *
+     * System apps can capture for many purposes like accessibility, user guidance...
+     * but have strong restriction. See
+     * {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM} for what the system apps
+     * can do with the capture audio.
+     */
+    AAUDIO_ALLOW_CAPTURE_BY_SYSTEM = 2,
+    /**
+     * Indicates that the audio may not be recorded by any app, even if it is a system app.
+     *
+     * It is encouraged to use {@link #AAUDIO_ALLOW_CAPTURE_BY_SYSTEM} instead of this value as system apps
+     * provide significant and useful features for the user (eg. accessibility).
+     * See {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+     */
+    AAUDIO_ALLOW_CAPTURE_BY_NONE = 3,
+};
+
+typedef int32_t aaudio_allowed_capture_policy_t;
+
+/**
  * These may be used with AAudioStreamBuilder_setSessionId().
  *
  * Added in API level 28.
@@ -452,8 +496,8 @@
  *
  * The deviceId is initially unspecified, meaning that the current default device will be used.
  *
- * The default direction is AAUDIO_DIRECTION_OUTPUT.
- * The default sharing mode is AAUDIO_SHARING_MODE_SHARED.
+ * The default direction is {@link #AAUDIO_DIRECTION_OUTPUT}.
+ * The default sharing mode is {@link #AAUDIO_SHARING_MODE_SHARED}.
  * The data format, samplesPerFrames and sampleRate are unspecified and will be
  * chosen by the device when it is opened.
  *
@@ -478,7 +522,7 @@
 /**
  * Request a sample rate in Hertz.
  *
- * The default, if you do not call this function, is AAUDIO_UNSPECIFIED.
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  * An optimal value will then be chosen when the stream is opened.
  * After opening a stream with an unspecified value, the application must
  * query for the actual value, which may vary by device.
@@ -495,7 +539,7 @@
 /**
  * Request a number of channels for the stream.
  *
- * The default, if you do not call this function, is AAUDIO_UNSPECIFIED.
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  * An optimal value will then be chosen when the stream is opened.
  * After opening a stream with an unspecified value, the application must
  * query for the actual value, which may vary by device.
@@ -519,9 +563,9 @@
                                                        int32_t samplesPerFrame) __INTRODUCED_IN(26);
 
 /**
- * Request a sample data format, for example AAUDIO_FORMAT_PCM_I16.
+ * Request a sample data format, for example {@link #AAUDIO_FORMAT_PCM_I16}.
  *
- * The default, if you do not call this function, is AAUDIO_UNSPECIFIED.
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  * An optimal value will then be chosen when the stream is opened.
  * After opening a stream with an unspecified value, the application must
  * query for the actual value, which may vary by device.
@@ -530,7 +574,8 @@
  * If a stream cannot be opened with the specified value then the open will fail.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param format common formats are AAUDIO_FORMAT_PCM_FLOAT and AAUDIO_FORMAT_PCM_I16.
+ * @param format common formats are {@link #AAUDIO_FORMAT_PCM_FLOAT} and
+ *               {@link #AAUDIO_FORMAT_PCM_I16}.
  */
 AAUDIO_API void AAudioStreamBuilder_setFormat(AAudioStreamBuilder* builder,
                                               aaudio_format_t format) __INTRODUCED_IN(26);
@@ -538,13 +583,13 @@
 /**
  * Request a mode for sharing the device.
  *
- * The default, if you do not call this function, is AAUDIO_SHARING_MODE_SHARED.
+ * The default, if you do not call this function, is {@link #AAUDIO_SHARING_MODE_SHARED}.
  *
  * The requested sharing mode may not be available.
  * The application can query for the actual mode after the stream is opened.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param sharingMode AAUDIO_SHARING_MODE_SHARED or AAUDIO_SHARING_MODE_EXCLUSIVE
+ * @param sharingMode {@link #AAUDIO_SHARING_MODE_SHARED} or {@link #AAUDIO_SHARING_MODE_EXCLUSIVE}
  */
 AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* builder,
         aaudio_sharing_mode_t sharingMode) __INTRODUCED_IN(26);
@@ -552,10 +597,10 @@
 /**
  * Request the direction for a stream.
  *
- * The default, if you do not call this function, is AAUDIO_DIRECTION_OUTPUT.
+ * The default, if you do not call this function, is {@link #AAUDIO_DIRECTION_OUTPUT}.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param direction AAUDIO_DIRECTION_OUTPUT or AAUDIO_DIRECTION_INPUT
+ * @param direction {@link #AAUDIO_DIRECTION_OUTPUT} or {@link #AAUDIO_DIRECTION_INPUT}
  */
 AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
         aaudio_direction_t direction) __INTRODUCED_IN(26);
@@ -564,10 +609,10 @@
  * Set the requested buffer capacity in frames.
  * The final AAudioStream capacity may differ, but will probably be at least this big.
  *
- * The default, if you do not call this function, is AAUDIO_UNSPECIFIED.
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param numFrames the desired buffer capacity in frames or AAUDIO_UNSPECIFIED
+ * @param numFrames the desired buffer capacity in frames or {@link #AAUDIO_UNSPECIFIED}
  */
 AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
         int32_t numFrames) __INTRODUCED_IN(26);
@@ -575,16 +620,17 @@
 /**
  * Set the requested performance mode.
  *
- * Supported modes are AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_PERFORMANCE_MODE_POWER_SAVING
- * and AAUDIO_PERFORMANCE_MODE_LOW_LATENCY.
+ * Supported modes are {@link #AAUDIO_PERFORMANCE_MODE_NONE},
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING} * and {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}.
  *
- * The default, if you do not call this function, is AAUDIO_PERFORMANCE_MODE_NONE.
+ * The default, if you do not call this function, is {@link #AAUDIO_PERFORMANCE_MODE_NONE}.
  *
  * You may not get the mode you requested.
- * You can call AAudioStream_getPerformanceMode() to find out the final mode for the stream.
+ * You can call AAudioStream_getPerformanceMode()
+ * to find out the final mode for the stream.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param mode the desired performance mode, eg. AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+ * @param mode the desired performance mode, eg. {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}
  */
 AAUDIO_API void AAudioStreamBuilder_setPerformanceMode(AAudioStreamBuilder* builder,
         aaudio_performance_mode_t mode) __INTRODUCED_IN(26);
@@ -596,12 +642,12 @@
  * behavior of the stream.
  * This could, for example, affect how volume and focus is handled for the stream.
  *
- * The default, if you do not call this function, is AAUDIO_USAGE_MEDIA.
+ * The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
  *
  * Added in API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param usage the desired usage, eg. AAUDIO_USAGE_GAME
+ * @param usage the desired usage, eg. {@link #AAUDIO_USAGE_GAME}
  */
 AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
         aaudio_usage_t usage) __INTRODUCED_IN(28);
@@ -613,12 +659,12 @@
  * behavior of the stream.
  * This could, for example, affect whether a stream is paused when a notification occurs.
  *
- * The default, if you do not call this function, is AAUDIO_CONTENT_TYPE_MUSIC.
+ * The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
  *
  * Added in API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param contentType the type of audio data, eg. AAUDIO_CONTENT_TYPE_SPEECH
+ * @param contentType the type of audio data, eg. {@link #AAUDIO_CONTENT_TYPE_SPEECH}
  */
 AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
         aaudio_content_type_t contentType) __INTRODUCED_IN(28);
@@ -631,7 +677,7 @@
  * This could, for example, affect which microphones are used and how the
  * recorded data is processed.
  *
- * The default, if you do not call this function, is AAUDIO_INPUT_PRESET_VOICE_RECOGNITION.
+ * The default, if you do not call this function, is {@link #AAUDIO_INPUT_PRESET_VOICE_RECOGNITION}.
  * That is because VOICE_RECOGNITION is the preset with the lowest latency
  * on many platforms.
  *
@@ -643,14 +689,30 @@
 AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
         aaudio_input_preset_t inputPreset) __INTRODUCED_IN(28);
 
+/**
+ * Specify whether this stream audio may or may not be captured by other apps or the system.
+ *
+ * The default is {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}.
+ *
+ * Note that an application can also set its global policy, in which case the most restrictive
+ * policy is always applied. See {@link android.media.AudioAttributes#setAllowedCapturePolicy(int)}
+ *
+ * Added in API level 29.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param inputPreset the desired level of opt-out from being captured.
+ */
+AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(AAudioStreamBuilder* builder,
+        aaudio_allowed_capture_policy_t capturePolicy) __INTRODUCED_IN(29);
+
 /** Set the requested session ID.
  *
  * The session ID can be used to associate a stream with effects processors.
  * The effects are controlled using the Android AudioEffect Java API.
  *
- * The default, if you do not call this function, is AAUDIO_SESSION_ID_NONE.
+ * The default, if you do not call this function, is {@link #AAUDIO_SESSION_ID_NONE}.
  *
- * If set to AAUDIO_SESSION_ID_ALLOCATE then a session ID will be allocated
+ * If set to {@link #AAUDIO_SESSION_ID_ALLOCATE} then a session ID will be allocated
  * when the stream is opened.
  *
  * The allocated session ID can be obtained by calling AAudioStream_getSessionId()
@@ -668,7 +730,7 @@
  * Added in API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param sessionId an allocated sessionID or AAUDIO_SESSION_ID_ALLOCATE
+ * @param sessionId an allocated sessionID or {@link #AAUDIO_SESSION_ID_ALLOCATE}
  */
 AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
         aaudio_session_id_t sessionId) __INTRODUCED_IN(28);
@@ -751,15 +813,16 @@
  *
  * Note that when using this callback, the audio data will be passed in or out
  * of the function as an argument.
- * So you cannot call AAudioStream_write() or AAudioStream_read() on the same stream
- * that has an active data callback.
+ * So you cannot call AAudioStream_write() or AAudioStream_read()
+ * on the same stream that has an active data callback.
  *
- * The callback function will start being called after AAudioStream_requestStart() is called.
+ * The callback function will start being called after AAudioStream_requestStart()
+ * is called.
  * It will stop being called after AAudioStream_requestPause() or
  * AAudioStream_requestStop() is called.
  *
  * This callback function will be called on a real-time thread owned by AAudio. See
- * {@link AAudioStream_dataCallback} for more information.
+ * {@link #AAudioStream_dataCallback} for more information.
  *
  * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
  *
@@ -773,9 +836,9 @@
 
 /**
  * Set the requested data callback buffer size in frames.
- * See {@link AAudioStream_dataCallback}.
+ * See {@link #AAudioStream_dataCallback}.
  *
- * The default, if you do not call this function, is AAUDIO_UNSPECIFIED.
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  *
  * For the lowest possible latency, do not call this function. AAudio will then
  * call the dataProc callback function with whatever size is optimal.
@@ -792,7 +855,7 @@
  * half the buffer capacity, to allow double buffering.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param numFrames the desired buffer size in frames or AAUDIO_UNSPECIFIED
+ * @param numFrames the desired buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
  */
 AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* builder,
                                                              int32_t numFrames) __INTRODUCED_IN(26);
@@ -853,12 +916,12 @@
 /**
  * Open a stream based on the options in the StreamBuilder.
  *
- * AAudioStream_close must be called when finished with the stream to recover
+ * AAudioStream_close() must be called when finished with the stream to recover
  * the memory and to free the associated resources.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param stream pointer to a variable to receive the new stream reference
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder* builder,
         AAudioStream** stream) __INTRODUCED_IN(26);
@@ -867,7 +930,7 @@
  * Delete the resources associated with the StreamBuilder.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder* builder)
     __INTRODUCED_IN(26);
@@ -880,7 +943,7 @@
  * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream* stream) __INTRODUCED_IN(26);
 
@@ -888,24 +951,26 @@
  * Asynchronously request to start playing the stream. For output streams, one should
  * write to the stream to fill the buffer before starting.
  * Otherwise it will underflow.
- * After this call the state will be in AAUDIO_STREAM_STATE_STARTING or AAUDIO_STREAM_STATE_STARTED.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STARTING} or
+ * {@link #AAUDIO_STREAM_STATE_STARTED}.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
  * Asynchronous request for the stream to pause.
  * Pausing a stream will freeze the data flow but not flush any buffers.
- * Use AAudioStream_Start() to resume playback after a pause.
- * After this call the state will be in AAUDIO_STREAM_STATE_PAUSING or AAUDIO_STREAM_STATE_PAUSED.
+ * Use AAudioStream_requestStart() to resume playback after a pause.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_PAUSING} or
+ * {@link #AAUDIO_STREAM_STATE_PAUSED}.
  *
- * This will return AAUDIO_ERROR_UNIMPLEMENTED for input streams.
+ * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
  * For input streams use AAudioStream_requestStop().
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream* stream) __INTRODUCED_IN(26);
 
@@ -914,32 +979,34 @@
  * Flushing will discard any pending data.
  * This call only works if the stream is pausing or paused. TODO review
  * Frame counters are not reset by a flush. They may be advanced.
- * After this call the state will be in AAUDIO_STREAM_STATE_FLUSHING or AAUDIO_STREAM_STATE_FLUSHED.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_FLUSHING} or
+ * {@link #AAUDIO_STREAM_STATE_FLUSHED}.
  *
- * This will return AAUDIO_ERROR_UNIMPLEMENTED for input streams.
+ * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
  * Asynchronous request for the stream to stop.
  * The stream will stop after all of the data currently buffered has been played.
- * After this call the state will be in AAUDIO_STREAM_STATE_STOPPING or AAUDIO_STREAM_STATE_STOPPED.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STOPPING} or
+ * {@link #AAUDIO_STREAM_STATE_STOPPED}.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
- * Query the current state of the client, eg. AAUDIO_STREAM_STATE_PAUSING
+ * Query the current state of the client, eg. {@link #AAUDIO_STREAM_STATE_PAUSING}
  *
  * This function will immediately return the state without updating the state.
  * If you want to update the client state based on the server state then
  * call AAudioStream_waitForStateChange() with currentState
- * set to AAUDIO_STREAM_STATE_UNKNOWN and a zero timeout.
+ * set to {@link #AAUDIO_STREAM_STATE_UNKNOWN} and a zero timeout.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  */
@@ -965,7 +1032,7 @@
  * @param inputState The state we want to avoid.
  * @param nextState Pointer to a variable that will be set to the new state.
  * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
- * @return AAUDIO_OK or a negative error.
+ * @return {@link #AAUDIO_OK} or a negative error.
  */
 AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
         aaudio_stream_state_t inputState, aaudio_stream_state_t *nextState,
@@ -1082,17 +1149,17 @@
  * This call can be used if the application needs to know the value of numFrames before
  * the stream is started. This is not normally necessary.
  *
- * If a specific size was requested by calling AAudioStreamBuilder_setFramesPerDataCallback()
- * then this will be the same size.
+ * If a specific size was requested by calling
+ * AAudioStreamBuilder_setFramesPerDataCallback() then this will be the same size.
  *
  * If AAudioStreamBuilder_setFramesPerDataCallback() was not called then this will
- * return the size chosen by AAudio, or AAUDIO_UNSPECIFIED.
+ * return the size chosen by AAudio, or {@link #AAUDIO_UNSPECIFIED}.
  *
- * AAUDIO_UNSPECIFIED indicates that the callback buffer size for this stream
+ * {@link #AAUDIO_UNSPECIFIED} indicates that the callback buffer size for this stream
  * may vary from one dataProc callback to the next.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return callback buffer size in frames or AAUDIO_UNSPECIFIED
+ * @return callback buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
  */
 AAUDIO_API int32_t AAudioStream_getFramesPerDataCallback(AAudioStream* stream) __INTRODUCED_IN(26);
 
@@ -1202,21 +1269,22 @@
  * The session ID can be used to associate a stream with effects processors.
  * The effects are controlled using the Android AudioEffect Java API.
  *
- * If AAudioStreamBuilder_setSessionId() was called with AAUDIO_SESSION_ID_ALLOCATE
+ * If AAudioStreamBuilder_setSessionId() was
+ * called with {@link #AAUDIO_SESSION_ID_ALLOCATE}
  * then a new session ID should be allocated once when the stream is opened.
  *
  * If AAudioStreamBuilder_setSessionId() was called with a previously allocated
  * session ID then that value should be returned.
  *
  * If AAudioStreamBuilder_setSessionId() was not called then this function should
- * return AAUDIO_SESSION_ID_NONE.
+ * return {@link #AAUDIO_SESSION_ID_NONE}.
  *
  * The sessionID for a stream should not change once the stream has been opened.
  *
  * Added in API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return session ID or AAUDIO_SESSION_ID_NONE
+ * @return session ID or {@link #AAUDIO_SESSION_ID_NONE}
  */
 AAUDIO_API aaudio_session_id_t AAudioStream_getSessionId(AAudioStream* stream) __INTRODUCED_IN(28);
 
@@ -1225,11 +1293,11 @@
  * This can be used to synchronize audio with video or MIDI.
  * It can also be used to align a recorded stream with a playback stream.
  *
- * Timestamps are only valid when the stream is in AAUDIO_STREAM_STATE_STARTED.
- * AAUDIO_ERROR_INVALID_STATE will be returned if the stream is not started.
+ * Timestamps are only valid when the stream is in {@link #AAUDIO_STREAM_STATE_STARTED}.
+ * {@link #AAUDIO_ERROR_INVALID_STATE} will be returned if the stream is not started.
  * Note that because requestStart() is asynchronous, timestamps will not be valid until
  * a short time after calling requestStart().
- * So AAUDIO_ERROR_INVALID_STATE should not be considered a fatal error.
+ * So {@link #AAUDIO_ERROR_INVALID_STATE} should not be considered a fatal error.
  * Just try calling again later.
  *
  * If an error occurs, then the position and time will not be modified.
@@ -1240,7 +1308,7 @@
  * @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
  * @param framePosition pointer to a variable to receive the position
  * @param timeNanoseconds pointer to a variable to receive the time
- * @return AAUDIO_OK or a negative error
+ * @return {@link #AAUDIO_OK} or a negative error
  */
 AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* stream,
         clockid_t clockid, int64_t *framePosition, int64_t *timeNanoseconds) __INTRODUCED_IN(26);
@@ -1261,7 +1329,7 @@
  * Added in API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return content type, for example AAUDIO_CONTENT_TYPE_MUSIC
+ * @return content type, for example {@link #AAUDIO_CONTENT_TYPE_MUSIC}
  */
 AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream)
         __INTRODUCED_IN(28);
@@ -1272,11 +1340,23 @@
  * Added in API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return input preset, for example AAUDIO_INPUT_PRESET_CAMCORDER
+ * @return input preset, for example {@link #AAUDIO_INPUT_PRESET_CAMCORDER}
  */
 AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream)
         __INTRODUCED_IN(28);
 
+/**
+ * Return the policy that determines whether the audio may or may not be captured
+ * by other apps or the system.
+ *
+ * Added in API level 29.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the allowed capture policy, for example {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}
+ */
+AAUDIO_API aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy(
+        AAudioStream* stream) __INTRODUCED_IN(29);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 3d1bc9b..a987fab 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -62,6 +62,8 @@
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32((int32_t) getInputPreset());
     if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32((int32_t) getAllowedCapturePolicy());
+    if (status != NO_ERROR) goto error;
     status = parcel->writeInt32(getSessionId());
     if (status != NO_ERROR) goto error;
     return NO_ERROR;
@@ -105,6 +107,9 @@
     setInputPreset((aaudio_input_preset_t) value);
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
+    setAllowedCapturePolicy((aaudio_allowed_capture_policy_t) value);
+    status = parcel->readInt32(&value);
+    if (status != NO_ERROR) goto error;
     setSessionId(value);
 
     return NO_ERROR;
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 0d71efc..8ae2644 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -204,6 +204,12 @@
     streamBuilder->setBufferCapacity(frames);
 }
 
+AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(
+        AAudioStreamBuilder* builder, aaudio_allowed_capture_policy_t policy) {
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setAllowedCapturePolicy(policy);
+}
+
 AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
                                                  aaudio_session_id_t sessionId)
 {
@@ -494,6 +500,13 @@
     return audioStream->getInputPreset();
 }
 
+AAUDIO_API aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy(
+        AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getAllowedCapturePolicy();
+}
+
 AAUDIO_API int32_t AAudioStream_getSessionId(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 88da53a..e5bda30 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -35,17 +35,18 @@
 AAudioStreamParameters::~AAudioStreamParameters() {}
 
 void AAudioStreamParameters::copyFrom(const AAudioStreamParameters &other) {
-    mSamplesPerFrame = other.mSamplesPerFrame;
-    mSampleRate      = other.mSampleRate;
-    mDeviceId        = other.mDeviceId;
-    mSessionId       = other.mSessionId;
-    mSharingMode     = other.mSharingMode;
-    mAudioFormat     = other.mAudioFormat;
-    mDirection       = other.mDirection;
-    mBufferCapacity  = other.mBufferCapacity;
-    mUsage           = other.mUsage;
-    mContentType     = other.mContentType;
-    mInputPreset     = other.mInputPreset;
+    mSamplesPerFrame      = other.mSamplesPerFrame;
+    mSampleRate           = other.mSampleRate;
+    mDeviceId             = other.mDeviceId;
+    mSessionId            = other.mSessionId;
+    mSharingMode          = other.mSharingMode;
+    mAudioFormat          = other.mAudioFormat;
+    mDirection            = other.mDirection;
+    mBufferCapacity       = other.mBufferCapacity;
+    mUsage                = other.mUsage;
+    mContentType          = other.mContentType;
+    mInputPreset          = other.mInputPreset;
+    mAllowedCapturePolicy = other.mAllowedCapturePolicy;
 }
 
 static aaudio_result_t isFormatValid(audio_format_t format) {
@@ -166,19 +167,32 @@
             // break;
     }
 
+    switch (mAllowedCapturePolicy) {
+        case AAUDIO_UNSPECIFIED:
+        case AAUDIO_ALLOW_CAPTURE_BY_ALL:
+        case AAUDIO_ALLOW_CAPTURE_BY_SYSTEM:
+        case AAUDIO_ALLOW_CAPTURE_BY_NONE:
+            break; // valid
+        default:
+            ALOGE("allowed capture policy not valid = %d", mAllowedCapturePolicy);
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+            // break;
+    }
+
     return AAUDIO_OK;
 }
 
 void AAudioStreamParameters::dump() const {
-    ALOGD("mDeviceId        = %6d", mDeviceId);
-    ALOGD("mSessionId       = %6d", mSessionId);
-    ALOGD("mSampleRate      = %6d", mSampleRate);
-    ALOGD("mSamplesPerFrame = %6d", mSamplesPerFrame);
-    ALOGD("mSharingMode     = %6d", (int)mSharingMode);
-    ALOGD("mAudioFormat     = %6d", (int)mAudioFormat);
-    ALOGD("mDirection       = %6d", mDirection);
-    ALOGD("mBufferCapacity  = %6d", mBufferCapacity);
-    ALOGD("mUsage           = %6d", mUsage);
-    ALOGD("mContentType     = %6d", mContentType);
-    ALOGD("mInputPreset     = %6d", mInputPreset);
+    ALOGD("mDeviceId             = %6d", mDeviceId);
+    ALOGD("mSessionId            = %6d", mSessionId);
+    ALOGD("mSampleRate           = %6d", mSampleRate);
+    ALOGD("mSamplesPerFrame      = %6d", mSamplesPerFrame);
+    ALOGD("mSharingMode          = %6d", (int)mSharingMode);
+    ALOGD("mAudioFormat          = %6d", (int)mAudioFormat);
+    ALOGD("mDirection            = %6d", mDirection);
+    ALOGD("mBufferCapacity       = %6d", mBufferCapacity);
+    ALOGD("mUsage                = %6d", mUsage);
+    ALOGD("mContentType          = %6d", mContentType);
+    ALOGD("mInputPreset          = %6d", mInputPreset);
+    ALOGD("mAllowedCapturePolicy = %6d", mAllowedCapturePolicy);
 }
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 6beb4b2..2e21a8d 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -112,6 +112,14 @@
         mInputPreset = inputPreset;
     }
 
+    aaudio_allowed_capture_policy_t getAllowedCapturePolicy() const {
+        return mAllowedCapturePolicy;
+    }
+
+    void setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy) {
+        mAllowedCapturePolicy = policy;
+    }
+
     aaudio_session_id_t getSessionId() const {
         return mSessionId;
     }
@@ -138,17 +146,18 @@
     void dump() const;
 
 private:
-    int32_t                    mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    int32_t                    mSampleRate      = AAUDIO_UNSPECIFIED;
-    int32_t                    mDeviceId        = AAUDIO_UNSPECIFIED;
-    aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
-    audio_format_t             mAudioFormat     = AUDIO_FORMAT_DEFAULT;
-    aaudio_direction_t         mDirection       = AAUDIO_DIRECTION_OUTPUT;
-    aaudio_usage_t             mUsage           = AAUDIO_UNSPECIFIED;
-    aaudio_content_type_t      mContentType     = AAUDIO_UNSPECIFIED;
-    aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
-    int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
-    aaudio_session_id_t        mSessionId       = AAUDIO_SESSION_ID_NONE;
+    int32_t                         mSamplesPerFrame      = AAUDIO_UNSPECIFIED;
+    int32_t                         mSampleRate           = AAUDIO_UNSPECIFIED;
+    int32_t                         mDeviceId             = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t           mSharingMode          = AAUDIO_SHARING_MODE_SHARED;
+    audio_format_t                  mAudioFormat          = AUDIO_FORMAT_DEFAULT;
+    aaudio_direction_t              mDirection            = AAUDIO_DIRECTION_OUTPUT;
+    aaudio_usage_t                  mUsage                = AAUDIO_UNSPECIFIED;
+    aaudio_content_type_t           mContentType          = AAUDIO_UNSPECIFIED;
+    aaudio_input_preset_t           mInputPreset          = AAUDIO_UNSPECIFIED;
+    int32_t                         mBufferCapacity       = AAUDIO_UNSPECIFIED;
+    aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_UNSPECIFIED;
+    aaudio_session_id_t             mSessionId            = AAUDIO_SESSION_ID_NONE;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index e39a075..732d45c 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -94,6 +94,10 @@
     if (mInputPreset == AAUDIO_UNSPECIFIED) {
         mInputPreset = AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
     }
+    mAllowedCapturePolicy = builder.getAllowedCapturePolicy();
+    if (mAllowedCapturePolicy == AAUDIO_UNSPECIFIED) {
+        mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
+    }
 
     // callbacks
     mFramesPerDataCallback = builder.getFramesPerDataCallback();
@@ -113,8 +117,8 @@
           mPerformanceMode,
           (isDataCallbackSet() ? "ON" : "OFF"),
           mFramesPerDataCallback);
-    ALOGI("open() usage  = %d, contentType = %d, inputPreset = %d",
-          mUsage, mContentType, mInputPreset);
+    ALOGI("open() usage  = %d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
+          mUsage, mContentType, mInputPreset, mAllowedCapturePolicy);
 
     return AAUDIO_OK;
 }
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 46951f5..32713b1 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -219,6 +219,10 @@
         return mInputPreset;
     }
 
+    aaudio_allowed_capture_policy_t getAllowedCapturePolicy() const {
+        return mAllowedCapturePolicy;
+    }
+
     int32_t getSessionId() const {
         return mSessionId;
     }
@@ -525,6 +529,13 @@
         mInputPreset = inputPreset;
     }
 
+    /**
+     * This should not be called after the open() call.
+     */
+    void setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy) {
+        mAllowedCapturePolicy = policy;
+    }
+
 private:
 
     aaudio_result_t safeStop();
@@ -546,6 +557,7 @@
     aaudio_usage_t              mUsage           = AAUDIO_UNSPECIFIED;
     aaudio_content_type_t       mContentType     = AAUDIO_UNSPECIFIED;
     aaudio_input_preset_t       mInputPreset     = AAUDIO_UNSPECIFIED;
+    aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
 
     int32_t                     mSessionId = AAUDIO_UNSPECIFIED;
 
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 16b10bc..d628bf7 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -134,12 +134,14 @@
             AAudioConvert_contentTypeToInternal(builder.getContentType());
     const audio_usage_t usage =
             AAudioConvert_usageToInternal(builder.getUsage());
+    const audio_flags_mask_t attributesFlags =
+        AAudioConvert_allowCapturePolicyToAudioFlagsMask(builder.getAllowedCapturePolicy());
 
     const audio_attributes_t attributes = {
             .content_type = contentType,
             .usage = usage,
             .source = AUDIO_SOURCE_DEFAULT, // only used for recording
-            .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_OUTPUT_FLAGS
+            .flags = attributesFlags,
             .tags = ""
     };
 
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 723cbf1..96ed56a 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -217,6 +217,22 @@
     return (audio_source_t) preset; // same value
 }
 
+audio_flags_mask_t AAudioConvert_allowCapturePolicyToAudioFlagsMask(
+        aaudio_allowed_capture_policy_t policy) {
+    switch (policy) {
+        case AAUDIO_UNSPECIFIED:
+        case AAUDIO_ALLOW_CAPTURE_BY_ALL:
+            return AUDIO_FLAG_NONE;
+        case AAUDIO_ALLOW_CAPTURE_BY_SYSTEM:
+            return AUDIO_FLAG_NO_MEDIA_PROJECTION;
+        case AAUDIO_ALLOW_CAPTURE_BY_NONE:
+            return AUDIO_FLAG_NO_MEDIA_PROJECTION | AUDIO_FLAG_NO_SYSTEM_CAPTURE;
+        default:
+            ALOGE("%s() 0x%08X unrecognized", __func__, policy);
+            return AUDIO_FLAG_NONE; //
+    }
+}
+
 int32_t AAudioConvert_framesToBytes(int32_t numFrames,
                                     int32_t bytesPerFrame,
                                     int32_t *sizeInBytes) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index dc2b198..76d0457 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -84,6 +84,14 @@
  */
 audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset);
 
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal audio flags mask
+ */
+audio_flags_mask_t AAudioConvert_allowCapturePolicyToAudioFlagsMask(
+        aaudio_allowed_capture_policy_t policy);
+
 // Note that this code may be replaced by Settings or by some other system configuration tool.
 
 #define AAUDIO_PROP_MMAP_POLICY           "aaudio.mmap_policy"
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index dbf8712..32ee2a3 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -32,6 +32,7 @@
                             aaudio_usage_t usage,
                             aaudio_content_type_t contentType,
                             aaudio_input_preset_t preset = DONT_SET,
+                            aaudio_allowed_capture_policy_t capturePolicy = DONT_SET,
                             aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
 
     float *buffer = new float[kNumFrames * kChannelCount];
@@ -56,6 +57,9 @@
     if (preset != DONT_SET) {
         AAudioStreamBuilder_setInputPreset(aaudioBuilder, preset);
     }
+    if (capturePolicy != DONT_SET) {
+        AAudioStreamBuilder_setAllowedCapturePolicy(aaudioBuilder, capturePolicy);
+    }
 
     // Create an AAudioStream using the Builder.
     ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
@@ -80,6 +84,12 @@
             : preset;
     EXPECT_EQ(expectedPreset, AAudioStream_getInputPreset(aaudioStream));
 
+    aaudio_allowed_capture_policy_t expectedCapturePolicy =
+            (capturePolicy == DONT_SET || capturePolicy == AAUDIO_UNSPECIFIED)
+            ? AAUDIO_ALLOW_CAPTURE_BY_ALL // default
+            : preset;
+    EXPECT_EQ(expectedCapturePolicy, AAudioStream_getAllowedCapturePolicy(aaudioStream));
+
     EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
 
     if (direction == AAUDIO_DIRECTION_INPUT) {
@@ -133,13 +143,21 @@
     AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE,
 };
 
+static const aaudio_input_preset_t sAllowCapturePolicies[] = {
+    DONT_SET,
+    AAUDIO_UNSPECIFIED,
+    AAUDIO_ALLOW_CAPTURE_BY_ALL,
+    AAUDIO_ALLOW_CAPTURE_BY_SYSTEM,
+    AAUDIO_ALLOW_CAPTURE_BY_NONE,
+};
+
 static void checkAttributesUsage(aaudio_performance_mode_t perfMode) {
     for (aaudio_usage_t usage : sUsages) {
         checkAttributes(perfMode, usage, DONT_SET);
     }
 }
 
-static void checkAttributesContentType(aaudio_input_preset_t perfMode) {
+static void checkAttributesContentType(aaudio_performance_mode_t perfMode) {
     for (aaudio_content_type_t contentType : sContentypes) {
         checkAttributes(perfMode, DONT_SET, contentType);
     }
@@ -151,6 +169,18 @@
                         DONT_SET,
                         DONT_SET,
                         inputPreset,
+                        DONT_SET,
+                        AAUDIO_DIRECTION_INPUT);
+    }
+}
+
+static void checkAttributesAllowedCapturePolicy(aaudio_performance_mode_t perfMode) {
+    for (aaudio_allowed_capture_policy_t policy : sAllowCapturePolicies) {
+        checkAttributes(perfMode,
+                        DONT_SET,
+                        DONT_SET,
+                        DONT_SET,
+                        policy,
                         AAUDIO_DIRECTION_INPUT);
     }
 }
@@ -167,6 +197,10 @@
     checkAttributesInputPreset(AAUDIO_PERFORMANCE_MODE_NONE);
 }
 
+TEST(test_attributes, aaudio_allowed_capture_policy_perfnone) {
+    checkAttributesAllowedCapturePolicy(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
 TEST(test_attributes, aaudio_usage_lowlat) {
     checkAttributesUsage(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
 }
@@ -178,3 +212,7 @@
 TEST(test_attributes, aaudio_input_preset_lowlat) {
     checkAttributesInputPreset(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
 }
+
+TEST(test_attributes, aaudio_allowed_capture_policy_lowlat) {
+    checkAttributesAllowedCapturePolicy(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 3ab38cd..65e797f 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -97,6 +97,7 @@
     mDeviceType = (audio_devices_t) parcel->readInt32();
     mDeviceAddress = parcel->readString8();
     mCbFlags = (uint32_t)parcel->readInt32();
+    mAllowPrivilegedPlaybackCapture = parcel->readBool();
     size_t size = (size_t)parcel->readInt32();
     if (size > MAX_CRITERIA_PER_MIX) {
         size = MAX_CRITERIA_PER_MIX;
@@ -120,6 +121,7 @@
     parcel->writeInt32(mDeviceType);
     parcel->writeString8(mDeviceAddress);
     parcel->writeInt32(mCbFlags);
+    parcel->writeBool(mAllowPrivilegedPlaybackCapture);
     size_t size = mCriteria.size();
     if (size > MAX_CRITERIA_PER_MIX) {
         size = MAX_CRITERIA_PER_MIX;
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 5851533..f07be46 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -410,8 +410,8 @@
     }
 
     // Call these directly because we are already holding the lock.
-    mAudioRecord->setMicrophoneDirection(mSelectedMicDirection);
-    mAudioRecord->setMicrophoneFieldDimension(mSelectedMicFieldDimension);
+    mAudioRecord->setPreferredMicrophoneDirection(mSelectedMicDirection);
+    mAudioRecord->setPreferredMicrophoneFieldDimension(mSelectedMicFieldDimension);
 
     if (status != NO_ERROR) {
         mActive = false;
@@ -1381,7 +1381,7 @@
     return mAudioRecord->getActiveMicrophones(activeMicrophones).transactionError();
 }
 
-status_t AudioRecord::setMicrophoneDirection(audio_microphone_direction_t direction)
+status_t AudioRecord::setPreferredMicrophoneDirection(audio_microphone_direction_t direction)
 {
     AutoMutex lock(mLock);
     if (mSelectedMicDirection == direction) {
@@ -1394,11 +1394,11 @@
         // the internal AudioRecord hasn't be created yet, so just stash the attribute.
         return OK;
     } else {
-        return mAudioRecord->setMicrophoneDirection(direction).transactionError();
+        return mAudioRecord->setPreferredMicrophoneDirection(direction).transactionError();
     }
 }
 
-status_t AudioRecord::setMicrophoneFieldDimension(float zoom) {
+status_t AudioRecord::setPreferredMicrophoneFieldDimension(float zoom) {
     AutoMutex lock(mLock);
     if (mSelectedMicFieldDimension == zoom) {
         // NOP
@@ -1410,7 +1410,7 @@
         // the internal AudioRecord hasn't be created yet, so just stash the attribute.
         return OK;
     } else {
-        return mAudioRecord->setMicrophoneFieldDimension(zoom).transactionError();
+        return mAudioRecord->setPreferredMicrophoneFieldDimension(zoom).transactionError();
     }
 }
 
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 0ce2513..f324669 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1133,6 +1133,12 @@
     }
 }
 
+status_t AudioSystem::setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) {
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == nullptr) return PERMISSION_DENIED;
+    return aps->setAllowedCapturePolicy(uid, flags);
+}
+
 bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info)
 {
     ALOGV("isOffloadSupported()");
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 3bac44f..bf98c60 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -101,7 +101,8 @@
     LIST_AUDIO_PRODUCT_STRATEGIES,
     GET_STRATEGY_FOR_ATTRIBUTES,
     LIST_AUDIO_VOLUME_GROUPS,
-    GET_VOLUME_GROUP_FOR_ATTRIBUTES
+    GET_VOLUME_GROUP_FOR_ATTRIBUTES,
+    SET_ALLOWED_CAPTURE_POLICY,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -603,6 +604,15 @@
         return status;
     }
 
+    status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        data.writeInt32(flags);
+        remote()->transact(SET_ALLOWED_CAPTURE_POLICY, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual bool isOffloadSupported(const audio_offload_info_t& info)
     {
         Parcel data, reply;
@@ -2168,7 +2178,7 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             bool isSupported = isHapticPlaybackSupported();
             reply->writeBool(isSupported);
-            return NO_ERROR;    
+            return NO_ERROR;
         }
 
         case SET_UID_DEVICE_AFFINITY: {
@@ -2285,6 +2295,15 @@
             return NO_ERROR;
         }
 
+        case SET_ALLOWED_CAPTURE_POLICY: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            uid_t uid = data.readInt32();
+            audio_flags_mask_t flags = data.readInt32();
+            status_t status = setAllowedCapturePolicy(uid, flags);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
index cf9c7f4..ecf58b6 100644
--- a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
@@ -39,9 +39,9 @@
 
   /* Set the microphone direction (for processing).
    */
-  void setMicrophoneDirection(int /*audio_microphone_direction_t*/ direction);
+  void setPreferredMicrophoneDirection(int /*audio_microphone_direction_t*/ direction);
 
   /* Set the microphone zoom (for processing).
    */
-  void setMicrophoneFieldDimension(float zoom);
+  void setPreferredMicrophoneFieldDimension(float zoom);
 }
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index bf8d627..4b94c12 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -114,6 +114,8 @@
     audio_devices_t mDeviceType;
     String8         mDeviceAddress;
     uint32_t        mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
+    /** Ignore the AUDIO_FLAG_NO_MEDIA_PROJECTION */
+    bool            mAllowPrivilegedPlaybackCapture = false;
 };
 
 
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index b4ddb69..9c81bb7 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -542,11 +542,11 @@
 
     /* Set the Microphone direction (for processing purposes).
      */
-            status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
+            status_t    setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
 
     /* Set the Microphone zoom factor (for processing purposes).
      */
-            status_t    setMicrophoneFieldDimension(float zoom);
+            status_t    setPreferredMicrophoneFieldDimension(float zoom);
 
      /* Get the unique port ID assigned to this AudioRecord instance by audio policy manager.
       * The ID is unique across all audioserver clients and can change during the life cycle
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index e64f285..05a1d56 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -299,6 +299,8 @@
 
     static status_t setLowRamDevice(bool isLowRamDevice, int64_t totalMemory);
 
+    static status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags);
+
     // Check if hw offload is possible for given format, stream type, sample rate,
     // bit rate, duration, video and streaming or offload property is enabled
     static bool isOffloadSupported(const audio_offload_info_t& info);
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 35540f0..95530ac 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -135,6 +135,7 @@
                                             audio_unique_id_t* id) = 0;
     virtual status_t removeSourceDefaultEffect(audio_unique_id_t id) = 0;
     virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) = 0;
+    virtual status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) = 0;
    // Check if offload is possible for given format, stream type, sample rate,
     // bit rate, duration, video and streaming or offload property is enabled
     virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index e396cf3..6c8e6a4 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -855,25 +855,26 @@
 #endif
 
 #if MAJOR_VERSION < 5
-status_t StreamInHalHidl::setMicrophoneDirection(audio_microphone_direction_t direction __unused) {
+status_t StreamInHalHidl::setPreferredMicrophoneDirection(
+            audio_microphone_direction_t direction __unused) {
     if (mStream == 0) return NO_INIT;
     return INVALID_OPERATION;
 }
 
-status_t StreamInHalHidl::setMicrophoneFieldDimension(float zoom __unused) {
+status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
     if (mStream == 0) return NO_INIT;
     return INVALID_OPERATION;
 }
 #else
-status_t StreamInHalHidl::setMicrophoneDirection(audio_microphone_direction_t direction) {
+status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
     if (!mStream) return NO_INIT;
-    return processReturn("setMicrophoneDirection",
-                mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
+    return processReturn("setPreferredMicrophoneDirection",
+        mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
 }
 
-status_t StreamInHalHidl::setMicrophoneFieldDimension(float zoom) {
+status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
     if (!mStream) return NO_INIT;
-    return processReturn("setMicrophoneFieldDimension",
+    return processReturn("setPreferredMicrophoneFieldDimension",
                 mStream->setMicrophoneFieldDimension(zoom));
 }
 #endif
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index 9ac1067..f587889 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -221,10 +221,11 @@
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
     // Set microphone direction (for processing)
-    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) override;
+    virtual status_t setPreferredMicrophoneDirection(
+                            audio_microphone_direction_t direction) override;
 
     // Set microphone zoom (for processing)
-    virtual status_t setMicrophoneFieldDimension(float zoom) override;
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom) override;
 
     // Called when the metadata of the stream's sink has been changed.
     status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index fcb809b..7d5ce05 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -369,20 +369,21 @@
 #endif
 
 #if MAJOR_VERSION < 5
-status_t StreamInHalLocal::setMicrophoneDirection(audio_microphone_direction_t direction __unused) {
+status_t StreamInHalLocal::setPreferredMicrophoneDirection(
+            audio_microphone_direction_t direction __unused) {
     return INVALID_OPERATION;
 }
 
-status_t StreamInHalLocal::setMicrophoneFieldDimension(float zoom __unused) {
+status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom __unused) {
     return INVALID_OPERATION;
 }
 #else
-status_t StreamInHalLocal::setMicrophoneDirection(audio_microphone_direction_t direction) {
+status_t StreamInHalLocal::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
     if (mStream->set_microphone_direction == NULL) return INVALID_OPERATION;
     return mStream->set_microphone_direction(mStream, direction);
 }
 
-status_t StreamInHalLocal::setMicrophoneFieldDimension(float zoom) {
+status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom) {
     if (mStream->set_microphone_field_dimension == NULL) return INVALID_OPERATION;
     return mStream->set_microphone_field_dimension(mStream, zoom);
 
@@ -391,3 +392,5 @@
 
 } // namespace CPP_VERSION
 } // namespace android
+
+
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index 3d6c50e..34f2bd8 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -205,10 +205,10 @@
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
     // Sets microphone direction (for processing)
-    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
 
     // Sets microphone zoom (for processing)
-    virtual status_t setMicrophoneFieldDimension(float zoom);
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom);
 
     // Called when the metadata of the stream's sink has been changed.
     status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index ed8282f..6c3b21c 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -180,10 +180,10 @@
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
 
     // Set direction for capture processing
-    virtual status_t setMicrophoneDirection(audio_microphone_direction_t) = 0;
+    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t) = 0;
 
     // Set zoom factor for capture stream
-    virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom) = 0;
 
     struct SinkMetadata {
         std::vector<record_track_metadata_t> tracks;
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index 7a32d3f..d150f18 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -132,6 +132,9 @@
     shared_libs: [
         "liblog",
     ],
+    header_libs: [
+        "libhardware_headers"
+    ],
     cflags: [
         "-fvisibility=hidden",
         "-DBUILD_FLOAT",
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 83ecae1..5082a53 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -298,6 +298,7 @@
     LVM_PSA_DecaySpeed_en       PSA_PeakDecayRate;      /* Peak value decay rate*/
 #ifdef SUPPORT_MC
     LVM_INT32                   NrChannels;
+    LVM_INT32                   ChMask;
 #endif
 
 } LVM_ControlParams_t;
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
index 62b4c73..1d95342 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
@@ -93,6 +93,7 @@
 
 #ifdef SUPPORT_MC
     pInstance->Params.NrChannels = pParams->NrChannels;
+    pInstance->Params.ChMask     = pParams->ChMask;
 #endif
     /*
      * Cinema Sound parameters
@@ -584,6 +585,7 @@
 
 #ifdef SUPPORT_MC
     pInstance->NrChannels = LocalParams.NrChannels;
+    pInstance->ChMask = LocalParams.ChMask;
 #endif
 
     /* Clear all internal data if format change*/
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index 19d1532..cdd3134 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -291,6 +291,7 @@
 
 #ifdef SUPPORT_MC
     LVM_INT16              NrChannels;
+    LVM_INT32              ChMask;
 #endif
 
 } LVM_Instance_t;
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
index 94ba278..8d30a61 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
@@ -21,6 +21,7 @@
 /*  Includes                                                                            */
 /*                                                                                      */
 /****************************************************************************************/
+#include <system/audio.h>
 
 #include "LVM_Private.h"
 #include "VectorArithmetic.h"
@@ -67,6 +68,7 @@
     LVM_ReturnStatus_en  Status;
 #ifdef SUPPORT_MC
     LVM_INT32           NrChannels  = pInstance->NrChannels;
+    LVM_INT32           ChMask      = pInstance->ChMask;
 #define NrFrames SampleCount  // alias for clarity
 #endif
 
@@ -119,6 +121,7 @@
 #ifdef SUPPORT_MC
         /* Update the local variable NrChannels from pInstance->NrChannels value */
         NrChannels = pInstance->NrChannels;
+        ChMask     = pInstance->ChMask;
 #endif
 
         if(Status != LVM_SUCCESS)
@@ -140,6 +143,7 @@
         pToProcess = pOutData;
 #ifdef SUPPORT_MC
         NrChannels = 2;
+        ChMask     = AUDIO_CHANNEL_OUT_STEREO;
 #endif
     }
 
@@ -254,18 +258,24 @@
 
             }
 #ifdef SUPPORT_MC
-            /* TODO - Multichannel support to be added */
-            if (NrChannels == 2)
+            /*
+             * Volume balance
+             */
+            LVC_MixSoft_1St_MC_float_SAT(&pInstance->VC_BalanceMix,
+                                          pProcessed,
+                                          pProcessed,
+                                          NrFrames,
+                                          NrChannels,
+                                          ChMask);
+#else
+            /*
+             * Volume balance
+             */
+            LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
+                                          pProcessed,
+                                          pProcessed,
+                                          SampleCount);
 #endif
-            {
-                /*
-                 * Volume balance
-                 */
-                LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
-                                              pProcessed,
-                                              pProcessed,
-                                              SampleCount);
-            }
 
             /*
              * Perform Parametric Spectum Analysis
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index 59586e0..fbfdd4d 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -94,6 +94,7 @@
 
 typedef     int32_t             LVM_INT32;          /* Signed 32-bit word */
 typedef     uint32_t            LVM_UINT32;         /* Unsigned 32-bit word */
+typedef     int64_t             LVM_INT64;          /* Signed 64-bit word */
 
 #ifdef BUILD_FLOAT
 
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
index eb5755e..db76cd1 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
@@ -59,6 +59,31 @@
 
 
 }
+#ifdef SUPPORT_MC
+void LVC_Core_MixHard_1St_MC_float_SAT (Mix_Private_FLOAT_st **ptrInstance,
+                                         const LVM_FLOAT      *src,
+                                         LVM_FLOAT            *dst,
+                                         LVM_INT16            NrFrames,
+                                         LVM_INT16            NrChannels)
+{
+    LVM_FLOAT  Temp;
+    LVM_INT16 ii, jj;
+    for (ii = NrFrames; ii != 0; ii--)
+    {
+        for (jj = 0; jj < NrChannels; jj++)
+        {
+            Mix_Private_FLOAT_st  *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance[jj]);
+            Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
+            if (Temp > 1.0f)
+                *dst++ = 1.0f;
+            else if (Temp < -1.0f)
+                *dst++ = -1.0f;
+            else
+                *dst++ = (LVM_FLOAT)Temp;
+        }
+    }
+}
+#endif
 #else
 void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_st        *ptrInstance1,
                                          LVMixer3_st        *ptrInstance2,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
index 656a117..56b5dae 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
@@ -146,6 +146,51 @@
     pInstanceR->Current = CurrentR;
 
 }
+#ifdef SUPPORT_MC
+void LVC_Core_MixSoft_1St_MC_float_WRA (Mix_Private_FLOAT_st **ptrInstance,
+                                         const LVM_FLOAT      *src,
+                                         LVM_FLOAT            *dst,
+                                         LVM_INT16            NrFrames,
+                                         LVM_INT16            NrChannels)
+{
+    LVM_INT32   ii, ch;
+    LVM_FLOAT   Temp =0.0f;
+    LVM_FLOAT   tempCurrent[NrChannels];
+    for (ch = 0; ch < NrChannels; ch++)
+    {
+        tempCurrent[ch] = ptrInstance[ch]->Current;
+    }
+    for (ii = NrFrames; ii > 0; ii--)
+    {
+        for (ch = 0; ch < NrChannels; ch++)
+        {
+            Mix_Private_FLOAT_st *pInstance = ptrInstance[ch];
+            const LVM_FLOAT   Delta = pInstance->Delta;
+            LVM_FLOAT         Current = tempCurrent[ch];
+            const LVM_FLOAT   Target = pInstance->Target;
+            if (Current < Target)
+            {
+                ADD2_SAT_FLOAT(Current, Delta, Temp);
+                Current = Temp;
+                if (Current > Target)
+                    Current = Target;
+            }
+            else
+            {
+                Current -= Delta;
+                if (Current < Target)
+                    Current = Target;
+            }
+            *dst++ = *src++ * Current;
+            tempCurrent[ch] = Current;
+        }
+    }
+    for (ch = 0; ch < NrChannels; ch++)
+    {
+        ptrInstance[ch]->Current = tempCurrent[ch];
+    }
+}
+#endif
 #else
 void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_st        *ptrInstance1,
                                          LVMixer3_st        *ptrInstance2,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
index bd5a925..a4682d3 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
@@ -19,6 +19,8 @@
    INCLUDE FILES
 ***********************************************************************************/
 
+#include <system/audio.h>
+
 #include "LVC_Mixer_Private.h"
 #include "VectorArithmetic.h"
 #include "ScalarArithmetic.h"
@@ -30,10 +32,207 @@
 #define TRUE          1
 #define FALSE         0
 
+#define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(*(a))))
+
 /**********************************************************************************
    FUNCTION LVC_MixSoft_1St_2i_D16C31_SAT
 ***********************************************************************************/
 #ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+/* This threshold is used to decide on the processing to be applied on
+ * front center and back center channels
+ */
+#define LVM_VOL_BAL_THR (0.000016f)
+void LVC_MixSoft_1St_MC_float_SAT (LVMixer3_2St_FLOAT_st *ptrInstance,
+                                    const LVM_FLOAT       *src,
+                                    LVM_FLOAT             *dst,
+                                    LVM_INT16             NrFrames,
+                                    LVM_INT32             NrChannels,
+                                    LVM_INT32             ChMask)
+{
+    char        HardMixing = TRUE;
+    LVM_FLOAT   TargetGain;
+    Mix_Private_FLOAT_st  Target_lfe = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
+    Mix_Private_FLOAT_st  Target_ctr = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
+    Mix_Private_FLOAT_st  *pInstance1 = \
+                              (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+    Mix_Private_FLOAT_st  *pInstance2 = \
+                              (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+    Mix_Private_FLOAT_st  *pMixPrivInst[4] = {pInstance1, pInstance2, &Target_ctr, &Target_lfe};
+    Mix_Private_FLOAT_st  *pInstance[NrChannels];
+
+    if (audio_channel_mask_get_representation(ChMask)
+            == AUDIO_CHANNEL_REPRESENTATION_INDEX)
+    {
+        for (int i = 0; i < 2; i++)
+        {
+            pInstance[i] = pMixPrivInst[i];
+        }
+        for (int i = 2; i < NrChannels; i++)
+        {
+            pInstance[i] = pMixPrivInst[2];
+        }
+    }
+    else
+    {
+        // TODO: Combine with system/media/audio_utils/Balance.cpp
+        // Constants in system/media/audio/include/system/audio-base.h
+        // 'mixInstIdx' is used to map the appropriate mixer instance for each channel.
+        const int mixInstIdx[] = {
+            0, // AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1u,
+            1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2u,
+            2, // AUDIO_CHANNEL_OUT_FRONT_CENTER          = 0x4u,
+            3, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY         = 0x8u,
+            0, // AUDIO_CHANNEL_OUT_BACK_LEFT             = 0x10u,
+            1, // AUDIO_CHANNEL_OUT_BACK_RIGHT            = 0x20u,
+            0, // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x40u,
+            1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
+            2, // AUDIO_CHANNEL_OUT_BACK_CENTER           = 0x100u,
+            0, // AUDIO_CHANNEL_OUT_SIDE_LEFT             = 0x200u,
+            1, // AUDIO_CHANNEL_OUT_SIDE_RIGHT            = 0x400u,
+            2, // AUDIO_CHANNEL_OUT_TOP_CENTER            = 0x800u,
+            0, // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT        = 0x1000u,
+            2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER      = 0x2000u,
+            1, // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT       = 0x4000u,
+            0, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT         = 0x8000u,
+            2, // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000u,
+            1, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000u,
+            0, // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT         = 0x40000u,
+            1, // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT        = 0x80000u
+        };
+        if (pInstance1->Target <= LVM_VOL_BAL_THR ||
+            pInstance2->Target <= LVM_VOL_BAL_THR)
+        {
+            Target_ctr.Target  = 0.0f;
+            Target_ctr.Current = 0.0f;
+            Target_ctr.Delta   = 0.0f;
+        }
+        const unsigned int idxArrSize = ARRAY_SIZE(mixInstIdx);
+        for (unsigned int i = 0, channel = ChMask; channel !=0 ; ++i)
+        {
+            const unsigned int idx = __builtin_ctz(channel);
+            if (idx < idxArrSize)
+            {
+                pInstance[i] = pMixPrivInst[mixInstIdx[idx]];
+            }
+            else
+            {
+                pInstance[i] = pMixPrivInst[2];
+            }
+            channel &= ~(1 << idx);
+        }
+    }
+
+    if (NrFrames <= 0)    return;
+
+    /******************************************************************************
+       SOFT MIXING
+    *******************************************************************************/
+
+    if ((pInstance1->Current != pInstance1->Target) ||
+        (pInstance2->Current != pInstance2->Target))
+    {
+        // TODO: combine similar checks below.
+        if (pInstance1->Delta == LVM_MAXFLOAT
+                || Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+        {
+            /* Difference is not significant anymore. Make them equal. */
+            pInstance1->Current = pInstance1->Target;
+            TargetGain = pInstance1->Target;
+            LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+        }
+        else
+        {
+            /* Soft mixing has to be applied */
+            HardMixing = FALSE;
+        }
+
+        if (HardMixing == TRUE)
+        {
+            if (pInstance2->Delta == LVM_MAXFLOAT
+                    || Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+            {
+                /* Difference is not significant anymore. Make them equal. */
+                pInstance2->Current = pInstance2->Target;
+                TargetGain = pInstance2->Target;
+                LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+            }
+            else
+            {
+                /* Soft mixing has to be applied */
+                HardMixing = FALSE;
+            }
+        }
+
+        if (HardMixing == FALSE)
+        {
+             LVC_Core_MixSoft_1St_MC_float_WRA (&pInstance[0],
+                                                 src, dst, NrFrames, NrChannels);
+        }
+    }
+
+    /******************************************************************************
+       HARD MIXING
+    *******************************************************************************/
+
+    if (HardMixing == TRUE)
+    {
+        if ((pInstance1->Target == LVM_MAXFLOAT) && (pInstance2->Target == LVM_MAXFLOAT))
+        {
+            if (src != dst)
+            {
+                Copy_Float(src, dst, NrFrames*NrChannels);
+            }
+        }
+        else
+        {
+            LVC_Core_MixHard_1St_MC_float_SAT(&(pInstance[0]),
+                                               src, dst, NrFrames, NrChannels);
+        }
+    }
+
+    /******************************************************************************
+       CALL BACK
+    *******************************************************************************/
+
+    if (ptrInstance->MixerStream[0].CallbackSet)
+    {
+        if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+        {
+            pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+                                                         Make them equal. */
+            TargetGain = pInstance1->Target;
+            LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
+            ptrInstance->MixerStream[0].CallbackSet = FALSE;
+            if (ptrInstance->MixerStream[0].pCallBack != 0)
+            {
+                (*ptrInstance->MixerStream[0].pCallBack) (\
+                    ptrInstance->MixerStream[0].pCallbackHandle,
+                    ptrInstance->MixerStream[0].pGeneralPurpose,
+                    ptrInstance->MixerStream[0].CallbackParam);
+            }
+        }
+    }
+    if (ptrInstance->MixerStream[1].CallbackSet)
+    {
+        if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+        {
+            pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
+                                                         Make them equal. */
+            TargetGain = pInstance2->Target;
+            LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
+            ptrInstance->MixerStream[1].CallbackSet = FALSE;
+            if (ptrInstance->MixerStream[1].pCallBack != 0)
+            {
+                (*ptrInstance->MixerStream[1].pCallBack) (\
+                    ptrInstance->MixerStream[1].pCallbackHandle,
+                    ptrInstance->MixerStream[1].pGeneralPurpose,
+                    ptrInstance->MixerStream[1].CallbackParam);
+            }
+        }
+    }
+}
+#endif
 void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
                                     const LVM_FLOAT             *src,
                                     LVM_FLOAT             *dst,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
index 7f18747..199d529 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
@@ -224,6 +224,14 @@
 /* Gain values should not be more that 1.0                                        */
 /**********************************************************************************/
 #ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void LVC_MixSoft_1St_MC_float_SAT(LVMixer3_2St_FLOAT_st *pInstance,
+                                   const   LVM_FLOAT     *src,
+                                   LVM_FLOAT             *dst,   /* dst can be equal to src */
+                                   LVM_INT16             NrFrames,
+                                   LVM_INT32             NrChannels,
+                                   LVM_INT32             ChMask);
+#endif
 void LVC_MixSoft_1St_2i_D16C31_SAT(LVMixer3_2St_FLOAT_st *pInstance,
                                    const   LVM_FLOAT     *src,
                                    LVM_FLOAT             *dst,   /* dst can be equal to src */
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
index f10094b..453a6a5 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
@@ -116,6 +116,13 @@
 /* Gain values should not be more that 1.0                                        */
 /**********************************************************************************/
 #ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void LVC_Core_MixSoft_1St_MC_float_WRA(Mix_Private_FLOAT_st **ptrInstance,
+                                         const LVM_FLOAT      *src,
+                                         LVM_FLOAT            *dst,
+                                         LVM_INT16            NrFrames,
+                                         LVM_INT16            NrChannels);
+#endif
 void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_FLOAT_st        *ptrInstance1,
                                          LVMixer3_FLOAT_st        *ptrInstance2,
                                          const LVM_FLOAT    *src,
@@ -136,6 +143,13 @@
 /* Gain values should not be more that 1.0                                        */
 /**********************************************************************************/
 #ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void LVC_Core_MixHard_1St_MC_float_SAT(Mix_Private_FLOAT_st **ptrInstance,
+                                         const LVM_FLOAT      *src,
+                                         LVM_FLOAT            *dst,
+                                         LVM_INT16            NrFrames,
+                                         LVM_INT16            NrChannels);
+#endif
 void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_FLOAT_st        *ptrInstance1,
                                          LVMixer3_FLOAT_st        *ptrInstance2,
                                          const LVM_FLOAT    *src,
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
index ea5f74a..61899fe 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
@@ -22,6 +22,17 @@
 
 #define LVM_MININT_32   0x80000000
 
+static LVM_INT32 mult32x32in32_shiftr(LVM_INT32 a, LVM_INT32 b, LVM_INT32 c) {
+  LVM_INT64 result = ((LVM_INT64)a * b) >> c;
+
+  if (result >= INT32_MAX) {
+    return INT32_MAX;
+  } else if (result <= INT32_MIN) {
+    return INT32_MIN;
+  } else {
+    return (LVM_INT32)result;
+  }
+}
 
 /************************************************************************************/
 /*                                                                                  */
@@ -123,10 +134,10 @@
 
     if(pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite_Save)
     {
-        MUL32x32INTO32((AudioTime + (LVM_INT32)((LVM_INT32)pLVPSA_Inst->LocalSamplesCount*1000)),
-                        (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
-                        AudioTimeInc,
-                        LVPSA_FsInvertShift)
+        AudioTimeInc = mult32x32in32_shiftr(
+                (AudioTime + ((LVM_INT32)pLVPSA_Inst->LocalSamplesCount * 1000)),
+                (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
+                LVPSA_FsInvertShift);
         pLVPSA_Inst->SpectralDataBufferAudioTime = AudioTime + AudioTimeInc;
     }
 
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
index 1a874a3..5079634 100755
--- a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
@@ -36,6 +36,10 @@
     "-csE -tE"
     "-csE -eqE" "-tE -eqE"
     "-csE -tE -bE -M -eqE"
+    "-tE -eqE -vcBal:96 -M"
+    "-tE -eqE -vcBal:-96 -M"
+    "-tE -eqE -vcBal:0 -M"
+    "-tE -eqE -bE -vcBal:30 -M"
 )
 
 fs_arr=(
@@ -56,26 +60,41 @@
 
 # run multichannel effects at different configs, saving only the stereo channel
 # pair.
+error_count=0
 for flags in "${flags_arr[@]}"
 do
     for fs in ${fs_arr[*]}
     do
-        for ch in {1..8}
+        for chMask in {0..22}
         do
             adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw \
-                -o:$testdir/sinesweep_$((ch))_$((fs)).raw -ch:$ch -fs:$fs $flags
+                -o:$testdir/sinesweep_$((chMask))_$((fs)).raw -chMask:$chMask -fs:$fs $flags
+
+            shell_ret=$?
+            if [ $shell_ret -ne 0 ]; then
+                echo "error: $shell_ret"
+                ((++error_count))
+            fi
+
 
             # two channel files should be identical to higher channel
             # computation (first 2 channels).
             # Do not compare cases where -bE is in flags (due to mono computation)
-            if [[ $flags != *"-bE"* ]] && [ "$ch" -gt 2 ]
+            if [[ $flags != *"-bE"* ]] && [[ "$chMask" -gt 1 ]]
             then
-                adb shell cmp $testdir/sinesweep_2_$((fs)).raw \
-                    $testdir/sinesweep_$((ch))_$((fs)).raw
-            elif [[ $flags == *"-bE"* ]] && [ "$ch" -gt 2 ]
+                adb shell cmp $testdir/sinesweep_1_$((fs)).raw \
+                    $testdir/sinesweep_$((chMask))_$((fs)).raw
+            elif [[ $flags == *"-bE"* ]] && [[ "$chMask" -gt 1 ]]
             then
-                adb shell $testdir/snr $testdir/sinesweep_2_$((fs)).raw \
-                    $testdir/sinesweep_$((ch))_$((fs)).raw -thr:90.308998
+                adb shell $testdir/snr $testdir/sinesweep_1_$((fs)).raw \
+                    $testdir/sinesweep_$((chMask))_$((fs)).raw -thr:90.308998
+            fi
+
+            # both cmp and snr return EXIT_FAILURE on mismatch.
+            shell_ret=$?
+            if [ $shell_ret -ne 0 ]; then
+                echo "error: $shell_ret"
+                ((++error_count))
             fi
 
         done
@@ -83,3 +102,5 @@
 done
 
 adb shell rm -r $testdir
+echo "$error_count errors"
+exit $error_count
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index 416bdaa..5b58dd1 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -24,6 +24,7 @@
 #include <audio_utils/channels.h>
 #include <audio_utils/primitives.h>
 #include <log/log.h>
+#include <system/audio.h>
 
 #include "EffectBundle.h"
 #include "LVM_Private.h"
@@ -76,6 +77,8 @@
 struct lvmConfigParams_t {
   int              samplingFreq    = 44100;
   int              nrChannels      = 2;
+  int              chMask          = AUDIO_CHANNEL_OUT_STEREO;
+  int              vcBal           = 0;
   int              fChannels       = 2;
   bool             monoMode        = false;
   int              bassEffectLevel = 0;
@@ -87,9 +90,36 @@
   LVM_Mode_en      csEnable        = LVM_MODE_OFF;
 };
 
+constexpr audio_channel_mask_t lvmConfigChMask[] = {
+    AUDIO_CHANNEL_OUT_MONO,
+    AUDIO_CHANNEL_OUT_STEREO,
+    AUDIO_CHANNEL_OUT_2POINT1,
+    AUDIO_CHANNEL_OUT_2POINT0POINT2,
+    AUDIO_CHANNEL_OUT_QUAD,
+    AUDIO_CHANNEL_OUT_QUAD_BACK,
+    AUDIO_CHANNEL_OUT_QUAD_SIDE,
+    AUDIO_CHANNEL_OUT_SURROUND,
+    (1 << 4) - 1,
+    AUDIO_CHANNEL_OUT_2POINT1POINT2,
+    AUDIO_CHANNEL_OUT_3POINT0POINT2,
+    AUDIO_CHANNEL_OUT_PENTA,
+    (1 << 5) - 1,
+    AUDIO_CHANNEL_OUT_3POINT1POINT2,
+    AUDIO_CHANNEL_OUT_5POINT1,
+    AUDIO_CHANNEL_OUT_5POINT1_BACK,
+    AUDIO_CHANNEL_OUT_5POINT1_SIDE,
+    (1 << 6) - 1,
+    AUDIO_CHANNEL_OUT_6POINT1,
+    (1 << 7) - 1,
+    AUDIO_CHANNEL_OUT_5POINT1POINT2,
+    AUDIO_CHANNEL_OUT_7POINT1,
+    (1 << 8) - 1,
+};
+
+
 void printUsage() {
   printf("\nUsage: ");
-  printf("\n     <exceutable> -i:<input_file> -o:<out_file> [options]\n");
+  printf("\n     <executable> -i:<input_file> -o:<out_file> [options]\n");
   printf("\nwhere, \n     <inputfile>  is the input file name");
   printf("\n                  on which LVM effects are applied");
   printf("\n     <outputfile> processed output file");
@@ -98,7 +128,34 @@
   printf("\n     -help (or) -h");
   printf("\n           Prints this usage information");
   printf("\n");
-  printf("\n     -ch:<process_channels> (1 through 8)\n\n");
+  printf("\n     -chMask:<channel_mask>\n");
+  printf("\n         0  - AUDIO_CHANNEL_OUT_MONO");
+  printf("\n         1  - AUDIO_CHANNEL_OUT_STEREO");
+  printf("\n         2  - AUDIO_CHANNEL_OUT_2POINT1");
+  printf("\n         3  - AUDIO_CHANNEL_OUT_2POINT0POINT2");
+  printf("\n         4  - AUDIO_CHANNEL_OUT_QUAD");
+  printf("\n         5  - AUDIO_CHANNEL_OUT_QUAD_BACK");
+  printf("\n         6  - AUDIO_CHANNEL_OUT_QUAD_SIDE");
+  printf("\n         7  - AUDIO_CHANNEL_OUT_SURROUND");
+  printf("\n         8  - canonical channel index mask for 4 ch: (1 << 4) - 1");
+  printf("\n         9  - AUDIO_CHANNEL_OUT_2POINT1POINT2");
+  printf("\n         10 - AUDIO_CHANNEL_OUT_3POINT0POINT2");
+  printf("\n         11 - AUDIO_CHANNEL_OUT_PENTA");
+  printf("\n         12 - canonical channel index mask for 5 ch: (1 << 5) - 1");
+  printf("\n         13 - AUDIO_CHANNEL_OUT_3POINT1POINT2");
+  printf("\n         14 - AUDIO_CHANNEL_OUT_5POINT1");
+  printf("\n         15 - AUDIO_CHANNEL_OUT_5POINT1_BACK");
+  printf("\n         16 - AUDIO_CHANNEL_OUT_5POINT1_SIDE");
+  printf("\n         17 - canonical channel index mask for 6 ch: (1 << 6) - 1");
+  printf("\n         18 - AUDIO_CHANNEL_OUT_6POINT1");
+  printf("\n         19 - canonical channel index mask for 7 ch: (1 << 7) - 1");
+  printf("\n         20 - AUDIO_CHANNEL_OUT_5POINT1POINT2");
+  printf("\n         21 - AUDIO_CHANNEL_OUT_7POINT1");
+  printf("\n         22 - canonical channel index mask for 8 ch: (1 << 8) - 1");
+  printf("\n         default 0");
+  printf("\n     -vcBal:<Left Right Balance control in dB [-96 to 96 dB]>");
+  printf("\n            -ve values reduce Right channel while +ve value reduces Left channel");
+  printf("\n                 default 0");
   printf("\n     -fch:<file_channels> (1 through 8)\n\n");
   printf("\n     -M");
   printf("\n           Mono mode (force all input audio channels to be identical)");
@@ -298,6 +355,7 @@
   params->OperatingMode = LVM_MODE_ON;
   params->SampleRate = LVM_FS_44100;
   params->SourceFormat = LVM_STEREO;
+  params->ChMask       = AUDIO_CHANNEL_OUT_STEREO;
   params->SpeakerType = LVM_HEADPHONES;
 
   pContext->pBundledContext->SampleRate = LVM_FS_44100;
@@ -452,13 +510,13 @@
   params->OperatingMode = LVM_MODE_ON;
   params->SpeakerType = LVM_HEADPHONES;
 
-  const int nrChannels = plvmConfigParams->nrChannels;
-  params->NrChannels = nrChannels;
-  if (nrChannels == 1) {
+  params->ChMask     = plvmConfigParams->chMask;
+  params->NrChannels = plvmConfigParams->nrChannels;
+  if (params->NrChannels == 1) {
     params->SourceFormat = LVM_MONO;
-  } else if (nrChannels == 2) {
+  } else if (params->NrChannels == 2) {
     params->SourceFormat = LVM_STEREO;
-  } else if (nrChannels > 2 && nrChannels <= 8) { // FCC_2 FCC_8
+  } else if (params->NrChannels > 2 && params->NrChannels <= 8) { // FCC_2 FCC_8
     params->SourceFormat = LVM_MULTICHANNEL;
   } else {
       return -EINVAL;
@@ -531,7 +589,7 @@
 
   /* Volume Control parameters */
   params->VC_EffectLevel = 0;
-  params->VC_Balance = 0;
+  params->VC_Balance = plvmConfigParams->vcBal;
 
   /* Treble Enhancement parameters */
   params->TE_OperatingMode = plvmConfigParams->trebleEnable;
@@ -667,13 +725,21 @@
         return -1;
       }
       lvmConfigParams.samplingFreq = samplingFreq;
-    } else if (!strncmp(argv[i], "-ch:", 4)) {
-      const int nrChannels = atoi(argv[i] + 4);
-      if (nrChannels > 8 || nrChannels < 1) {
-        printf("Error: Unsupported number of channels : %d\n", nrChannels);
+    } else if (!strncmp(argv[i], "-chMask:", 8)) {
+      const int chMaskConfigIdx = atoi(argv[i] + 8);
+      if (chMaskConfigIdx < 0 || (size_t)chMaskConfigIdx >= std::size(lvmConfigChMask)) {
+        ALOGE("\nError: Unsupported Channel Mask : %d\n", chMaskConfigIdx);
         return -1;
       }
-      lvmConfigParams.nrChannels = nrChannels;
+      const audio_channel_mask_t chMask = lvmConfigChMask[chMaskConfigIdx];
+      lvmConfigParams.chMask = chMask;
+      lvmConfigParams.nrChannels = audio_channel_count_from_out_mask(chMask);
+    } else if (!strncmp(argv[i], "-vcBal:", 7)) {
+      const int vcBalance = atoi(argv[i] + 7);
+      if (vcBalance > 96 || vcBalance < -96) {
+        ALOGE("\nError: Unsupported volume balance value: %d\n", vcBalance);
+      }
+      lvmConfigParams.vcBal = vcBalance;
     } else if (!strncmp(argv[i], "-fch:", 5)) {
       const int fChannels = atoi(argv[i] + 5);
       if (fChannels > 8 || fChannels < 1) {
diff --git a/media/libeffects/lvm/tests/snr.cpp b/media/libeffects/lvm/tests/snr.cpp
index 88110c0..885994c 100644
--- a/media/libeffects/lvm/tests/snr.cpp
+++ b/media/libeffects/lvm/tests/snr.cpp
@@ -84,6 +84,7 @@
     printf("\nError: missing input/reference files\n");
     return -1;
   }
+  int ret = EXIT_SUCCESS;
   auto sn = pcm_format == 0
       ? getSignalNoise<short>(finp, fref)
       : getSignalNoise<float>(finp, fref);
@@ -92,6 +93,7 @@
     // compare the measured snr value with threshold
     if (snr < thr) {
       printf("%.6f less than threshold %.6f\n", snr, thr);
+      ret = EXIT_FAILURE;
     } else {
       printf("%.6f\n", snr);
     }
@@ -99,5 +101,5 @@
   fclose(finp);
   fclose(fref);
 
-  return 0;
+  return ret;
 }
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 0c6f8de..3a97905 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1315,6 +1315,7 @@
 
 #ifdef SUPPORT_MC
         ActiveParams.NrChannels = NrChannels;
+        ActiveParams.ChMask = pConfig->inputCfg.channels;
 #endif
 
         LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index f283569..a354ce1 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -66,8 +66,8 @@
     ENABLE_AUDIO_DEVICE_CALLBACK,
     GET_ACTIVE_MICROPHONES,
     GET_PORT_ID,
-    SET_MICROPHONE_DIRECTION,
-    SET_MICROPHONE_FIELD_DIMENSION
+    SET_PREFERRED_MICROPHONE_DIRECTION,
+    SET_PREFERRED_MICROPHONE_FIELD_DIMENSION
 };
 
 class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -409,21 +409,21 @@
         return status;
     }
 
-    status_t setMicrophoneDirection(audio_microphone_direction_t direction) {
-        ALOGV("setMicrophoneDirection(%d)", direction);
+    status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
+        ALOGV("setPreferredMicrophoneDirection(%d)", direction);
         Parcel data, reply;
         data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
         data.writeInt32(direction);
-        status_t status = remote()->transact(SET_MICROPHONE_DIRECTION, data, &reply);
+        status_t status = remote()->transact(SET_PREFERRED_MICROPHONE_DIRECTION, data, &reply);
         return status == NO_ERROR ? (status_t)reply.readInt32() : status;
     }
 
-    status_t setMicrophoneFieldDimension(float zoom) {
-        ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    status_t setPreferredMicrophoneFieldDimension(float zoom) {
+        ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
         Parcel data, reply;
         data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
         data.writeFloat(zoom);
-        status_t status = remote()->transact(SET_MICROPHONE_FIELD_DIMENSION, data, &reply);
+        status_t status = remote()->transact(SET_PREFERRED_MICROPHONE_FIELD_DIMENSION, data, &reply);
         return status == NO_ERROR ? (status_t)reply.readInt32() : status;
     }
 
@@ -709,20 +709,20 @@
             }
             return NO_ERROR;
         }
-        case SET_MICROPHONE_DIRECTION: {
-            ALOGV("SET_MICROPHONE_DIRECTION");
+        case SET_PREFERRED_MICROPHONE_DIRECTION: {
+            ALOGV("SET_PREFERRED_MICROPHONE_DIRECTION");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
             int direction = data.readInt32();
-            status_t status =
-                setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+            status_t status = setPreferredMicrophoneDirection(
+                    static_cast<audio_microphone_direction_t>(direction));
             reply->writeInt32(status);
             return NO_ERROR;
         }
-        case SET_MICROPHONE_FIELD_DIMENSION: {
+        case SET_PREFERRED_MICROPHONE_FIELD_DIMENSION: {
             ALOGV("SET_MICROPHONE_FIELD_DIMENSION");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
             float zoom = data.readFloat();
-            status_t status = setMicrophoneFieldDimension(zoom);
+            status_t status = setPreferredMicrophoneFieldDimension(zoom);
             reply->writeInt32(status);
             return NO_ERROR;
         }
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index ea0547c..c150407 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -65,6 +65,7 @@
     AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL,
     AMEDIAFORMAT_KEY_GRID_COLUMNS,
     AMEDIAFORMAT_KEY_GRID_ROWS,
+    AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT,
     AMEDIAFORMAT_KEY_HEIGHT,
     AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD,
     AMEDIAFORMAT_KEY_IS_ADTS,
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 0301b21..5be78d1 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -217,6 +217,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_ADAPTIVE),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC_LL),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_TWSP),
     TERMINATOR
 };
 
@@ -391,7 +392,8 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BYPASS_MUTE),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_LOW_LATENCY),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_DEEP_BUFFER),
-    MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_CAPTURE),
+    MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_MEDIA_PROJECTION),
+    MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_SYSTEM_CAPTURE),
     TERMINATOR
 };
 
diff --git a/media/libmedia/include/media/IMediaRecorder.h b/media/libmedia/include/media/IMediaRecorder.h
index 0b09420..f9c557c 100644
--- a/media/libmedia/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/media/IMediaRecorder.h
@@ -73,8 +73,8 @@
     virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
     virtual status_t getActiveMicrophones(
                         std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
-    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) = 0;
-    virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
+    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) = 0;
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom) = 0;
     virtual status_t getPortId(audio_port_handle_t *portId) = 0;
 };
 
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index 88282ac..a2dff31 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -72,8 +72,8 @@
     virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
     virtual status_t getActiveMicrophones(
                         std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
-    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) = 0;
-    virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
+    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) = 0;
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom) = 0;
     virtual status_t getPortId(audio_port_handle_t *portId) const = 0;
 
 
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 8580437..2dd4b7f 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -264,8 +264,8 @@
     status_t    getRoutedDeviceId(audio_port_handle_t *deviceId);
     status_t    enableAudioDeviceCallback(bool enabled);
     status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
-    status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
-    status_t    setMicrophoneFieldDimension(float zoom);
+    status_t    setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
+    status_t    setPreferredMicrophoneFieldDimension(float zoom);
 
     status_t    getPortId(audio_port_handle_t *portId) const;
 
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6c59a29..4570af9 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -842,14 +842,14 @@
     return mMediaRecorder->getActiveMicrophones(activeMicrophones);
 }
 
-status_t MediaRecorder::setMicrophoneDirection(audio_microphone_direction_t direction) {
-    ALOGV("setMicrophoneDirection(%d)", direction);
-    return mMediaRecorder->setMicrophoneDirection(direction);
+status_t MediaRecorder::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setPreferredMicrophoneDirection(%d)", direction);
+    return mMediaRecorder->setPreferredMicrophoneDirection(direction);
 }
 
-status_t MediaRecorder::setMicrophoneFieldDimension(float zoom) {
-    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
-    return mMediaRecorder->setMicrophoneFieldDimension(zoom);
+status_t MediaRecorder::setPreferredMicrophoneFieldDimension(float zoom) {
+    ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
+    return mMediaRecorder->setPreferredMicrophoneFieldDimension(zoom);
 }
 
 status_t MediaRecorder::getPortId(audio_port_handle_t *portId) const
diff --git a/media/libmedia/xsd/api/current.txt b/media/libmedia/xsd/api/current.txt
index 0924dd9..05e8a49 100644
--- a/media/libmedia/xsd/api/current.txt
+++ b/media/libmedia/xsd/api/current.txt
@@ -45,10 +45,17 @@
     ctor public CamcorderProfiles();
     method public int getCameraId();
     method public java.util.List<media.profiles.EncoderProfile> getEncoderProfile();
+    method public java.util.List<media.profiles.CamcorderProfiles.ImageDecoding> getImageDecoding();
     method public java.util.List<media.profiles.CamcorderProfiles.ImageEncoding> getImageEncoding();
     method public void setCameraId(int);
   }
 
+  public static class CamcorderProfiles.ImageDecoding {
+    ctor public CamcorderProfiles.ImageDecoding();
+    method public int getMemCap();
+    method public void setMemCap(int);
+  }
+
   public static class CamcorderProfiles.ImageEncoding {
     ctor public CamcorderProfiles.ImageEncoding();
     method public int getQuality();
diff --git a/media/libmedia/xsd/media_profiles.xsd b/media/libmedia/xsd/media_profiles.xsd
index a9687b0..a02252a 100644
--- a/media/libmedia/xsd/media_profiles.xsd
+++ b/media/libmedia/xsd/media_profiles.xsd
@@ -42,6 +42,11 @@
                     <xs:attribute name="quality" type="xs:int"/>
                 </xs:complexType>
             </xs:element>
+            <xs:element name="ImageDecoding" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="memCap" type="xs:int"/>
+                </xs:complexType>
+            </xs:element>
         </xs:sequence>
         <xs:attribute name="cameraId" type="xs:int"/>
     </xs:complexType>
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index d6628d9..9f4265b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -538,18 +538,19 @@
     return NO_INIT;
 }
 
-status_t MediaRecorderClient::setMicrophoneDirection(audio_microphone_direction_t direction) {
-    ALOGV("setMicrophoneDirection(%d)", direction);
+status_t MediaRecorderClient::setPreferredMicrophoneDirection(
+            audio_microphone_direction_t direction) {
+    ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     if (mRecorder != NULL) {
-        return mRecorder->setMicrophoneDirection(direction);
+        return mRecorder->setPreferredMicrophoneDirection(direction);
     }
     return NO_INIT;
 }
 
-status_t MediaRecorderClient::setMicrophoneFieldDimension(float zoom) {
-    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+status_t MediaRecorderClient::setPreferredMicrophoneFieldDimension(float zoom) {
+    ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     if (mRecorder != NULL) {
-        return mRecorder->setMicrophoneFieldDimension(zoom);
+        return mRecorder->setPreferredMicrophoneFieldDimension(zoom);
     }
     return NO_INIT;
 }
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 8da718f..e698819 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -109,8 +109,8 @@
     virtual     status_t   enableAudioDeviceCallback(bool enabled);
     virtual     status_t   getActiveMicrophones(
                               std::vector<media::MicrophoneInfo>* activeMicrophones);
-    virtual     status_t   setMicrophoneDirection(audio_microphone_direction_t direction);
-    virtual     status_t   setMicrophoneFieldDimension(float zoom);
+    virtual     status_t   setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
+    virtual     status_t   setPreferredMicrophoneFieldDimension(float zoom);
                 status_t   getPortId(audio_port_handle_t *portId) override;
 
 private:
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 77777b8..63681fa 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -164,9 +164,12 @@
     mAnalyticsItem->setInt32(kRecorderVideoIframeInterval, mIFramesIntervalSec);
     // TBD mAudioSourceNode = 0;
     // TBD mUse64BitFileOffset = false;
-    mAnalyticsItem->setInt32(kRecorderMovieTimescale, mMovieTimeScale);
-    mAnalyticsItem->setInt32(kRecorderAudioTimescale, mAudioTimeScale);
-    mAnalyticsItem->setInt32(kRecorderVideoTimescale, mVideoTimeScale);
+    if (mMovieTimeScale != -1)
+        mAnalyticsItem->setInt32(kRecorderMovieTimescale, mMovieTimeScale);
+    if (mAudioTimeScale != -1)
+        mAnalyticsItem->setInt32(kRecorderAudioTimescale, mAudioTimeScale);
+    if (mVideoTimeScale != -1)
+        mAnalyticsItem->setInt32(kRecorderVideoTimescale, mVideoTimeScale);
     // TBD mCameraId        = 0;
     // TBD mStartTimeOffsetMs = -1;
     mAnalyticsItem->setInt32(kRecorderVideoProfile, mVideoEncoderProfile);
@@ -2210,7 +2213,7 @@
 }
 
 status_t StagefrightRecorder::getMetrics(Parcel *reply) {
-    ALOGD("StagefrightRecorder::getMetrics");
+    ALOGV("StagefrightRecorder::getMetrics");
 
     if (reply == NULL) {
         ALOGE("Null pointer argument");
@@ -2274,20 +2277,20 @@
     return NO_INIT;
 }
 
-status_t StagefrightRecorder::setMicrophoneDirection(audio_microphone_direction_t direction) {
-    ALOGV("setMicrophoneDirection(%d)", direction);
+status_t StagefrightRecorder::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     mSelectedMicDirection = direction;
     if (mAudioSourceNode != 0) {
-        return mAudioSourceNode->setMicrophoneDirection(direction);
+        return mAudioSourceNode->setPreferredMicrophoneDirection(direction);
     }
     return NO_INIT;
 }
 
-status_t StagefrightRecorder::setMicrophoneFieldDimension(float zoom) {
-    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+status_t StagefrightRecorder::setPreferredMicrophoneFieldDimension(float zoom) {
+    ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     mSelectedMicFieldDimension = zoom;
     if (mAudioSourceNode != 0) {
-        return mAudioSourceNode->setMicrophoneFieldDimension(zoom);
+        return mAudioSourceNode->setPreferredMicrophoneFieldDimension(zoom);
     }
     return NO_INIT;
 }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 236b19e..8bf083a 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -77,8 +77,8 @@
     virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
     virtual status_t enableAudioDeviceCallback(bool enabled);
     virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
-    virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction);
-    virtual status_t setMicrophoneFieldDimension(float zoom);
+    virtual status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
+    virtual status_t setPreferredMicrophoneFieldDimension(float zoom);
             status_t getPortId(audio_port_handle_t *portId) const override;
 
 private:
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index f00c895..cf1a6f1 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -569,7 +569,6 @@
       mFps(-1.0),
       mCaptureFps(-1.0),
       mCreateInputBuffersSuspended(false),
-      mLatency(0),
       mTunneled(false),
       mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),
       mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),
@@ -4425,12 +4424,13 @@
             h264type.eProfile == OMX_VIDEO_AVCProfileHigh) {
         h264type.nSliceHeaderSpacing = 0;
         h264type.bUseHadamard = OMX_TRUE;
-        h264type.nRefFrames = 2;
-        h264type.nBFrames = mLatency == 0 ? 1 : std::min(1U, mLatency - 1);
-
-        // disable B-frames until we have explicit settings for enabling the feature.
-        h264type.nRefFrames = 1;
-        h264type.nBFrames = 0;
+        int32_t maxBframes = 0;
+        (void)msg->findInt32(KEY_MAX_B_FRAMES, &maxBframes);
+        h264type.nBFrames = uint32_t(maxBframes);
+        if (mLatency && h264type.nBFrames > *mLatency) {
+            h264type.nBFrames = *mLatency;
+        }
+        h264type.nRefFrames = h264type.nBFrames == 0 ? 1 : 2;
 
         h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
         h264type.nAllowedPictureTypes =
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index dc51b16..da35889 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -181,6 +181,7 @@
         "libcamera_client",
         "libcutils",
         "libdl",
+        "libdl_android",
         "libdrmframework",
         "libgui",
         "liblog",
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 5f86bd3..a713900 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -385,11 +385,11 @@
     }
     mLastFrameTimestampUs = timeUs;
 
-    size_t numLostBytes = 0;
+    uint64_t numLostBytes = 0; // AudioRecord::getInputFramesLost() returns uint32_t
     if (mNumFramesReceived > 0) {  // Ignore earlier frame lost
         // getInputFramesLost() returns the number of lost frames.
         // Convert number of frames lost to number of bytes lost.
-        numLostBytes = mRecord->getInputFramesLost() * mRecord->frameSize();
+        numLostBytes = (uint64_t)mRecord->getInputFramesLost() * mRecord->frameSize();
     }
 
     CHECK_EQ(numLostBytes & 1, 0u);
@@ -397,11 +397,11 @@
     if (numLostBytes > 0) {
         // Loss of audio frames should happen rarely; thus the LOGW should
         // not cause a logging spam
-        ALOGW("Lost audio record data: %zu bytes", numLostBytes);
+        ALOGW("Lost audio record data: %" PRIu64 " bytes", numLostBytes);
     }
 
     while (numLostBytes > 0) {
-        size_t bufferSize = numLostBytes;
+        uint64_t bufferSize = numLostBytes;
         if (numLostBytes > kMaxBufferSize) {
             numLostBytes -= kMaxBufferSize;
             bufferSize = kMaxBufferSize;
@@ -510,18 +510,18 @@
     return NO_INIT;
 }
 
-status_t AudioSource::setMicrophoneDirection(audio_microphone_direction_t direction) {
-    ALOGV("setMicrophoneDirection(%d)", direction);
+status_t AudioSource::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
+    ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     if (mRecord != 0) {
-        return mRecord->setMicrophoneDirection(direction);
+        return mRecord->setPreferredMicrophoneDirection(direction);
     }
     return NO_INIT;
 }
 
-status_t AudioSource::setMicrophoneFieldDimension(float zoom) {
-    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+status_t AudioSource::setPreferredMicrophoneFieldDimension(float zoom) {
+    ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     if (mRecord != 0) {
-        return mRecord->setMicrophoneFieldDimension(zoom);
+        return mRecord->setPreferredMicrophoneFieldDimension(zoom);
     }
     return NO_INIT;
 }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a52da45..b322670 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -71,6 +71,7 @@
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
 static const int64_t kInitialDelayTimeUs     = 700000LL;
 static const int64_t kMaxMetadataSize = 0x4000000LL;   // 64MB max per-frame metadata size
+static const int64_t kMaxCttsOffsetTimeUs = 30 * 60 * 1000000LL;  // 30 minutes
 
 static const char kMetaKey_Version[]    = "com.android.version";
 static const char kMetaKey_Manufacturer[]      = "com.android.manufacturer";
@@ -136,13 +137,6 @@
     void resetInternal();
 
 private:
-    enum {
-        // TODO: need to increase this considering the bug
-        // about camera app not sending video frames continuously?
-        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
-        kSampleArraySize = 1000,
-    };
-
     // A helper class to handle faster write box with table entries
     template<class TYPE, unsigned ENTRY_SIZE>
     // ENTRY_SIZE: # of values in each entry
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index dbc287e..3f0bc7d 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -309,7 +309,6 @@
 void parseVorbisComment(
         AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
     // Haptic tag is only kept here as it will only be used in extractor to generate channel mask.
-    const char* const haptic = "haptic";
     struct {
         const char *const mTag;
         const char *mKey;
@@ -330,7 +329,7 @@
         { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
         { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
         { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
-        { "ANDROID_HAPTIC", haptic },
+        { "ANDROID_HAPTIC", AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT },
     };
 
         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
@@ -346,12 +345,12 @@
                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
                         AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
                     }
-                } else if (kMap[j].mKey == haptic) {
+                } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT) {
                     char *end;
                     errno = 0;
                     const int hapticChannelCount = strtol(&comment[tagLen + 1], &end, 10);
                     if (errno == 0) {
-                        AMediaFormat_setInt32(fileMeta, haptic, hapticChannelCount);
+                        AMediaFormat_setInt32(fileMeta, kMap[j].mKey, hapticChannelCount);
                     } else {
                         ALOGE("Error(%d) when parsing haptic channel count", errno);
                     }
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index b0ce688..29c3a35 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "RemoteMediaExtractor"
 #include <utils/Log.h>
 
+#include <binder/IPCThreadState.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/MediaSource.h>
@@ -51,6 +52,11 @@
     if (MEDIA_LOG) {
         mAnalyticsItem = MediaAnalyticsItem::create(kKeyExtractor);
 
+        // we're in the extractor service, we want to attribute to the app
+        // that invoked us.
+        int uid = IPCThreadState::self()->getCallingUid();
+        mAnalyticsItem->setUid(uid);
+
         // track the container format (mpeg, aac, wvm, etc)
         size_t ntracks = extractor->countTracks();
         mAnalyticsItem->setCString(kExtractorFormat, extractor->name());
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 2aa9ed8..c7b2719 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -967,6 +967,11 @@
         if (meta->findInt32(kKeyPcmEncoding, &pcmEncoding)) {
             msg->setInt32("pcm-encoding", pcmEncoding);
         }
+
+        int32_t hapticChannelCount;
+        if (meta->findInt32(kKeyHapticChannelCount, &hapticChannelCount)) {
+            msg->setInt32("haptic-channel-count", hapticChannelCount);
+        }
     }
 
     int32_t maxInputSize;
@@ -1708,6 +1713,11 @@
         if (msg->findInt32("pcm-encoding", &pcmEncoding)) {
             meta->setInt32(kKeyPcmEncoding, pcmEncoding);
         }
+
+        int32_t hapticChannelCount;
+        if (msg->findInt32("haptic-channel-count", &hapticChannelCount)) {
+            meta->setInt32(kKeyHapticChannelCount, hapticChannelCount);
+        }
     }
 
     int32_t maxInputSize;
diff --git a/media/libstagefright/codecs/aacdec/Android.bp b/media/libstagefright/codecs/aacdec/Android.bp
index 25628a2..e0bb5cd 100644
--- a/media/libstagefright/codecs/aacdec/Android.bp
+++ b/media/libstagefright/codecs/aacdec/Android.bp
@@ -29,12 +29,10 @@
 
     static_libs: ["libFraunhoferAAC"],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
         "libcutils",
-        "liblog",
     ],
     compile_multilib: "32",
 }
diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp
index ec1151b..0d677fe 100644
--- a/media/libstagefright/codecs/aacenc/Android.bp
+++ b/media/libstagefright/codecs/aacenc/Android.bp
@@ -26,11 +26,7 @@
 
     static_libs: ["libFraunhoferAAC"],
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
+
     compile_multilib: "32",
 }
diff --git a/media/libstagefright/codecs/amrnb/common/src/lsp.cpp b/media/libstagefright/codecs/amrnb/common/src/lsp.cpp
index 0e3f772..81d9cde 100644
--- a/media/libstagefright/codecs/amrnb/common/src/lsp.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/lsp.cpp
@@ -173,7 +173,7 @@
     *st = NULL;
 
     /* allocate memory */
-    if ((s = (lspState *) malloc(sizeof(lspState))) == NULL)
+    if ((s = (lspState *) calloc(sizeof(lspState), 1)) == NULL)
     {
         /* fprintf(stderr, "lsp_init: can not malloc state structure\n"); */
         return -1;
@@ -182,11 +182,13 @@
     /* Initialize quantization state */
     if (0 != Q_plsf_init(&s->qSt))
     {
+        lsp_exit(&s);
         return -1;
     }
 
     if (0 != lsp_reset(s))
     {
+        lsp_exit(&s);
         return -1;
     }
 
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index 880f161..f3b272b 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -101,11 +101,9 @@
         "libstagefright_amrwbdec",
     ],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
         "libstagefright_amrnb_common",
     ],
     compile_multilib: "32",
diff --git a/media/libstagefright/codecs/amrnb/dec/src/sp_dec.cpp b/media/libstagefright/codecs/amrnb/dec/src/sp_dec.cpp
index 2989b74..49cafff 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/sp_dec.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/sp_dec.cpp
@@ -268,13 +268,7 @@
     if (Decoder_amr_init(&s->decoder_amrState)
             || Post_Process_reset(&s->postHP_state))
     {
-        Speech_Decode_FrameState *tmp = s;
-        /*
-         *  dereferencing type-punned pointer avoid
-         *  breaking strict-aliasing rules
-         */
-        void** tempVoid = (void**) tmp;
-        GSMDecodeFrameExit(tempVoid);
+        free(s);
         return (-1);
     }
 
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index 19fd4a8..1c8b511 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -110,11 +110,9 @@
 
     static_libs: ["libstagefright_amrnbenc"],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
         "libstagefright_amrnb_common",
     ],
     compile_multilib: "32",
diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp
index b9d45c1..8327500 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/Android.bp
@@ -167,11 +167,9 @@
 
     static_libs: ["libstagefright_amrwbenc"],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
         "libstagefright_enc_common",
     ],
     compile_multilib: "32",
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 8a34845..567bcca 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -22,12 +22,7 @@
         "frameworks/native/include/media/openmax",
     ],
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     sanitize: {
         misc_undefined: [
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 6371828..0cd39e1 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -16,12 +16,7 @@
         "frameworks/native/include/media/openmax",
     ],
 
-    shared_libs: [
-        "libstagefright_foundation",
-        "libstagefright_omx",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     sanitize: {
         misc_undefined: [
diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp
index 3d4a44f..18a3f6b 100644
--- a/media/libstagefright/codecs/flac/dec/Android.bp
+++ b/media/libstagefright/codecs/flac/dec/Android.bp
@@ -28,12 +28,10 @@
         cfi: true,
     },
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
-        "liblog",
         "libstagefright_flacdec",
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
     ],
     compile_multilib: "32",
 }
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index b32ab08..4149ccd 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -19,13 +19,7 @@
         ],
         cfi: true,
     },
-
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     header_libs: ["libbase_headers"],
     static_libs: [
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index 7097688..c273179 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -12,12 +12,7 @@
         "frameworks/native/include/media/openmax",
     ],
 
-    shared_libs: [
-        "libstagefright_foundation",
-        "libstagefright_omx",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     cflags: ["-Werror"],
 
diff --git a/media/libstagefright/codecs/gsm/dec/Android.bp b/media/libstagefright/codecs/gsm/dec/Android.bp
index a973f70..3c5ebfe 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.bp
+++ b/media/libstagefright/codecs/gsm/dec/Android.bp
@@ -25,12 +25,7 @@
         cfi: true,
     },
 
-    shared_libs: [
-        "libstagefright_foundation",
-        "libstagefright_omx",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     static_libs: ["libgsm"],
     compile_multilib: "32",
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
index 60fc446..cc91d53 100644
--- a/media/libstagefright/codecs/hevcdec/Android.bp
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -30,12 +30,7 @@
         cfi: true,
     },
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     // We need this because the current asm generates the following link error:
     // requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
index 41141b1..0523143 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -91,12 +91,7 @@
 
     static_libs: ["libstagefright_m4vh263dec"],
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     sanitize: {
         misc_undefined: [
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index a8fcdd1..60750d9 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -24,7 +24,6 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/IOMX.h>
 
 #include "mp4dec_api.h"
 
@@ -118,9 +117,14 @@
                 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
                 List<BufferInfo *>::iterator it = outQueue.begin();
-                while ((*it)->mHeader != outHeader) {
+                while (it != outQueue.end() && (*it)->mHeader != outHeader) {
                     ++it;
                 }
+                if (it == outQueue.end()) {
+                    ALOGE("couldn't find port buffer %d in outQueue: b/109891727", mNumSamplesOutput & 1);
+                    android_errorWriteLog(0x534e4554, "109891727");
+                    return;
+                }
 
                 BufferInfo *outInfo = *it;
                 outInfo->mOwnedByUs = false;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index d4f7d50..d38f4b1 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -77,12 +77,7 @@
 
     static_libs: ["libstagefright_m4vh263enc"],
 
-    shared_libs: [
-        "libstagefright_foundation",
-        "libstagefright_omx",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     sanitize: {
         misc_undefined: [
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index 2154f84..9173ed6 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -105,12 +105,7 @@
         cfi: true,
     },
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     static_libs: ["libstagefright_mp3dec"],
     compile_multilib: "32",
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index c655544..26e786e 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -20,12 +20,7 @@
         "frameworks/native/include/media/openmax",
     ],
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     ldflags: ["-Wl,-Bsymbolic"],
 
diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp
index 174f183..abd21d7 100644
--- a/media/libstagefright/codecs/on2/dec/Android.bp
+++ b/media/libstagefright/codecs/on2/dec/Android.bp
@@ -14,12 +14,7 @@
 
     static_libs: ["libvpx"],
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
 
     cflags: ["-Werror"],
 
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index 891a771..ea46bad 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -30,11 +30,7 @@
 
     static_libs: ["libvpx"],
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
+
     compile_multilib: "32",
 }
diff --git a/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h
index b4904bf..c5c2abf 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h
@@ -23,8 +23,6 @@
 #include <OMX_VideoExt.h>
 #include <OMX_IndexExt.h>
 
-#include <hardware/gralloc.h>
-
 #include "vpx/vpx_encoder.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/vp8cx.h"
diff --git a/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h
index 85df69a..308a9ac 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h
@@ -23,8 +23,6 @@
 #include <OMX_VideoExt.h>
 #include <OMX_IndexExt.h>
 
-#include <hardware/gralloc.h>
-
 #include "vpx/vpx_encoder.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/vp8cx.h"
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index 263d134..7208d69 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -23,8 +23,6 @@
 #include <OMX_VideoExt.h>
 #include <OMX_IndexExt.h>
 
-#include <hardware/gralloc.h>
-
 #include "vpx/vpx_encoder.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/vp8cx.h"
diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp
index afe459d..bfcae07 100644
--- a/media/libstagefright/codecs/opus/dec/Android.bp
+++ b/media/libstagefright/codecs/opus/dec/Android.bp
@@ -12,12 +12,10 @@
         "frameworks/native/include/media/openmax",
     ],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
         "libopus",
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
     ],
 
     cflags: ["-Werror"],
diff --git a/media/libstagefright/codecs/raw/Android.bp b/media/libstagefright/codecs/raw/Android.bp
index f822445..1c23bad 100644
--- a/media/libstagefright/codecs/raw/Android.bp
+++ b/media/libstagefright/codecs/raw/Android.bp
@@ -24,11 +24,7 @@
         cfi: true,
     },
 
-    shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
-    ],
+    defaults: ["omx_soft_libs"],
+
     compile_multilib: "32",
 }
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.bp b/media/libstagefright/codecs/vorbis/dec/Android.bp
index a9265cb..2d1a922 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.bp
+++ b/media/libstagefright/codecs/vorbis/dec/Android.bp
@@ -12,12 +12,10 @@
         "frameworks/native/include/media/openmax",
     ],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
         "libvorbisidec",
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
-        "liblog",
     ],
 
     cflags: ["-Werror"],
diff --git a/media/libstagefright/codecs/xaacdec/Android.bp b/media/libstagefright/codecs/xaacdec/Android.bp
index 7392f1e..e49eb8f 100644
--- a/media/libstagefright/codecs/xaacdec/Android.bp
+++ b/media/libstagefright/codecs/xaacdec/Android.bp
@@ -24,12 +24,10 @@
 
     static_libs: ["libxaacdec"],
 
+    defaults: ["omx_soft_libs"],
+
     shared_libs: [
-        "libstagefright_omx",
-        "libstagefright_foundation",
-        "libutils",
         "libcutils",
-        "liblog",
     ],
 
     compile_multilib: "32",
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index e20174f..f785bfa 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -115,6 +115,9 @@
             <Limit name="block-count" range="1-4096" /> <!-- max 512x512 -->
             <Limit name="blocks-per-second" range="1-122880" />
             <Limit name="bitrate" range="1-10000000" />
+            <Limit name="complexity" range="0-10"  default="0" />
+            <Limit name="quality" range="0-100"  default="80" />
+            <Feature name="bitrate-modes" value="VBR,CBR,CQ" />
         </MediaCodec>
         <MediaCodec name="c2.android.mpeg4.encoder" type="video/mp4v-es">
             <Alias name="OMX.google.mpeg4.encoder" />
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index d153598..c62c2cd 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -2125,7 +2125,10 @@
     size_t offset = 0;
     while (offset < buffer->size()) {
         const uint8_t *adtsHeader = buffer->data() + offset;
-        CHECK_LT(offset + 5, buffer->size());
+        if (buffer->size() <= offset+5) {
+            ALOGV("buffer does not contain a complete header");
+            return ERROR_MALFORMED;
+        }
         // non-const pointer for decryption if needed
         uint8_t *adtsFrame = buffer->data() + offset;
 
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 9d46d2d..784fd36 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -286,7 +286,7 @@
     double mFps;
     double mCaptureFps;
     bool mCreateInputBuffersSuspended;
-    uint32_t mLatency;
+    std::optional<uint32_t> mLatency;
 
     bool mTunneled;
 
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index 18e5f10..af04dad 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -70,8 +70,8 @@
     status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
 
     status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
-    status_t setMicrophoneDirection(audio_microphone_direction_t direction);
-    status_t setMicrophoneFieldDimension(float zoom);
+    status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
+    status_t setPreferredMicrophoneFieldDimension(float zoom);
 
     status_t getPortId(audio_port_handle_t *portId) const;
 
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 803155d..6f19023 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -82,10 +82,6 @@
         kWhatSwitch                          = 'swch',
     };
 
-    enum {
-        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
-    };
-
     int  mFd;
     int mNextFd;
     sp<MetaData> mStartMeta;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 2dca5c3..8b6944b 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -772,6 +772,7 @@
 constexpr char KEY_LANGUAGE[] = "language";
 constexpr char KEY_LATENCY[] = "latency";
 constexpr char KEY_LEVEL[] = "level";
+constexpr char KEY_MAX_B_FRAMES[] = "max-bframes";
 constexpr char KEY_MAX_BIT_RATE[] = "max-bitrate";
 constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
 constexpr char KEY_MAX_HEIGHT[] = "max-height";
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 75fd0d9..8dc2dd5 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -62,8 +62,6 @@
     kKeyAV1C              = 'av1c',  // raw data
     kKeyThumbnailHVCC     = 'thvc',  // raw data
     kKeyD263              = 'd263',  // raw data
-    kKeyVorbisInfo        = 'vinf',  // raw data
-    kKeyVorbisBooks       = 'vboo',  // raw data
     kKeyOpusHeader        = 'ohdr',  // raw data
     kKeyOpusCodecDelay    = 'ocod',  // uint64_t (codec delay in ns)
     kKeyOpusSeekPreRoll   = 'ospr',  // uint64_t (seek preroll in ns)
@@ -238,6 +236,8 @@
     kKeyOpaqueCSD0       = 'csd0',
     kKeyOpaqueCSD1       = 'csd1',
     kKeyOpaqueCSD2       = 'csd2',
+
+    kKeyHapticChannelCount = 'hapC',
 };
 
 enum {
diff --git a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.cpp b/media/libstagefright/mpeg2ts/HlsSampleDecryptor.cpp
index e32f676..7d446ab 100644
--- a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.cpp
+++ b/media/libstagefright/mpeg2ts/HlsSampleDecryptor.cpp
@@ -149,6 +149,11 @@
     }
 
     // ADTS header is included in the size
+    if (size < adtsHdrSize) {
+        ALOGV("processAAC: size (%zu) < adtsHdrSize (%zu)", size, adtsHdrSize);
+        android_errorWriteLog(0x534e4554, "128433933");
+        return;
+    }
     size_t offset = adtsHdrSize;
     size_t remainingBytes = size - adtsHdrSize;
 
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 4383004..b959f6c 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -11,11 +11,6 @@
         "OMXNodeInstance.cpp",
         "OMXUtils.cpp",
         "OmxGraphicBufferSource.cpp",
-        "SimpleSoftOMXComponent.cpp",
-        "SoftOMXComponent.cpp",
-        "SoftOMXPlugin.cpp",
-        "SoftVideoDecoderOMXComponent.cpp",
-        "SoftVideoEncoderOMXComponent.cpp",
         "1.0/Omx.cpp",
         "1.0/OmxStore.cpp",
         "1.0/WGraphicBufferSource.cpp",
@@ -56,6 +51,7 @@
         "libvndksupport",
         "android.hardware.media.omx@1.0",
         "android.hardware.graphics.bufferqueue@1.0",
+        "libstagefright_omx_soft",
     ],
 
     export_shared_lib_headers: [
@@ -81,6 +77,64 @@
     },
 }
 
+cc_defaults {
+    name: "omx_soft_libs",
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libstagefright_foundation",
+        "libstagefright_omx_soft",
+    ],
+}
+
+cc_library_shared {
+    name: "libstagefright_omx_soft",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+
+    srcs: [
+        "SimpleSoftOMXComponent.cpp",
+        "SoftOMXComponent.cpp",
+        "SoftOMXPlugin.cpp",
+        "SoftVideoDecoderOMXComponent.cpp",
+        "SoftVideoEncoderOMXComponent.cpp",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libui",
+        "libstagefright_foundation",
+    ],
+
+    export_shared_lib_headers: [
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wno-unused-parameter",
+        "-Wno-documentation",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
+
 cc_library_shared {
     name: "libstagefright_omx_utils",
     vendor_available: true,
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 2fbbb44..d75acda 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -559,7 +559,7 @@
         if (nativeMeta.nFenceFd >= 0) {
             sp<Fence> fence = new Fence(nativeMeta.nFenceFd);
             nativeMeta.nFenceFd = -1;
-            status_t err = fence->wait(IOMX::kFenceTimeoutMs);
+            status_t err = fence->wait(kFenceTimeoutMs);
             if (err != OK) {
                 ALOGE("Timed out waiting on input fence");
                 return NULL;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXComponent.h
index 3ab6f88..79f0c77 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXComponent.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXComponent.h
@@ -21,12 +21,15 @@
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AString.h>
 #include <utils/RefBase.h>
-
+#include <utils/Log.h>
 #include <OMX_Component.h>
 
 namespace android {
 
 struct SoftOMXComponent : public RefBase {
+    enum {
+        kFenceTimeoutMs = 1000
+    };
     SoftOMXComponent(
             const char *name,
             const OMX_CALLBACKTYPE *callbacks,
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoDecoderOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoDecoderOMXComponent.h
index 3b381ce..d7c1658 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoDecoderOMXComponent.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoDecoderOMXComponent.h
@@ -23,7 +23,10 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/foundation/ColorUtils.h>
-#include <media/IOMX.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/openmax/OMX_Video.h>
+#include <media/openmax/OMX_VideoExt.h>
+
 #include <media/hardware/HardwareAPI.h>
 
 #include <utils/RefBase.h>
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoEncoderOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoEncoderOMXComponent.h
index 2d6f31b..9cb72dd 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoEncoderOMXComponent.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoEncoderOMXComponent.h
@@ -18,7 +18,9 @@
 
 #define SOFT_VIDEO_ENCODER_OMX_COMPONENT_H_
 
-#include <media/IOMX.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/openmax/OMX_Video.h>
+#include <media/openmax/OMX_VideoExt.h>
 
 #include "SimpleSoftOMXComponent.h"
 
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index b0a303e..26e0884 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -177,8 +177,8 @@
         const void *headerData3;
         size_t headerSize1, headerSize2 = sizeof(headerData2), headerSize3;
 
-        if (!md->findData(kKeyVorbisInfo, &type, &headerData1, &headerSize1)
-            || !md->findData(kKeyVorbisBooks, &type, &headerData3, &headerSize3)) {
+        if (!md->findData(kKeyOpaqueCSD0, &type, &headerData1, &headerSize1)
+            || !md->findData(kKeyOpaqueCSD1, &type, &headerData3, &headerSize3)) {
             ALOGE("Missing header format keys for vorbis track");
             md->dumpToLog();
             return NULL;
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index f5245c1..5443f2c 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -1,6 +1,12 @@
 // Signature format: 2.0
 package media.codecs {
 
+  public class Alias {
+    ctor public Alias();
+    method public String getName();
+    method public void setName(String);
+  }
+
   public class Decoders {
     ctor public Decoders();
     method public java.util.List<media.codecs.MediaCodec> getMediaCodec();
@@ -23,6 +29,23 @@
     method public void setValue(String);
   }
 
+  public class Include {
+    ctor public Include();
+    method public String getHref();
+    method public void setHref(String);
+  }
+
+  public class Included {
+    ctor public Included();
+    method public media.codecs.Decoders getDecoders_optional();
+    method public media.codecs.Encoders getEncoders_optional();
+    method public java.util.List<media.codecs.Include> getInclude_optional();
+    method public media.codecs.Settings getSettings_optional();
+    method public void setDecoders_optional(media.codecs.Decoders);
+    method public void setEncoders_optional(media.codecs.Encoders);
+    method public void setSettings_optional(media.codecs.Settings);
+  }
+
   public class Limit {
     ctor public Limit();
     method public String getIn();
@@ -47,12 +70,13 @@
 
   public class MediaCodec {
     ctor public MediaCodec();
-    method public java.util.List<media.codecs.Feature> getFeature();
-    method public java.util.List<media.codecs.Limit> getLimit();
+    method public java.util.List<media.codecs.Alias> getAlias_optional();
+    method public java.util.List<media.codecs.Feature> getFeature_optional();
+    method public java.util.List<media.codecs.Limit> getLimit_optional();
     method public String getName();
-    method public java.util.List<media.codecs.Quirk> getQuirk();
-    method public java.util.List<media.codecs.Type> getType();
+    method public java.util.List<media.codecs.Quirk> getQuirk_optional();
     method public String getType();
+    method public java.util.List<media.codecs.Type> getType_optional();
     method public String getUpdate();
     method public void setName(String);
     method public void setType(String);
@@ -61,9 +85,13 @@
 
   public class MediaCodecs {
     ctor public MediaCodecs();
-    method public java.util.List<media.codecs.Decoders> getDecoders();
-    method public java.util.List<media.codecs.Encoders> getEncoders();
-    method public java.util.List<media.codecs.Settings> getSettings();
+    method public media.codecs.Decoders getDecoders_optional();
+    method public media.codecs.Encoders getEncoders_optional();
+    method public java.util.List<media.codecs.Include> getInclude_optional();
+    method public media.codecs.Settings getSettings_optional();
+    method public void setDecoders_optional(media.codecs.Decoders);
+    method public void setEncoders_optional(media.codecs.Encoders);
+    method public void setSettings_optional(media.codecs.Settings);
   }
 
   public class Quirk {
@@ -89,6 +117,7 @@
 
   public class Type {
     ctor public Type();
+    method public java.util.List<media.codecs.Alias> getAlias();
     method public java.util.List<media.codecs.Feature> getFeature();
     method public java.util.List<media.codecs.Limit> getLimit();
     method public String getName();
@@ -99,7 +128,8 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static media.codecs.MediaCodecs read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static media.codecs.Included readIncluded(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static media.codecs.MediaCodecs readMediaCodecs(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 4faba87..77193a2 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -20,11 +20,22 @@
            xmlns:xs="http://www.w3.org/2001/XMLSchema">
     <xs:element name="MediaCodecs">
         <xs:complexType>
-            <xs:sequence>
-                <xs:element name="Decoders" type="Decoders" maxOccurs="unbounded"/>
-                <xs:element name="Encoders" type="Encoders" maxOccurs="unbounded"/>
-                <xs:element name="Settings" type="Settings" maxOccurs="unbounded"/>
-            </xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="Include" type="Include" maxOccurs="unbounded"/>
+                <xs:element name="Settings" type="Settings"/>
+                <xs:element name="Decoders" type="Decoders"/>
+                <xs:element name="Encoders" type="Encoders"/>
+            </xs:choice>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="Included">
+        <xs:complexType>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="Include" type="Include" maxOccurs="unbounded"/>
+                <xs:element name="Settings" type="Settings"/>
+                <xs:element name="Decoders" type="Decoders"/>
+                <xs:element name="Encoders" type="Encoders"/>
+            </xs:choice>
         </xs:complexType>
     </xs:element>
     <xs:complexType name="Decoders">
@@ -43,12 +54,13 @@
         </xs:sequence>
     </xs:complexType>
     <xs:complexType name="MediaCodec">
-        <xs:sequence>
-            <xs:element name="Quirk" type="Quirk" maxOccurs="unbounded"/>
-            <xs:element name="Type" type="Type" maxOccurs="unbounded"/>
-            <xs:element name="Limit" type="Limit" maxOccurs="unbounded"/>
-            <xs:element name="Feature" type="Feature" maxOccurs="unbounded"/>
-        </xs:sequence>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Quirk" type="Quirk" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Type" type="Type" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Alias" type="Alias" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Limit" type="Limit" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Feature" type="Feature" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:choice>
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="type" type="xs:string"/>
         <xs:attribute name="update" type="xs:string"/>
@@ -58,12 +70,16 @@
     </xs:complexType>
     <xs:complexType name="Type">
         <xs:sequence>
-            <xs:element name="Limit" type="Limit" maxOccurs="unbounded"/>
-            <xs:element name="Feature" type="Feature" maxOccurs="unbounded"/>
+            <xs:element name="Alias" type="Alias" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Limit" type="Limit" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Feature" type="Feature" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="update" type="xs:string"/>
     </xs:complexType>
+    <xs:complexType name="Alias">
+        <xs:attribute name="name" type="xs:string"/>
+    </xs:complexType>
     <xs:complexType name="Limit">
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="default" type="xs:string"/>
@@ -86,4 +102,7 @@
         <xs:attribute name="value" type="xs:string"/>
         <xs:attribute name="update" type="xs:string"/>
     </xs:complexType>
+    <xs:complexType name="Include">
+        <xs:attribute name="href" type="xs:string"/>
+    </xs:complexType>
 </xs:schema>
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index 8cfcd79..f6c325c 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -2,7 +2,5 @@
     class main
     user media
     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
-    # TODO(b/123275379): Remove updatable when http://aosp/878198 has landed
-    updatable
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index f4cc704..a4f5730 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -73,6 +73,7 @@
     shared_libs: [
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hidl.token@1.0-utils",
+        "libandroid_runtime_lazy",
         "libbinder",
         "libmedia",
         "libmedia_omx",
@@ -93,12 +94,6 @@
         "libmediandk_utils",
     ],
 
-    required: [
-        // libmediandk may be used by Java and non-Java things. When lower-level things use it,
-        // they shouldn't have to take on the cost of loading libandroid_runtime.
-        "libandroid_runtime",
-    ],
-
     export_include_dirs: ["include"],
 
     export_shared_lib_headers: [
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 0891f2a..7979c2f 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -23,7 +23,8 @@
 #include <jni.h>
 #include <unistd.h>
 
-#include <binder/IBinder.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_util_Binder.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
@@ -39,67 +40,9 @@
 #include "../../libstagefright/include/NuCachedSource2.h"
 #include "NdkMediaDataSourceCallbacksPriv.h"
 
-#include <mutex> // std::call_once,once_flag
-#include <dlfcn.h> // dlopen
 
 using namespace android;
 
-// load libandroid_runtime.so lazily.
-// A vendor process may use libmediandk but should not depend on libandroid_runtime.
-// TODO(jooyung): remove duplicate (b/125550121)
-// frameworks/native/libs/binder/ndk/ibinder_jni.cpp
-namespace {
-
-typedef JNIEnv* (*getJNIEnv_t)();
-typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
-
-getJNIEnv_t getJNIEnv_;
-ibinderForJavaObject_t ibinderForJavaObject_;
-
-std::once_flag mLoadFlag;
-
-void load() {
-    std::call_once(mLoadFlag, []() {
-        void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
-        if (handle == nullptr) {
-            ALOGE("Could not open libandroid_runtime.");
-            return;
-        }
-
-        getJNIEnv_ = reinterpret_cast<getJNIEnv_t>(
-                dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"));
-        if (getJNIEnv_ == nullptr) {
-            ALOGE("Could not find AndroidRuntime::getJNIEnv.");
-            // no return
-        }
-
-        ibinderForJavaObject_ = reinterpret_cast<ibinderForJavaObject_t>(
-                dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
-        if (ibinderForJavaObject_ == nullptr) {
-            ALOGE("Could not find ibinderForJavaObject.");
-            // no return
-        }
-    });
-}
-
-JNIEnv* getJNIEnv() {
-    load();
-    if (getJNIEnv_ == nullptr) {
-        return nullptr;
-    }
-    return (getJNIEnv_)();
-}
-
-sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) {
-    load();
-    if (ibinderForJavaObject_ == nullptr) {
-        return nullptr;
-    }
-    return (ibinderForJavaObject_)(env, obj);
-}
-
-} // namespace
-
 struct AMediaDataSource {
     void *userdata;
     AMediaDataSourceReadAt readAt;
@@ -181,14 +124,9 @@
     if (obj == NULL) {
         return NULL;
     }
-    sp<IBinder> binder;
     switch (version) {
         case 1:
-            binder = ibinderForJavaObject(env, obj);
-            if (binder == NULL) {
-                return NULL;
-            }
-            return interface_cast<IMediaHTTPService>(binder);
+            return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
         case 2:
             return new JMedia2HTTPService(env, obj);
         default:
@@ -241,7 +179,7 @@
 
     switch (version) {
         case 1:
-            env = getJNIEnv();
+            env = AndroidRuntime::getJNIEnv();
             clazz = "android/media/MediaHTTPService";
             method = "createHttpServiceBinderIfNecessary";
             signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index ed88cf3..51138c8 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -324,6 +324,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_GENRE = "genre";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLUMNS = "grid-cols";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows";
+EXPORT const char* AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT = "haptic-channel-count";
 EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info";
 EXPORT const char* AMEDIAFORMAT_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
 EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 259481d..fd43f36 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -209,6 +209,7 @@
 extern const char* AMEDIAFORMAT_KEY_EXIF_SIZE __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_FRAME_COUNT __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_ICC_PROFILE __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_IS_SYNC_FRAME __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_LOCATION __INTRODUCED_IN(29);
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 4725e9e..f666ad0 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -89,6 +89,7 @@
     AMEDIAFORMAT_KEY_GENRE; # var introduced=29
     AMEDIAFORMAT_KEY_GRID_COLUMNS; # var introduced=28
     AMEDIAFORMAT_KEY_GRID_ROWS; # var introduced=28
+    AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT; # var introduced=29
     AMEDIAFORMAT_KEY_HDR_STATIC_INFO; # var introduced=28
     AMEDIAFORMAT_KEY_HEIGHT; # var introduced=21
     AMEDIAFORMAT_KEY_ICC_PROFILE; # var introduced=29
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 2fb24f5..cb681e0 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -130,6 +130,14 @@
     return ok;
 }
 
+bool captureMediaOutputAllowed(pid_t pid, uid_t uid) {
+    if (isAudioServerOrRootUid(uid)) return true;
+    static const String16 sCaptureMediaOutput("android.permission.CAPTURE_MEDIA_OUTPUT");
+    bool ok = PermissionCache::checkPermission(sCaptureMediaOutput, pid, uid);
+    if (!ok) ALOGE("Request requires android.permission.CAPTURE_MEDIA_OUTPUT");
+    return ok;
+}
+
 bool captureHotwordAllowed(pid_t pid, uid_t uid) {
     // CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
     bool ok = recordingAllowed(String16(""), pid, uid);
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 94370ee..9377ff3 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -74,6 +74,7 @@
 bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid);
 void finishRecording(const String16& opPackageName, uid_t uid);
 bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
+bool captureMediaOutputAllowed(pid_t pid, uid_t uid);
 bool captureHotwordAllowed(pid_t pid, uid_t uid);
 bool settingsAllowed();
 bool modifyAudioRoutingAllowed();
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
new file mode 100644
index 0000000..96ad54b
--- /dev/null
+++ b/services/audioflinger/Android.bp
@@ -0,0 +1,73 @@
+
+
+cc_library_shared {
+    name: "libaudioflinger",
+
+    srcs: [
+        "AudioFlinger.cpp",
+        "AudioHwDevice.cpp",
+        "AudioStreamOut.cpp",
+        "AudioWatchdog.cpp",
+        "BufLog.cpp",
+        "Effects.cpp",
+        "FastCapture.cpp",
+        "FastCaptureDumpState.cpp",
+        "FastCaptureState.cpp",
+        "FastMixer.cpp",
+        "FastMixerDumpState.cpp",
+        "FastMixerState.cpp",
+        "FastThread.cpp",
+        "FastThreadDumpState.cpp",
+        "FastThreadState.cpp",
+        "NBAIO_Tee.cpp",
+        "PatchPanel.cpp",
+        "SpdifStreamOut.cpp",
+        "StateQueue.cpp",
+        "Threads.cpp",
+        "Tracks.cpp",
+        "TypedLogger.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/services/audiopolicy",
+        "frameworks/av/services/medialog",
+    ],
+
+    shared_libs: [
+        "libaudiohal",
+        "libaudioprocessing",
+        "libaudiospdif",
+        "libaudioutils",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libbinder",
+        "libaudioclient",
+        "libmedialogservice",
+        "libmediametrics",
+        "libmediautils",
+        "libnbaio",
+        "libnblog",
+        "libpowermanager",
+        "libmediautils",
+        "libmemunreachable",
+        "libmedia_helper",
+        "libvibrator",
+    ],
+
+    static_libs: [
+        "libcpustats",
+        "libsndfile",
+    ],
+
+    cflags: [
+        "-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
+        "-fvisibility=hidden",
+        "-Werror",
+        "-Wall",
+    ],
+    sanitize: {
+        integer_overflow: true,
+    },
+
+}
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
deleted file mode 100644
index 40980a6..0000000
--- a/services/audioflinger/Android.mk
+++ /dev/null
@@ -1,74 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=               \
-    AudioFlinger.cpp            \
-    Threads.cpp                 \
-    Tracks.cpp                  \
-    AudioHwDevice.cpp           \
-    AudioStreamOut.cpp          \
-    SpdifStreamOut.cpp          \
-    Effects.cpp                 \
-    PatchPanel.cpp              \
-    StateQueue.cpp              \
-    BufLog.cpp                  \
-    TypedLogger.cpp             \
-    NBAIO_Tee.cpp               \
-
-LOCAL_C_INCLUDES := \
-    frameworks/av/services/audiopolicy \
-    frameworks/av/services/medialog \
-    $(call include-path-for, audio-utils)
-
-LOCAL_SHARED_LIBRARIES := \
-    libaudiohal \
-    libaudioprocessing \
-    libaudiospdif \
-    libaudioutils \
-    libcutils \
-    libutils \
-    liblog \
-    libbinder \
-    libaudioclient \
-    libmedialogservice \
-    libmediametrics \
-    libmediautils \
-    libnbaio \
-    libnblog \
-    libpowermanager \
-    libmediautils \
-    libmemunreachable \
-    libmedia_helper \
-    libvibrator
-
-LOCAL_STATIC_LIBRARIES := \
-    libcpustats \
-    libsndfile \
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libaudioflinger
-
-LOCAL_SRC_FILES += \
-    AudioWatchdog.cpp        \
-    FastCapture.cpp          \
-    FastCaptureDumpState.cpp \
-    FastCaptureState.cpp     \
-    FastMixer.cpp            \
-    FastMixerDumpState.cpp   \
-    FastMixerState.cpp       \
-    FastThread.cpp           \
-    FastThreadDumpState.cpp  \
-    FastThreadState.cpp
-
-LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
-
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := integer_overflow
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b8f88cf..0825cb4 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -466,15 +466,8 @@
 
 bool AudioFlinger::dumpTryLock(Mutex& mutex)
 {
-    bool locked = false;
-    for (int i = 0; i < kDumpLockRetries; ++i) {
-        if (mutex.tryLock() == NO_ERROR) {
-            locked = true;
-            break;
-        }
-        usleep(kDumpLockSleepUs);
-    }
-    return locked;
+    status_t err = mutex.timedLock(kDumpLockTimeoutNs);
+    return err == NO_ERROR;
 }
 
 status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
@@ -3297,7 +3290,8 @@
         // output threads.
         // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
         // because of code checking output when entering the function.
-        // Note: io is never 0 when creating an effect on an input
+        // Note: io is never AUDIO_IO_HANDLE_NONE when creating an effect on an input by APM.
+        // An AudioEffect created from the Java API will have io as AUDIO_IO_HANDLE_NONE.
         if (io == AUDIO_IO_HANDLE_NONE) {
             // look for the thread where the specified audio session is present
             io = findIoHandleBySessionId_l(sessionId, mPlaybackThreads);
@@ -3307,6 +3301,25 @@
             if (io == AUDIO_IO_HANDLE_NONE) {
                 io = findIoHandleBySessionId_l(sessionId, mMmapThreads);
             }
+
+            // If you wish to create a Record preprocessing AudioEffect in Java,
+            // you MUST create an AudioRecord first and keep it alive so it is picked up above.
+            // Otherwise it will fail when created on a Playback thread by legacy
+            // handling below.  Ditto with Mmap, the associated Mmap track must be created
+            // before creating the AudioEffect or the io handle must be specified.
+            //
+            // Detect if the effect is created after an AudioRecord is destroyed.
+            if (getOrphanEffectChain_l(sessionId).get() != nullptr) {
+                ALOGE("%s: effect %s with no specified io handle is denied because the AudioRecord"
+                        " for session %d no longer exists",
+                         __func__, desc.name, sessionId);
+                lStatus = PERMISSION_DENIED;
+                goto Exit;
+            }
+
+            // Legacy handling of creating an effect on an expired or made-up
+            // session id.  We think that it is a Playback effect.
+            //
             // If no output thread contains the requested session ID, default to
             // first output. The effect chain will be moved to the correct output
             // thread when a track with the same session ID is created
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index ec5dfb1..5a65ea8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -431,8 +431,7 @@
     static uint32_t         mScreenState;
 
     // Internal dump utilities.
-    static const int kDumpLockRetries = 50;
-    static const int kDumpLockSleepUs = 20000;
+    static const int kDumpLockTimeoutNs = 1 * NANOS_PER_SECOND;
     static bool dumpTryLock(Mutex& mutex);
     void dumpPermissionDenial(int fd, const Vector<String16>& args);
     void dumpClients(int fd, const Vector<String16>& args);
@@ -615,9 +614,9 @@
         virtual binder::Status   stop();
         virtual binder::Status   getActiveMicrophones(
                 std::vector<media::MicrophoneInfo>* activeMicrophones);
-        virtual binder::Status   setMicrophoneDirection(
+        virtual binder::Status   setPreferredMicrophoneDirection(
                 int /*audio_microphone_direction_t*/ direction);
-        virtual binder::Status   setMicrophoneFieldDimension(float zoom);
+        virtual binder::Status   setPreferredMicrophoneFieldDimension(float zoom);
 
     private:
         const sp<RecordThread::RecordTrack> mRecordTrack;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index ecaeb52..2b34267 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2335,13 +2335,10 @@
 
 void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
     String8 result;
 
-    size_t numEffects = mEffects.size();
-    snprintf(buffer, SIZE, "    %zu effects for session %d\n", numEffects, mSessionId);
-    result.append(buffer);
+    const size_t numEffects = mEffects.size();
+    result.appendFormat("    %zu effects for session %d\n", numEffects, mSessionId);
 
     if (numEffects) {
         bool locked = AudioFlinger::dumpTryLock(mLock);
@@ -2369,6 +2366,8 @@
         if (locked) {
             mLock.unlock();
         }
+    } else {
+        write(fd, result.string(), result.size());
     }
 }
 
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index ab4af33..ec1f86c 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -71,8 +71,8 @@
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
-            status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
-            status_t    setMicrophoneFieldDimension(float zoom);
+            status_t    setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
+            status_t    setPreferredMicrophoneFieldDimension(float zoom);
 
     static  bool        checkServerLatencySupported(
                                 audio_format_t format, audio_input_flags_t flags) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3ecb37d..984d9fe 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7245,7 +7245,7 @@
                 } else {
                     // FIXME could do a partial drop of framesOut
                     if (activeTrack->mFramesToDrop > 0) {
-                        activeTrack->mFramesToDrop -= framesOut;
+                        activeTrack->mFramesToDrop -= (ssize_t)framesOut;
                         if (activeTrack->mFramesToDrop <= 0) {
                             activeTrack->clearSyncStartEvent();
                         }
@@ -7718,18 +7718,19 @@
     return status;
 }
 
-status_t AudioFlinger::RecordThread::setMicrophoneDirection(audio_microphone_direction_t direction)
+status_t AudioFlinger::RecordThread::setPreferredMicrophoneDirection(
+            audio_microphone_direction_t direction)
 {
-    ALOGV("setMicrophoneDirection(%d)", direction);
+    ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     AutoMutex _l(mLock);
-    return mInput->stream->setMicrophoneDirection(direction);
+    return mInput->stream->setPreferredMicrophoneDirection(direction);
 }
 
-status_t AudioFlinger::RecordThread::setMicrophoneFieldDimension(float zoom)
+status_t AudioFlinger::RecordThread::setPreferredMicrophoneFieldDimension(float zoom)
 {
-    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     AutoMutex _l(mLock);
-    return mInput->stream->setMicrophoneFieldDimension(zoom);
+    return mInput->stream->setPreferredMicrophoneFieldDimension(zoom);
 }
 
 void AudioFlinger::RecordThread::updateMetadata_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 47e580b..e5abce7 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1607,8 +1607,8 @@
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
-            status_t    setMicrophoneDirection(audio_microphone_direction_t direction);
-            status_t    setMicrophoneFieldDimension(float zoom);
+            status_t    setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
+            status_t    setPreferredMicrophoneFieldDimension(float zoom);
 
             void        updateMetadata_l() override;
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5a43696..fbf8fef 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1838,16 +1838,16 @@
             mRecordTrack->getActiveMicrophones(activeMicrophones));
 }
 
-binder::Status AudioFlinger::RecordHandle::setMicrophoneDirection(
+binder::Status AudioFlinger::RecordHandle::setPreferredMicrophoneDirection(
         int /*audio_microphone_direction_t*/ direction) {
     ALOGV("%s()", __func__);
-    return binder::Status::fromStatusT(mRecordTrack->setMicrophoneDirection(
+    return binder::Status::fromStatusT(mRecordTrack->setPreferredMicrophoneDirection(
             static_cast<audio_microphone_direction_t>(direction)));
 }
 
-binder::Status AudioFlinger::RecordHandle::setMicrophoneFieldDimension(float zoom) {
+binder::Status AudioFlinger::RecordHandle::setPreferredMicrophoneFieldDimension(float zoom) {
     ALOGV("%s()", __func__);
-    return binder::Status::fromStatusT(mRecordTrack->setMicrophoneFieldDimension(zoom));
+    return binder::Status::fromStatusT(mRecordTrack->setPreferredMicrophoneFieldDimension(zoom));
 }
 
 // ----------------------------------------------------------------------------
@@ -2144,22 +2144,22 @@
     }
 }
 
-status_t AudioFlinger::RecordThread::RecordTrack::setMicrophoneDirection(
+status_t AudioFlinger::RecordThread::RecordTrack::setPreferredMicrophoneDirection(
         audio_microphone_direction_t direction) {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
-        return recordThread->setMicrophoneDirection(direction);
+        return recordThread->setPreferredMicrophoneDirection(direction);
     } else {
         return BAD_VALUE;
     }
 }
 
-status_t AudioFlinger::RecordThread::RecordTrack::setMicrophoneFieldDimension(float zoom) {
+status_t AudioFlinger::RecordThread::RecordTrack::setPreferredMicrophoneFieldDimension(float zoom) {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
-        return recordThread->setMicrophoneFieldDimension(zoom);
+        return recordThread->setPreferredMicrophoneFieldDimension(zoom);
     } else {
         return BAD_VALUE;
     }
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index acbfc9e..a2cf7aa 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -198,6 +198,7 @@
     //dump state
     virtual status_t    dump(int fd) = 0;
 
+    virtual status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) = 0;
     virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0;
     virtual bool isDirectOutputSupported(const audio_config_base_t& config,
                                          const audio_attributes_t& attributes) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 635de6f..5b4e2eb 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -334,6 +334,13 @@
 void AudioInputDescriptor::updateClientRecordingConfiguration(
     int event, const sp<RecordClientDescriptor>& client)
 {
+    // do not send callback if starting and no device is selected yet to avoid
+    // double callbacks from startInput() before and after the device is selected
+    if (event ==  RECORD_CONFIG_EVENT_START
+            && mPatchHandle == AUDIO_PATCH_HANDLE_NONE) {
+        return;
+    }
+
     const audio_config_base_t sessionConfig = client->config();
     const record_client_info_t recordClientInfo{client->uid(), client->session(),
                                                 client->source(), client->portId(),
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index f7289ca..8f15016 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -47,32 +47,29 @@
 
     int indexCriterion = 0;
     for (const auto &criterion : mCriteria) {
-        dst->appendFormat("%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
+        dst->appendFormat("%*s- Criterion %d: ", spaces + 2, "", indexCriterion++);
 
-        std::string usageLiteral;
-        if (!UsageTypeConverter::toString(criterion.mValue.mUsage, usageLiteral)) {
-            ALOGE("%s: failed to convert usage %d", __FUNCTION__, criterion.mValue.mUsage);
-            return;
+        std::string ruleType, ruleValue;
+        bool unknownRule = !RuleTypeConverter::toString(criterion.mRule, ruleType);
+        switch (criterion.mRule & ~RULE_EXCLUSION_MASK) { // no need to match RULE_EXCLUDE_...
+        case RULE_MATCH_ATTRIBUTE_USAGE:
+            UsageTypeConverter::toString(criterion.mValue.mUsage, ruleValue);
+            break;
+        case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+            SourceTypeConverter::toString(criterion.mValue.mSource, ruleValue);
+            break;
+        case RULE_MATCH_UID:
+            ruleValue = std::to_string(criterion.mValue.mUid);
+            break;
+        default:
+            unknownRule = true;
         }
-        dst->appendFormat("%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
 
-        if (mMixType == MIX_TYPE_RECORDERS) {
-            std::string sourceLiteral;
-            if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
-                ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
-                return;
-            }
-            dst->appendFormat("%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
-
+        if (!unknownRule) {
+            dst->appendFormat("%s %s\n", ruleType.c_str(), ruleValue.c_str());
+        } else {
+            dst->appendFormat("Unknown rule type value 0x%x\n", criterion.mRule);
         }
-        dst->appendFormat("%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
-
-        std::string ruleLiteral;
-        if (!RuleTypeConverter::toString(criterion.mRule, ruleLiteral)) {
-            ALOGE("%s: failed to convert source %d", __FUNCTION__,criterion.mRule);
-            return;
-        }
-        dst->appendFormat("%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
     }
 }
 
@@ -180,7 +177,12 @@
         // Loopback render mixes are created from a public API and thus restricted
         // to non sensible audio that have not opted out.
         if (is_mix_loopback_render(mix->mRouteFlags)) {
-            if ((attributes.flags & AUDIO_FLAG_NO_CAPTURE) == AUDIO_FLAG_NO_CAPTURE) {
+            auto hasFlag = [](auto flags, auto flag) { return (flags & flag) == flag; };
+            if (hasFlag(attributes.flags, AUDIO_FLAG_NO_SYSTEM_CAPTURE)) {
+                return MixMatchStatus::NO_MATCH;
+            }
+            if (!mix->mAllowPrivilegedPlaybackCapture &&
+                hasFlag(attributes.flags, AUDIO_FLAG_NO_MEDIA_PROJECTION)) {
                 return MixMatchStatus::NO_MATCH;
             }
             if (!(attributes.usage == AUDIO_USAGE_UNKNOWN ||
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 91961d0..1a74f48 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -40,7 +40,7 @@
     mTagName(tagName), mDeviceType(type), mEncodedFormats(encodedFormats)
 {
     mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
-    if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
+    if (audio_is_remote_submix_device(type)) {
         mAddress = String8("0");
     }
     /* If framework runs against a pre 5.0 Audio HAL, encoded formats are absent from the config.
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
index 7c76d8a..2b5455e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -52,7 +52,6 @@
 
 template <>
 const RuleTypeConverter::Table RuleTypeConverter::mTable[] = {
-    MAKE_STRING_FROM_ENUM(RULE_EXCLUSION_MASK),
     MAKE_STRING_FROM_ENUM(RULE_MATCH_ATTRIBUTE_USAGE),
     MAKE_STRING_FROM_ENUM(RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET),
     MAKE_STRING_FROM_ENUM(RULE_MATCH_UID),
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e8e9fa6..a12bdaa 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -169,8 +169,6 @@
                 broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
                 return INVALID_OPERATION;
             }
-            // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(device, state);
 
             // outputs should never be empty here
             ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
@@ -200,8 +198,6 @@
             // Reset active device codec
             device->setEncodedFormat(AUDIO_FORMAT_DEFAULT);
 
-            // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(device, state);
             } break;
 
         default:
@@ -209,6 +205,9 @@
             return BAD_VALUE;
         }
 
+        // Propagate device availability to Engine
+        setEngineDeviceConnectionState(device, state);
+
         // No need to evaluate playback routing when connecting a remote submix
         // output device used by a dynamic policy of type recorder as no
         // playback use case is affected.
@@ -318,9 +317,6 @@
             if (mAvailableInputDevices.add(device) < 0) {
                 return NO_MEMORY;
             }
-
-            // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(device, state);
         } break;
 
         // handle input device disconnection
@@ -337,9 +333,6 @@
 
             checkInputsForDevice(device, state, inputs);
             mAvailableInputDevices.remove(device);
-
-            // Propagate device availability to Engine
-            mEngine->setDeviceConnectionState(device, state);
         } break;
 
         default:
@@ -347,6 +340,9 @@
             return BAD_VALUE;
         }
 
+        // Propagate device availability to Engine
+        setEngineDeviceConnectionState(device, state);
+
         closeAllInputs();
         // As the input device list can impact the output device selection, update
         // getDeviceForStrategy() cache
@@ -369,6 +365,17 @@
     return BAD_VALUE;
 }
 
+void AudioPolicyManager::setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
+                                      audio_policy_dev_state_t state) {
+
+    // the Engine does not have to know about remote submix devices used by dynamic audio policies
+    if (audio_is_remote_submix_device(device->type()) && device->address() != "0") {
+        return;
+    }
+    mEngine->setDeviceConnectionState(device, state);
+}
+
+
 audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
                                                                       const char *device_address)
 {
@@ -945,6 +952,9 @@
     if (status != NO_ERROR) {
         return status;
     }
+    if (auto it = mAllowedCapturePolicies.find(uid); it != end(mAllowedCapturePolicies)) {
+        resultAttr->flags |= it->second;
+    }
     *stream = mEngine->getStreamTypeForAttributes(*resultAttr);
 
     ALOGV("%s() attributes=%s stream=%s session %d selectedDeviceId %d", __func__,
@@ -2025,7 +2035,7 @@
         mSoundTriggerSessions.indexOfKey(session) > 0;
     *portId = AudioPort::getNextUniqueId();
 
-    clientDesc = new RecordClientDescriptor(*portId, uid, session, *attr, *config,
+    clientDesc = new RecordClientDescriptor(*portId, uid, session, attributes, *config,
                                             requestedDeviceId, attributes.source, flags,
                                             isSoundTrigger);
     inputDesc = mInputs.valueFor(*input);
@@ -3022,6 +3032,11 @@
     mPolicyMixes.dump(dst);
     mAudioSources.dump(dst);
 
+    dst->appendFormat(" AllowedCapturePolicies:\n");
+    for (auto& policy : mAllowedCapturePolicies) {
+        dst->appendFormat("   - uid=%d flag_mask=%#x\n", policy.first, policy.second);
+    }
+
     dst->appendFormat("\nPolicy Engine dump:\n");
     mEngine->dump(dst);
 }
@@ -3034,6 +3049,12 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyManager::setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t capturePolicy)
+{
+    mAllowedCapturePolicies[uid] = capturePolicy;
+    return NO_ERROR;
+}
+
 // This function checks for the parameters which can be offloaded.
 // This can be enhanced depending on the capability of the DSP and policy
 // of the system.
@@ -4385,7 +4406,7 @@
                 continue;
             }
             // Device is now validated and can be appended to the available devices of the engine
-            mEngine->setDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+            setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
             i++;
         }
     };
@@ -4399,7 +4420,7 @@
         status = NO_INIT;
     }
     // If microphones address is empty, set it according to device type
-    for (size_t i = 0; i  < mAvailableInputDevices.size(); i++) {
+    for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
         if (mAvailableInputDevices[i]->address().isEmpty()) {
             if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
                 mAvailableInputDevices[i]->setAddress(String8(AUDIO_BOTTOM_MICROPHONE_ADDRESS));
@@ -4828,6 +4849,7 @@
         ALOGW("closeOutput() unknown output %d", output);
         return;
     }
+    const bool closingOutputWasActive = closingOutput->isActive();
     mPolicyMixes.closeOutput(closingOutput);
 
     // look for duplicated outputs connected to the output being removed.
@@ -4867,6 +4889,9 @@
         mpClientInterface->onAudioPatchListUpdate();
     }
 
+    if (closingOutputWasActive) {
+        closingOutput->stop();
+    }
     closingOutput->close();
 
     removeOutput(output);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 1c98684..26208c8 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -218,6 +218,7 @@
 
         status_t dump(int fd) override;
 
+        status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t capturePolicy) override;
         virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
 
         virtual bool isDirectOutputSupported(const audio_config_base_t& config,
@@ -754,6 +755,8 @@
         // Surround formats that are enabled manually. Taken into account when
         // "encoded surround" is forced into "manual" mode.
         std::unordered_set<audio_format_t> mManualSurroundFormats;
+
+        std::unordered_map<uid_t, audio_flags_mask_t> mAllowedCapturePolicies;
 private:
         // Add or remove AC3 DTS encodings based on user preferences.
         void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
@@ -844,6 +847,10 @@
                                              const char *device_address,
                                              const char *device_name,
                                              audio_format_t encodedFormat);
+
+        void setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
+                                      audio_policy_dev_state_t state);
+
         void updateMono(audio_io_handle_t output) {
             AudioParameter param;
             param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index a672521..b2a2344 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -192,7 +192,7 @@
     }
     audio_attributes_t attr = *originalAttr;
     if (!mPackageManager.allowPlaybackCapture(uid)) {
-        attr.flags |= AUDIO_FLAG_NO_CAPTURE;
+        attr.flags |= AUDIO_FLAG_NO_MEDIA_PROJECTION;
     }
     audio_output_flags_t originalFlags = flags;
     AutoCallerClear acc;
@@ -322,7 +322,7 @@
         return;
     }
     sp<AudioPlaybackClient> client = mAudioPlaybackClients.valueAt(index);
-    mAudioRecordClients.removeItem(portId);
+    mAudioPlaybackClients.removeItem(portId);
 
     // called from internal thread: no need to clear caller identity
     mAudioPolicyManager->releaseOutput(portId);
@@ -376,15 +376,17 @@
         return PERMISSION_DENIED;
     }
 
+    bool canCaptureOutput = captureAudioOutputAllowed(pid, uid);
     if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
         attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
         attr->source == AUDIO_SOURCE_VOICE_CALL ||
         attr->source == AUDIO_SOURCE_ECHO_REFERENCE) &&
-        !captureAudioOutputAllowed(pid, uid)) {
+        !canCaptureOutput) {
         return PERMISSION_DENIED;
     }
 
-    if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) {
+    bool canCaptureHotword = captureHotwordAllowed(pid, uid);
+    if ((attr->source == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
         return BAD_VALUE;
     }
 
@@ -415,7 +417,7 @@
             case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
                 // FIXME: use the same permission as for remote submix for now.
             case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
-                if (!captureAudioOutputAllowed(pid, uid)) {
+                if (!canCaptureOutput) {
                     ALOGE("getInputForAttr() permission denied: capture not allowed");
                     status = PERMISSION_DENIED;
                 }
@@ -442,7 +444,8 @@
         }
 
         sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session,
-                                                             *selectedDeviceId, opPackageName);
+                                                             *selectedDeviceId, opPackageName,
+                                                             canCaptureOutput, canCaptureHotword);
         mAudioRecordClients.add(*portId, client);
     }
 
@@ -945,6 +948,20 @@
     return audioPolicyEffects->removeStreamDefaultEffect(id);
 }
 
+status_t AudioPolicyService::setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t capturePolicy) {
+    Mutex::Autolock _l(mLock);
+    if (mAudioPolicyManager == NULL) {
+        ALOGV("%s() mAudioPolicyManager == NULL", __func__);
+        return NO_INIT;
+    }
+    uint_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (uid != callingUid) {
+        ALOGD("%s() uid invalid %d != %d", __func__, uid, callingUid);
+        return PERMISSION_DENIED;
+    }
+    return mAudioPolicyManager->setAllowedCapturePolicy(uid, capturePolicy);
+}
+
 bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
 {
     if (mAudioPolicyManager == NULL) {
@@ -1080,6 +1097,14 @@
         return PERMISSION_DENIED;
     }
 
+    bool needCaptureMediaOutput = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
+            return mix.mAllowPrivilegedPlaybackCapture; });
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+    if (needCaptureMediaOutput && !captureMediaOutputAllowed(callingPid, callingUid)) {
+        return PERMISSION_DENIED;
+    }
+
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -1124,9 +1149,10 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
+    // startAudioSource should be created as the calling uid
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     AutoCallerClear acc;
-    return mAudioPolicyManager->startAudioSource(source, attributes, portId,
-                                                 IPCThreadState::self()->getCallingUid());
+    return mAudioPolicyManager->startAudioSource(source, attributes, portId, callingUid);
 }
 
 status_t AudioPolicyService::stopAudioSource(audio_port_handle_t portId)
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 8cbf3af..f63fa81 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -22,8 +22,9 @@
 #define __STDINT_LIMITS
 #define __STDC_LIMIT_MACROS
 #include <stdint.h>
-
 #include <sys/time.h>
+
+#include <audio_utils/clock.h>
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
 #include <cutils/properties.h>
@@ -48,8 +49,7 @@
 static const char kDeadlockedString[] = "AudioPolicyService may be deadlocked\n";
 static const char kCmdDeadlockedString[] = "AudioPolicyService command thread may be deadlocked\n";
 
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleepUs = 20000;
+static const int kDumpLockTimeoutNs = 1 * NANOS_PER_SECOND;
 
 static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
 
@@ -376,17 +376,10 @@
             IPCThreadState::self()->getCallingPid());
 }
 
-static bool tryLock(Mutex& mutex)
+static bool dumpTryLock(Mutex& mutex)
 {
-    bool locked = false;
-    for (int i = 0; i < kDumpLockRetries; ++i) {
-        if (mutex.tryLock() == NO_ERROR) {
-            locked = true;
-            break;
-        }
-        usleep(kDumpLockSleepUs);
-    }
-    return locked;
+    status_t err = mutex.timedLock(kDumpLockTimeoutNs);
+    return err == NO_ERROR;
 }
 
 status_t AudioPolicyService::dumpInternals(int fd)
@@ -414,32 +407,35 @@
 {
 //    Go over all active clients and allow capture (does not force silence) in the
 //    following cases:
-//    The client is the assistant
+//    Another client in the same UID has already been allowed to capture
+//    OR The client is the assistant
 //        AND an accessibility service is on TOP
 //               AND the source is VOICE_RECOGNITION or HOTWORD
 //        OR uses VOICE_RECOGNITION AND is on TOP OR latest started
 //               OR uses HOTWORD
-//            AND there is no privacy sensitive active capture
+//            AND there is no active privacy sensitive capture or call
+//                OR client has CAPTURE_AUDIO_OUTPUT privileged permission
 //    OR The client is an accessibility service
 //        AND is on TOP OR latest started
 //        AND the source is VOICE_RECOGNITION or HOTWORD
-//    OR the source is one of: AUDIO_SOURCE_VOICE_DOWNLINK, AUDIO_SOURCE_VOICE_UPLINK,
-//       AUDIO_SOURCE_VOICE_CALL
+//    OR the client source is virtual (remote submix, call audio TX or RX...)
 //    OR Any other client
 //        AND The assistant is not on TOP
-//        AND is on TOP OR latest started
-//        AND there is no privacy sensitive active capture
+//        AND there is no active privacy sensitive capture or call
+//                OR client has CAPTURE_AUDIO_OUTPUT privileged permission
 //TODO: mamanage pre processing effects according to use case priority
 
     sp<AudioRecordClient> topActive;
     sp<AudioRecordClient> latestActive;
     sp<AudioRecordClient> latestSensitiveActive;
+
     nsecs_t topStartNs = 0;
     nsecs_t latestStartNs = 0;
     nsecs_t latestSensitiveStartNs = 0;
     bool isA11yOnTop = mUidPolicy->isA11yOnTop();
     bool isAssistantOnTop = false;
     bool isSensitiveActive = false;
+    bool isInCall = mPhoneState == AUDIO_MODE_IN_CALL;
 
     // if Sensor Privacy is enabled then all recordings should be silenced.
     if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -449,15 +445,18 @@
 
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
-        if (!current->active) continue;
-        if (isPrivacySensitiveSource(current->attributes.source)) {
-            if (current->startTimeNs > latestSensitiveStartNs) {
-                latestSensitiveActive = current;
-                latestSensitiveStartNs = current->startTimeNs;
-            }
-            isSensitiveActive = true;
+        if (!current->active) {
+            continue;
         }
-        if (mUidPolicy->getUidState(current->uid) == ActivityManager::PROCESS_STATE_TOP) {
+
+        app_state_t appState = apmStatFromAmState(mUidPolicy->getUidState(current->uid));
+        // clients which app is in IDLE state are not eligible for top active or
+        // latest active
+        if (appState == APP_STATE_IDLE) {
+            continue;
+        }
+
+        if (appState == APP_STATE_TOP) {
             if (current->startTimeNs > topStartNs) {
                 topActive = current;
                 topStartNs = current->startTimeNs;
@@ -470,72 +469,105 @@
             latestActive = current;
             latestStartNs = current->startTimeNs;
         }
+        if (isPrivacySensitiveSource(current->attributes.source)) {
+            if (current->startTimeNs > latestSensitiveStartNs) {
+                latestSensitiveActive = current;
+                latestSensitiveStartNs = current->startTimeNs;
+            }
+            isSensitiveActive = true;
+        }
     }
 
-    if (topActive == nullptr && latestActive == nullptr) {
-        return;
+    // if no active client with UI on Top, consider latest active as top
+    if (topActive == nullptr) {
+        topActive = latestActive;
     }
 
-    if (topActive != nullptr) {
-        latestActive = nullptr;
-    }
+    std::vector<uid_t> enabledUids;
 
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
-        if (!current->active) continue;
+        if (!current->active) {
+            continue;
+        }
+
+        // keep capture allowed if another client with the same UID has already
+        // been allowed to capture
+        if (std::find(enabledUids.begin(), enabledUids.end(), current->uid)
+                != enabledUids.end()) {
+            continue;
+        }
 
         audio_source_t source = current->attributes.source;
-        bool isOnTop = current == topActive;
-        bool isLatest = current == latestActive;
-        bool isLatestSensitive = current == latestSensitiveActive;
-        bool forceIdle = true;
+        bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
+        bool isLatestSensitive = latestSensitiveActive == nullptr ?
+                                 false : current->uid == latestSensitiveActive->uid;
+
+        // By default allow capture if:
+        //     The assistant is not on TOP
+        //     AND there is no active privacy sensitive capture or call
+        //             OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+        bool allowCapture = !isAssistantOnTop
+                && !(isSensitiveActive && !(isLatestSensitive || current->canCaptureOutput))
+                && !(isInCall && !current->canCaptureOutput);
 
         if (isVirtualSource(source)) {
-            forceIdle = false;
+            // Allow capture for virtual (remote submix, call audio TX or RX...) sources
+            allowCapture = true;
         } else if (mUidPolicy->isAssistantUid(current->uid)) {
+            // For assistant allow capture if:
+            //     An accessibility service is on TOP
+            //            AND the source is VOICE_RECOGNITION or HOTWORD
+            //     OR is on TOP OR latest started AND uses VOICE_RECOGNITION
+            //            OR uses HOTWORD
+            //         AND there is no active privacy sensitive capture or call
+            //             OR client has CAPTURE_AUDIO_OUTPUT privileged permission
             if (isA11yOnTop) {
                 if (source == AUDIO_SOURCE_HOTWORD || source == AUDIO_SOURCE_VOICE_RECOGNITION) {
-                    forceIdle = false;
+                    allowCapture = true;
                 }
             } else {
-                if ((((isOnTop || isLatest) && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
-                     source == AUDIO_SOURCE_HOTWORD) && !isSensitiveActive) {
-                    forceIdle = false;
+                if (((isTopOrLatestActive && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
+                        source == AUDIO_SOURCE_HOTWORD) &&
+                        (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) {
+                    allowCapture = true;
                 }
             }
         } else if (mUidPolicy->isA11yUid(current->uid)) {
-            if ((isOnTop || isLatest) &&
-                (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD)) {
-                forceIdle = false;
-            }
-        } else {
-            if (!isAssistantOnTop && (isOnTop || isLatest) &&
-                (!isSensitiveActive || isLatestSensitive)) {
-                forceIdle = false;
+            // For accessibility service allow capture if:
+            //     Is on TOP OR latest started
+            //     AND the source is VOICE_RECOGNITION or HOTWORD
+            if (isTopOrLatestActive &&
+                    (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD)) {
+                allowCapture = true;
             }
         }
         setAppState_l(current->uid,
-                      forceIdle ? APP_STATE_IDLE :
-                                  apmStatFromAmState(mUidPolicy->getUidState(current->uid)));
+                      allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
+                                APP_STATE_IDLE);
+        if (allowCapture) {
+            enabledUids.push_back(current->uid);
+        }
     }
 }
 
 void AudioPolicyService::silenceAllRecordings_l() {
     for (size_t i = 0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
-        setAppState_l(current->uid, APP_STATE_IDLE);
+        if (!isVirtualSource(current->attributes.source)) {
+            setAppState_l(current->uid, APP_STATE_IDLE);
+        }
     }
 }
 
 /* static */
 app_state_t AudioPolicyService::apmStatFromAmState(int amState) {
-    switch (amState) {
-    case ActivityManager::PROCESS_STATE_UNKNOWN:
+
+    if (amState == ActivityManager::PROCESS_STATE_UNKNOWN) {
         return APP_STATE_IDLE;
-    case ActivityManager::PROCESS_STATE_TOP:
-        return APP_STATE_TOP;
-    default:
-        break;
+    } else if (amState <= ActivityManager::PROCESS_STATE_TOP) {
+      // include persistent services
+      return APP_STATE_TOP;
     }
     return APP_STATE_FOREGROUND;
 }
@@ -588,7 +620,7 @@
     if (!dumpAllowed()) {
         dumpPermissionDenial(fd);
     } else {
-        bool locked = tryLock(mLock);
+        bool locked = dumpTryLock(mLock);
         if (!locked) {
             String8 result(kDeadlockedString);
             write(fd, result.string(), result.size());
@@ -1221,7 +1253,7 @@
     result.append(buffer);
     write(fd, result.string(), result.size());
 
-    bool locked = tryLock(mLock);
+    bool locked = dumpTryLock(mLock);
     if (!locked) {
         String8 result2(kCmdDeadlockedString);
         write(fd, result2.string(), result2.size());
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a2e75cd..efdba56 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -182,6 +182,7 @@
                                      audio_io_handle_t output,
                                      int delayMs = 0);
     virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+    status_t setAllowedCapturePolicy(uint_t uid, audio_flags_mask_t capturePolicy) override;
     virtual bool isOffloadSupported(const audio_offload_info_t &config);
     virtual bool isDirectOutputSupported(const audio_config_base_t& config,
                                          const audio_attributes_t& attributes);
@@ -753,13 +754,17 @@
                 AudioRecordClient(const audio_attributes_t attributes,
                           const audio_io_handle_t io, uid_t uid, pid_t pid,
                           const audio_session_t session, const audio_port_handle_t deviceId,
-                          const String16& opPackageName) :
+                          const String16& opPackageName,
+                          bool canCaptureOutput, bool canCaptureHotword) :
                     AudioClient(attributes, io, uid, pid, session, deviceId),
-                    opPackageName(opPackageName), startTimeNs(0) {}
+                    opPackageName(opPackageName), startTimeNs(0),
+                    canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {}
                 ~AudioRecordClient() override = default;
 
         const String16 opPackageName;        // client package name
         nsecs_t startTimeNs;
+        const bool canCaptureOutput;
+        const bool canCaptureHotword;
     };
 
     // --- AudioPlaybackClient ---
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 51d0682..8113c3f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -972,8 +972,9 @@
     userid_t clientUserId = multiuser_get_user_id(clientUid);
 
     // Only allow clients who are being used by the current foreground device user, unless calling
-    // from our own process.
-    if (callingPid != getpid() && (mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
+    // from our own process OR the caller is using the cameraserver's HIDL interface.
+    if (!hardware::IPCThreadState::self()->isServingCall() && callingPid != getpid() &&
+            (mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
         ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from "
                 "device user %d, currently allowed device users: %s)", callingPid, clientUserId,
                 toString(mAllowedUsers).string());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 22e09e4..ef99dea 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1062,14 +1062,18 @@
             nsecs_t waitDuration = kBaseGetBufferWait + getExpectedInFlightDuration();
             status_t res = outputStream->getBuffer(&sb, waitDuration);
             if (res != OK) {
-                ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
-                        __FUNCTION__, streamId, strerror(-res), res);
                 if (res == NO_INIT || res == DEAD_OBJECT) {
+                    ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
+                            __FUNCTION__, streamId, strerror(-res), res);
                     bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
-                } else if (res == TIMED_OUT || res == NO_MEMORY) {
-                    bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
                 } else {
-                    bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+                    ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
+                            __FUNCTION__, streamId, strerror(-res), res);
+                    if (res == TIMED_OUT || res == NO_MEMORY) {
+                        bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
+                    } else {
+                        bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+                    }
                 }
                 currentReqSucceeds = false;
                 break;
@@ -3154,9 +3158,10 @@
 
         // Note: stream may be deallocated at this point, if this buffer was
         // the last reference to it.
-        if (res != OK) {
-            ALOGE("Can't return buffer to its stream: %s (%d)",
-                strerror(-res), res);
+        if (res == NO_INIT || res == DEAD_OBJECT) {
+            ALOGV("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
+        } else if (res != OK) {
+            ALOGE("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
         }
 
         // Long processing consumers can cause returnBuffer timeout for shared stream
@@ -5580,7 +5585,7 @@
 
             if (mUseHalBufManager) {
                 if (outputStream->isAbandoned()) {
-                    ALOGE("%s: stream %d is abandoned.", __FUNCTION__, streamId);
+                    ALOGV("%s: stream %d is abandoned, skipping request", __FUNCTION__, streamId);
                     return TIMED_OUT;
                 }
                 // HAL will request buffer through requestStreamBuffer API
@@ -5598,7 +5603,7 @@
                     // Can't get output buffer from gralloc queue - this could be due to
                     // abandoned queue or other consumer misbehavior, so not a fatal
                     // error
-                    ALOGE("RequestThread: Can't get output buffer, skipping request:"
+                    ALOGV("RequestThread: Can't get output buffer, skipping request:"
                             " %s (%d)", strerror(-res), res);
 
                     return TIMED_OUT;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index baba856..1c77581 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -233,6 +233,7 @@
      * queueBuffer
      */
     sp<ANativeWindow> currentConsumer = mConsumer;
+    StreamState state = mState;
     mLock.unlock();
 
     ANativeWindowBuffer *anwBuffer = container_of(buffer.buffer, ANativeWindowBuffer, handle);
@@ -244,7 +245,7 @@
         if (mDropBuffers) {
             ALOGV("%s: Dropping a frame for stream %d.", __FUNCTION__, mId);
         } else if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
-            ALOGW("%s: A frame is dropped for stream %d due to buffer error.", __FUNCTION__, mId);
+            ALOGV("%s: A frame is dropped for stream %d due to buffer error.", __FUNCTION__, mId);
         } else {
             ALOGE("%s: Stream %d: timestamp shouldn't be 0", __FUNCTION__, mId);
         }
@@ -252,7 +253,7 @@
         res = currentConsumer->cancelBuffer(currentConsumer.get(),
                 anwBuffer,
                 anwReleaseFence);
-        if (res != OK) {
+        if (shouldLogError(res, state)) {
             ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
                   " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
@@ -284,9 +285,9 @@
         }
 
         res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
-        if (res != OK) {
-            ALOGE("%s: Stream %d: Error queueing buffer to native window: "
-                  "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
+        if (shouldLogError(res, state)) {
+            ALOGE("%s: Stream %d: Error queueing buffer to native window:"
+                  " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
     }
     mLock.lock();
@@ -534,10 +535,11 @@
             // successful return.
             *anb = gb.get();
             res = mConsumer->attachBuffer(*anb);
-            if (res != OK) {
+            if (shouldLogError(res, mState)) {
                 ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
                         __FUNCTION__, mId, strerror(-res), res);
-
+            }
+            if (res != OK) {
                 checkRetAndSetAbandonedLocked(res);
                 return res;
             }
@@ -592,9 +594,10 @@
                 ALOGV("Stream %d: Attached new buffer", getId());
 
                 if (res != OK) {
-                    ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
-                            __FUNCTION__, mId, strerror(-res), res);
-
+                    if (shouldLogError(res, mState)) {
+                        ALOGE("%s: Stream %d: Can't attach the output buffer to this surface:"
+                                " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+                    }
                     checkRetAndSetAbandonedLocked(res);
                     return res;
                 }
@@ -604,9 +607,10 @@
                 return res;
             }
         } else if (res != OK) {
-            ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
-
+            if (shouldLogError(res, mState)) {
+                ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
+                        __FUNCTION__, mId, strerror(-res), res);
+            }
             checkRetAndSetAbandonedLocked(res);
             return res;
         }
@@ -639,6 +643,16 @@
     }
 }
 
+bool Camera3OutputStream::shouldLogError(status_t res, StreamState state) {
+    if (res == OK) {
+        return false;
+    }
+    if ((res == DEAD_OBJECT || res == NO_INIT) && state == STATE_ABANDONED) {
+        return false;
+    }
+    return true;
+}
+
 status_t Camera3OutputStream::disconnectLocked() {
     status_t res;
 
@@ -838,7 +852,9 @@
         ALOGW("%s: the released buffer has already been freed by the buffer queue!", __FUNCTION__);
     } else if (res != OK) {
         // Treat other errors as abandonment
-        ALOGE("%s: detach next buffer failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+        if (shouldLogError(res, mState)) {
+            ALOGE("%s: detach next buffer failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+        }
         mState = STATE_ABANDONED;
         return res;
     }
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 30fc2f7..729c655 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -317,6 +317,10 @@
     // Check return status of IGBP calls and set abandoned state accordingly
     void checkRetAndSetAbandonedLocked(status_t res);
 
+    // If the status indicates abandonded stream, only log when state hasn't been updated to
+    // STATE_ABANDONED
+    static bool shouldLogError(status_t res, StreamState state);
+
     static const int32_t kDequeueLatencyBinSize = 5; // in ms
     CameraLatencyHistogram mDequeueBufferLatency;
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 0571741..12ff130 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -321,7 +321,7 @@
     // so. As documented in hardware/camera3.h:configure_streams().
     if (mState == STATE_IN_RECONFIG &&
             mOldUsage == mUsage &&
-            mOldMaxBuffers == camera3_stream::max_buffers) {
+            mOldMaxBuffers == camera3_stream::max_buffers && !mDataSpaceOverridden) {
         mState = STATE_CONFIGURED;
         return OK;
     }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 5eb6a23..3d21029 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -458,7 +458,7 @@
     // Zero for formats with fixed buffer size for given dimensions.
     const size_t mMaxSize;
 
-    enum {
+    enum StreamState {
         STATE_ERROR,
         STATE_CONSTRUCTED,
         STATE_IN_CONFIG,
diff --git a/services/camera/libcameraservice/hidl/Convert.cpp b/services/camera/libcameraservice/hidl/Convert.cpp
index a87812b..c2ed23a 100644
--- a/services/camera/libcameraservice/hidl/Convert.cpp
+++ b/services/camera/libcameraservice/hidl/Convert.cpp
@@ -97,6 +97,21 @@
     return outputConfiguration;
 }
 
+hardware::camera2::params::SessionConfiguration convertFromHidl(
+    const HSessionConfiguration &hSessionConfiguration) {
+    hardware::camera2::params::SessionConfiguration sessionConfig(
+            hSessionConfiguration.inputWidth, hSessionConfiguration.inputHeight,
+            hSessionConfiguration.inputFormat,
+            static_cast<int>(hSessionConfiguration.operationMode));
+
+    for (const auto& hConfig : hSessionConfiguration.outputStreams) {
+        hardware::camera2::params::OutputConfiguration config = convertFromHidl(hConfig);
+        sessionConfig.addOutputConfiguration(config);
+    }
+
+    return sessionConfig;
+}
+
 // The camera metadata here is cloned. Since we're reading metadata over
 // hwbinder we would need to clone it in order to avoid aligment issues.
 bool convertFromHidl(const HCameraMetadata &src, CameraMetadata *dst) {
diff --git a/services/camera/libcameraservice/hidl/Convert.h b/services/camera/libcameraservice/hidl/Convert.h
index 82937a3..79683f6 100644
--- a/services/camera/libcameraservice/hidl/Convert.h
+++ b/services/camera/libcameraservice/hidl/Convert.h
@@ -53,6 +53,7 @@
 using HOutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
 using HPhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
 using HPhysicalCaptureResultInfo = frameworks::cameraservice::device::V2_0::PhysicalCaptureResultInfo;
+using HSessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
 using HSubmitInfo = frameworks::cameraservice::device::V2_0::SubmitInfo;
 using HStatus = frameworks::cameraservice::common::V2_0::Status;
 using HStreamConfigurationMode = frameworks::cameraservice::device::V2_0::StreamConfigurationMode;
@@ -70,6 +71,9 @@
 hardware::camera2::params::OutputConfiguration convertFromHidl(
     const HOutputConfiguration &hOutputConfiguration);
 
+hardware::camera2::params::SessionConfiguration convertFromHidl(
+    const HSessionConfiguration &hSessionConfiguration);
+
 HCameraDeviceStatus convertToHidlCameraDeviceStatus(int32_t status);
 
 void convertToHidl(const std::vector<hardware::CameraStatus> &src,
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index d22ba5a..675ad24 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -41,6 +41,7 @@
 using hardware::Void;
 using HSubmitInfo = device::V2_0::SubmitInfo;
 using hardware::camera2::params::OutputConfiguration;
+using hardware::camera2::params::SessionConfiguration;
 
 static constexpr int32_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1 MB */;
 static constexpr int32_t CAMERA_RESULT_METADATA_QUEUE_SIZE = 1 << 20 /* 1 MB */;
@@ -255,6 +256,18 @@
     return B2HStatus(ret);
 }
 
+Return<void> HidlCameraDeviceUser::isSessionConfigurationSupported(
+    const HSessionConfiguration& hSessionConfiguration,
+    isSessionConfigurationSupported_cb _hidl_cb) {
+    bool supported = false;
+    SessionConfiguration sessionConfiguration = convertFromHidl(hSessionConfiguration);
+    binder::Status ret = mDeviceRemote->isSessionConfigurationSupported(
+            sessionConfiguration, &supported);
+    HStatus status = B2HStatus(ret);
+    _hidl_cb(status, supported);
+    return Void();
+}
+
 } // implementation
 } // V2_0
 } // device
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
index be8f1d6..c3a80fe 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
@@ -53,6 +53,7 @@
 using HCameraDeviceUser = device::V2_0::ICameraDeviceUser;
 using HCameraMetadata = cameraservice::service::V2_0::CameraMetadata;
 using HCaptureRequest = device::V2_0::CaptureRequest;
+using HSessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
 using HOutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
 using HPhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
 using HStatus = frameworks::cameraservice::common::V2_0::Status;
@@ -97,6 +98,10 @@
     virtual Return<HStatus> updateOutputConfiguration(
         int32_t streamId, const HOutputConfiguration& outputConfiguration) override;
 
+    virtual Return<void> isSessionConfigurationSupported(
+        const HSessionConfiguration& sessionConfiguration,
+        isSessionConfigurationSupported_cb _hidl_cb) override;
+
     bool initStatus() { return mInitSuccess; }
 
     std::shared_ptr<CaptureResultMetadataQueue> getCaptureResultMetadataQueue() {
diff --git a/services/mediaextractor/mediaextractor.rc b/services/mediaextractor/mediaextractor.rc
index 6b2d0a5..5fc2941 100644
--- a/services/mediaextractor/mediaextractor.rc
+++ b/services/mediaextractor/mediaextractor.rc
@@ -2,7 +2,5 @@
     class main
     user mediaex
     group drmrpc mediadrm
-    # TODO(b/123275379): Remove updatable when http://aosp/878198 has landed
-    updatable
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 6c28083..fbf7d10 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -93,12 +93,14 @@
     const audio_source_t source = (direction == AAUDIO_DIRECTION_INPUT)
             ? AAudioConvert_inputPresetToAudioSource(getInputPreset())
             : AUDIO_SOURCE_DEFAULT;
+    const audio_flags_mask_t flags = AUDIO_FLAG_LOW_LATENCY |
+            AAudioConvert_allowCapturePolicyToAudioFlagsMask(getAllowedCapturePolicy());
 
     const audio_attributes_t attributes = {
             .content_type = contentType,
             .usage = usage,
             .source = source,
-            .flags = AUDIO_FLAG_LOW_LATENCY,
+            .flags = flags,
             .tags = ""
     };
 
diff --git a/services/soundtrigger/Android.bp b/services/soundtrigger/Android.bp
index 1f2283a..3f02f48 100644
--- a/services/soundtrigger/Android.bp
+++ b/services/soundtrigger/Android.bp
@@ -28,6 +28,7 @@
         "libhardware",
         "libsoundtrigger",
         "libaudioclient",
+        "libaudioutils",
         "libmediautils",
 
         "libhwbinder",
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index fe2ccf2..f89683a 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <pthread.h>
 
+#include <audio_utils/clock.h>
 #include <system/sound_trigger.h>
 #include <cutils/atomic.h>
 #include <cutils/properties.h>
@@ -146,20 +147,12 @@
 }
 
 
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleep = 60000;
+static const int kDumpLockTimeoutNs = 1 * NANOS_PER_SECOND;
 
-static bool tryLock(Mutex& mutex)
+static bool dumpTryLock(Mutex& mutex)
 {
-    bool locked = false;
-    for (int i = 0; i < kDumpLockRetries; ++i) {
-        if (mutex.tryLock() == NO_ERROR) {
-            locked = true;
-            break;
-        }
-        usleep(kDumpLockSleep);
-    }
-    return locked;
+    status_t err = mutex.timedLock(kDumpLockTimeoutNs);
+    return err == NO_ERROR;
 }
 
 status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) {
@@ -168,7 +161,7 @@
         result.appendFormat("Permission Denial: can't dump SoundTriggerHwService");
         write(fd, result.string(), result.size());
     } else {
-        bool locked = tryLock(mServiceLock);
+        bool locked = dumpTryLock(mServiceLock);
         // failed to lock - SoundTriggerHwService is probably deadlocked
         if (!locked) {
             result.append("SoundTriggerHwService may be deadlocked\n");