Merge "AudioFlinger: enforce OP_RECORD_AUDIO during recording" into qt-dev
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 25a81eb..d24cb81 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -28,6 +28,10 @@
 
 #include "ACameraCaptureSession.inc"
 
+ACameraDevice::~ACameraDevice() {
+    mDevice->stopLooper();
+}
+
 namespace android {
 namespace acam {
 
@@ -116,14 +120,10 @@
         if (!isClosed()) {
             disconnectLocked(session);
         }
+        LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
+                "CameraDevice looper should've been stopped before ~CameraDevice");
         mCurrentSession = nullptr;
-        if (mCbLooper != nullptr) {
-            mCbLooper->unregisterHandler(mHandler->id());
-            mCbLooper->stop();
-        }
     }
-    mCbLooper.clear();
-    mHandler.clear();
 }
 
 void
@@ -892,6 +892,16 @@
     return;
 }
 
+void CameraDevice::stopLooper() {
+    Mutex::Autolock _l(mDeviceLock);
+    if (mCbLooper != nullptr) {
+      mCbLooper->unregisterHandler(mHandler->id());
+      mCbLooper->stop();
+    }
+    mCbLooper.clear();
+    mHandler.clear();
+}
+
 CameraDevice::CallbackHandler::CallbackHandler(const char* id) : mId(id) {
 }
 
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index c92a95f..7a35bf0 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -109,6 +109,9 @@
 
     inline ACameraDevice* getWrapper() const { return mWrapper; };
 
+    // Stop the looper thread and unregister the handler
+    void stopLooper();
+
   private:
     friend ACameraCaptureSession;
     camera_status_t checkCameraClosedOrErrorLocked() const;
@@ -354,7 +357,7 @@
                   sp<ACameraMetadata> chars) :
             mDevice(new android::acam::CameraDevice(id, cb, chars, this)) {}
 
-    ~ACameraDevice() {};
+    ~ACameraDevice();
 
     /*******************
      * NDK public APIs *
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 7cd832a..8dd6e00 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7689,14 +7689,14 @@
      * case, when the application configures a RAW stream, the camera device will make sure
      * the active physical camera will remain active to ensure consistent RAW output
      * behavior, and not switch to other physical cameras.</p>
-     * <p>To maintain backward compatibility, the capture request and result metadata tags
-     * required for basic camera functionalities will be solely based on the
-     * logical camera capabiltity. Other request and result metadata tags, on the other
-     * hand, will be based on current active physical camera. For example, the physical
-     * cameras' sensor sensitivity and lens capability could be different from each other.
-     * So when the application manually controls sensor exposure time/gain, or does manual
-     * focus control, it must checks the current active physical camera's exposure, gain,
-     * and focus distance range.</p>
+     * <p>The capture request and result metadata tags required for backward compatible camera
+     * functionalities will be solely based on the logical camera capabiltity. On the other
+     * hand, the use of manual capture controls (sensor or post-processing) with a
+     * logical camera may result in unexpected behavior when the HAL decides to switch
+     * between physical cameras with different characteristics under the hood. For example,
+     * when the application manually sets exposure time and sensitivity while zooming in,
+     * the brightness of the camera images may suddenly change because HAL switches from one
+     * physical camera to the other.</p>
      *
      * @see ACAMERA_LENS_DISTORTION
      * @see ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -8330,7 +8330,7 @@
      * fire the flash for flash power metering during precapture, and then fire the flash
      * for the final capture, if a flash is available on the device and the AE mode is set to
      * enable the flash.</p>
-     * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build.VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
+     * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
      *
      * @see ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
      * @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index a43d707..35c8355 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -44,6 +44,10 @@
 
 using namespace android;
 
+ACameraDevice::~ACameraDevice() {
+    mDevice->stopLooper();
+}
+
 namespace android {
 namespace acam {
 
@@ -130,13 +134,9 @@
             disconnectLocked(session);
         }
         mCurrentSession = nullptr;
-        if (mCbLooper != nullptr) {
-            mCbLooper->unregisterHandler(mHandler->id());
-            mCbLooper->stop();
-        }
+        LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
+            "CameraDevice looper should've been stopped before ~CameraDevice");
     }
-    mCbLooper.clear();
-    mHandler.clear();
 }
 
 void
@@ -1400,6 +1400,16 @@
     }
 }
 
+void CameraDevice::stopLooper() {
+    Mutex::Autolock _l(mDeviceLock);
+    if (mCbLooper != nullptr) {
+      mCbLooper->unregisterHandler(mHandler->id());
+      mCbLooper->stop();
+    }
+    mCbLooper.clear();
+    mHandler.clear();
+}
+
 /**
   * Camera service callback implementation
   */
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 829b084..3328a85 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -133,6 +133,9 @@
     bool setDeviceMetadataQueues();
     inline ACameraDevice* getWrapper() const { return mWrapper; };
 
+    // Stop the looper thread and unregister the handler
+    void stopLooper();
+
   private:
     friend ACameraCaptureSession;
 
@@ -383,7 +386,7 @@
                   sp<ACameraMetadata> chars) :
             mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {}
 
-    ~ACameraDevice() {};
+    ~ACameraDevice();
 
     /*******************
      * NDK public APIs *
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index 23a35e5..f164f28 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -62,10 +62,8 @@
       secure, keyId, iv, mode, pattern, subSamples, source, offset, destination,
       [&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) {
         status = toStatus_1_0(hStatus);
-        if (status == Status::OK) {
-          bytesWritten = hBytesWritten;
-          detailedError = hDetailedError;
-        }
+        bytesWritten = hBytesWritten;
+        detailedError = hDetailedError;
       }
     );
 
@@ -109,6 +107,10 @@
                  "destination decrypt buffer base not set");
         return Void();
       }
+    } else {
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
+                 "destination type not supported");
+        return Void();
     }
 
     sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
@@ -126,38 +128,45 @@
             (static_cast<void *>(sourceBase->getPointer()));
     uint8_t* srcPtr = static_cast<uint8_t *>(base + source.offset + offset);
     void* destPtr = NULL;
-    if (destination.type == BufferType::SHARED_MEMORY) {
-        const SharedBuffer& destBuffer = destination.nonsecureMemory;
-        sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
-        if (destBase == nullptr) {
-            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
-            return Void();
-        }
-
-        if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
-            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
-            return Void();
-        }
-        destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
-    } else if (destination.type == BufferType::NATIVE_HANDLE) {
-        native_handle_t *handle = const_cast<native_handle_t *>(
-        destination.secureMemory.getNativeHandle());
-        destPtr = static_cast<void *>(handle);
+    // destination.type == BufferType::SHARED_MEMORY
+    const SharedBuffer& destBuffer = destination.nonsecureMemory;
+    sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
+    if (destBase == nullptr) {
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
+        return Void();
     }
 
+    if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+        _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
+        return Void();
+    }
+    destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+
+
     // Calculate the output buffer size and determine if any subsamples are
     // encrypted.
     size_t destSize = 0;
     bool haveEncryptedSubsamples = false;
     for (size_t i = 0; i < subSamples.size(); i++) {
         const SubSample &subSample = subSamples[i];
-        destSize += subSample.numBytesOfClearData;
-        destSize += subSample.numBytesOfEncryptedData;
+        if (__builtin_add_overflow(destSize, subSample.numBytesOfClearData, &destSize)) {
+            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample clear size overflow");
+            return Void();
+        }
+        if (__builtin_add_overflow(destSize, subSample.numBytesOfEncryptedData, &destSize)) {
+            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample encrypted size overflow");
+            return Void();
+        }
         if (subSample.numBytesOfEncryptedData > 0) {
         haveEncryptedSubsamples = true;
         }
     }
 
+    if (destSize > destBuffer.size) {
+        _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample sum too large");
+        return Void();
+    }
+
     if (mode == Mode::UNENCRYPTED) {
         if (haveEncryptedSubsamples) {
             _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 6509a88..6dab70b 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -127,14 +127,14 @@
     }
 
     switch (mBitrateMode->value) {
-        case C2Config::BITRATE_VARIABLE:
-            mBitrateControlMode = VPX_VBR;
-            break;
         case C2Config::BITRATE_CONST:
-        default:
             mBitrateControlMode = VPX_CBR;
             break;
-        break;
+        case C2Config::BITRATE_VARIABLE:
+        [[fallthrough]];
+        default:
+            mBitrateControlMode = VPX_VBR;
+            break;
     }
 
     setCodecSpecificInterface();
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index 90758f9..62ccd1b 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -275,7 +275,7 @@
         addParameter(
             DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
                 .withDefault(new C2StreamBitrateModeTuning::output(
-                        0u, C2Config::BITRATE_CONST))
+                        0u, C2Config::BITRATE_VARIABLE))
                 .withFields({
                     C2F(mBitrateMode, value).oneOf({
                         C2Config::BITRATE_CONST, C2Config::BITRATE_VARIABLE })
diff --git a/media/codec2/core/include/C2Param.h b/media/codec2/core/include/C2Param.h
index cc8c17a..51d417a 100644
--- a/media/codec2/core/include/C2Param.h
+++ b/media/codec2/core/include/C2Param.h
@@ -176,9 +176,9 @@
             DIR_INPUT      = 0x00000000,
             DIR_OUTPUT     = 0x10000000,
 
-            IS_STREAM_FLAG  = 0x00100000,
-            STREAM_ID_MASK  = 0x03E00000,
-            STREAM_ID_SHIFT = 21,
+            IS_STREAM_FLAG  = 0x02000000,
+            STREAM_ID_MASK  = 0x01F00000,
+            STREAM_ID_SHIFT = 20,
             MAX_STREAM_ID   = STREAM_ID_MASK >> STREAM_ID_SHIFT,
             STREAM_MASK     = IS_STREAM_FLAG | STREAM_ID_MASK,
 
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/Android.bp b/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
index 687754b..65f0d09 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
@@ -15,19 +15,19 @@
  */
 
 cc_test {
-    name: "VtsHidlC2V1_0TargetAudioDecTest",
-    defaults: ["VtsMediaC2V1_0Defaults"],
+    name: "VtsHalMediaC2V1_0TargetAudioDecTest",
+    defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: [
-        "VtsHidlC2V1_0TargetAudioDecTest.cpp",
+        "VtsHalMediaC2V1_0TargetAudioDecTest.cpp",
         //"media_audio_hidl_test_common.cpp"
     ],
 }
 
 cc_test {
-    name: "VtsHidlC2V1_0TargetAudioEncTest",
-    defaults: ["VtsMediaC2V1_0Defaults"],
+    name: "VtsHalMediaC2V1_0TargetAudioEncTest",
+    defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: [
-        "VtsHidlC2V1_0TargetAudioEncTest.cpp",
+        "VtsHalMediaC2V1_0TargetAudioEncTest.cpp",
         //"media_audio_hidl_test_common.cpp"
     ],
 }
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
similarity index 99%
rename from media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 6469735..a8a552c 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -547,6 +547,10 @@
     if (mCompName == raw) {
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
+    } else if (mCompName == g711alaw || mCompName == g711mlaw) {
+        // g711 test data is all 1-channel and has no embedded config info.
+        bitStreamInfo[0] = 8000;
+        bitStreamInfo[1] = 1;
     } else {
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/functional/common/Android.bp b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
index da0061a..a011ba3 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
@@ -1,5 +1,5 @@
 cc_library_static {
-    name: "VtsMediaC2V1_0CommonUtil",
+    name: "VtsHalMediaC2V1_0CommonUtil",
     defaults: [
         "VtsHalTargetTestDefaults",
         "libcodec2-hidl-client-defaults",
@@ -17,14 +17,14 @@
 }
 
 cc_defaults {
-    name: "VtsMediaC2V1_0Defaults",
+    name: "VtsHalMediaC2V1_0Defaults",
     defaults: [
         "VtsHalTargetTestDefaults",
         "libcodec2-hidl-client-defaults",
     ],
 
     static_libs: [
-        "VtsMediaC2V1_0CommonUtil",
+        "VtsHalMediaC2V1_0CommonUtil",
     ],
 
     shared_libs: [
diff --git a/media/codec2/hidl/1.0/vts/functional/common/README.md b/media/codec2/hidl/1.0/vts/functional/common/README.md
index 3deab10..f2f579c 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/README.md
+++ b/media/codec2/hidl/1.0/vts/functional/common/README.md
@@ -1,31 +1,36 @@
-## Codec2 VTS Hal @ 1.0 tests ##
----
-#### master :
+# Codec2 VTS Hal @ 1.0 tests #
+
+## master :
 Functionality of master is to enumerate all the Codec2 components available in C2 media service.
 
-usage: VtsHidlC2V1\_0TargetMasterTest -I default
+usage: `VtsHalMediaC2V1_0TargetMasterTest -I default`
 
-#### component :
+## component :
 Functionality of component test is to validate common functionality across all the Codec2 components available in C2 media service. For a standard C2 component, these tests are expected to pass.
 
-usage: VtsHidlC2V1\_0TargetComponentTest -I software -C <comp name>
-example: VtsHidlC2V1\_0TargetComponentTest -I software -C c2.android.vorbis.decoder
+usage: `VtsHalMediaC2V1_0TargetComponentTest -I software -C <comp name>`
 
-#### audio :
-Functionality of audio test is to validate audio specific functionality Codec2 components. The resource files for this test are taken from media/codec2/hidl/1.0/vts/functional/res. The path to these files on the device is required to be given for bitstream tests.
+example: `VtsHalMediaC2V1_0TargetComponentTest -I software -C c2.android.vorbis.decoder`
 
-usage: VtsHidlC2V1\_0TargetAudioDecTest -I default -C <comp name> -P /sdcard/res/
-usage: VtsHidlC2V1\_0TargetAudioEncTest -I software -C <comp name> -P /sdcard/res/
+## audio :
+Functionality of audio test is to validate audio specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
 
-example: VtsHidlC2V1\_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /sdcard/res/
-example: VtsHidlC2V1\_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /sdcard/res/
+usage: `VtsHalMediaC2V1_0TargetAudioDecTest -I default -C <comp name> -P <path to resource files>`
 
-#### video :
-Functionality of video test is to validate video specific functionality Codec2 components. The resource files for this test are taken from media/codec2/hidl/1.0/vts/functional/res. The path to these files on the device is required to be given for bitstream tests.
+usage: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C <comp name> -P <path to resource files>`
 
-usage: VtsHidlC2V1\_0TargetVideoDecTest -I default -C <comp name> -P /sdcard/res/
-usage: VtsHidlC2V1\_0TargetVideoEncTest -I software -C <comp name> -P /sdcard/res/
+example: `VtsHalMediaC2V1_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /data/local/tmp/media/`
 
-example: VtsHidlC2V1\_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /sdcard/res/
-example: VtsHidlC2V1\_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /sdcard/res/
+example: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /data/local/tmp/media/`
+
+## video :
+Functionality of video test is to validate video specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
+
+usage: `VtsHalMediaC2V1_0TargetVideoDecTest -I default -C <comp name> -P <path to resource files>`
+
+usage: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C <comp name> -P <path to resource files>`
+
+example: `VtsHalMediaC2V1_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /data/local/tmp/media/`
+
+example: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /data/local/tmp/media/`
 
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 c577dac..db59e54 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
@@ -118,7 +118,7 @@
         registerTestService<IComponentStore>();
     }
 
-    ComponentTestEnvironment() : res("/sdcard/media/") {}
+    ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
 
     void setComponent(const char* _component) { component = _component; }
 
diff --git a/media/codec2/hidl/1.0/vts/functional/component/Android.bp b/media/codec2/hidl/1.0/vts/functional/component/Android.bp
index 4b913b6..7ec64ee 100644
--- a/media/codec2/hidl/1.0/vts/functional/component/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/component/Android.bp
@@ -15,8 +15,8 @@
  */
 
 cc_test {
-    name: "VtsHidlC2V1_0TargetComponentTest",
-    defaults: ["VtsMediaC2V1_0Defaults"],
-    srcs: ["VtsHidlC2V1_0TargetComponentTest.cpp"],
+    name: "VtsHalMediaC2V1_0TargetComponentTest",
+    defaults: ["VtsHalMediaC2V1_0Defaults"],
+    srcs: ["VtsHalMediaC2V1_0TargetComponentTest.cpp"],
 }
 
diff --git a/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
similarity index 95%
rename from media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
index 74548b5..9dc541c 100644
--- a/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
@@ -144,8 +144,7 @@
 
     // Queueing an empty WorkBundle
     std::list<std::unique_ptr<C2Work>> workList;
-    err = mComponent->queue(&workList);
-    ASSERT_EQ(err, C2_OK);
+    mComponent->queue(&workList);
 
     err = mComponent->reset();
     ASSERT_EQ(err, C2_OK);
@@ -183,33 +182,23 @@
 // Test Multiple Start Stop Reset Test
 TEST_F(Codec2ComponentHidlTest, MultipleStartStopReset) {
     ALOGV("Multiple Start Stop and Reset Test");
-    c2_status_t err = C2_OK;
 
     for (size_t i = 0; i < MAX_RETRY; i++) {
-        err = mComponent->start();
-        ASSERT_EQ(err, C2_OK);
-
-        err = mComponent->stop();
-        ASSERT_EQ(err, C2_OK);
+        mComponent->start();
+        mComponent->stop();
     }
 
-    err = mComponent->start();
-    ASSERT_EQ(err, C2_OK);
+    ASSERT_EQ(mComponent->start(), C2_OK);
 
     for (size_t i = 0; i < MAX_RETRY; i++) {
-        err = mComponent->reset();
-        ASSERT_EQ(err, C2_OK);
+        mComponent->reset();
     }
 
-    err = mComponent->start();
-    ASSERT_EQ(err, C2_OK);
-
-    err = mComponent->stop();
-    ASSERT_EQ(err, C2_OK);
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
 
     // Second stop should return error
-    err = mComponent->stop();
-    ASSERT_NE(err, C2_OK);
+    ASSERT_NE(mComponent->stop(), C2_OK);
 }
 
 // Test Component Release API
@@ -233,8 +222,7 @@
     ASSERT_EQ(failures.size(), 0u);
 
     for (size_t i = 0; i < MAX_RETRY; i++) {
-        err = mComponent->release();
-        ASSERT_EQ(err, C2_OK);
+        mComponent->release();
     }
 }
 
@@ -332,14 +320,12 @@
     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();
diff --git a/media/codec2/hidl/1.0/vts/functional/master/Android.bp b/media/codec2/hidl/1.0/vts/functional/master/Android.bp
index e164d68..53e323e 100644
--- a/media/codec2/hidl/1.0/vts/functional/master/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/master/Android.bp
@@ -15,8 +15,8 @@
  */
 
 cc_test {
-    name: "VtsHidlC2V1_0TargetMasterTest",
-    defaults: ["VtsMediaC2V1_0Defaults"],
-    srcs: ["VtsHidlC2V1_0TargetMasterTest.cpp"],
+    name: "VtsHalMediaC2V1_0TargetMasterTest",
+    defaults: ["VtsHalMediaC2V1_0Defaults"],
+    srcs: ["VtsHalMediaC2V1_0TargetMasterTest.cpp"],
 }
 
diff --git a/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp b/media/codec2/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/functional/video/Android.bp b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
index 6e57ee7..be35b02 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
@@ -15,14 +15,14 @@
  */
 
 cc_test {
-    name: "VtsHidlC2V1_0TargetVideoDecTest",
-    defaults: ["VtsMediaC2V1_0Defaults"],
-    srcs: ["VtsHidlC2V1_0TargetVideoDecTest.cpp"],
+    name: "VtsHalMediaC2V1_0TargetVideoDecTest",
+    defaults: ["VtsHalMediaC2V1_0Defaults"],
+    srcs: ["VtsHalMediaC2V1_0TargetVideoDecTest.cpp"],
 }
 
 cc_test {
-    name: "VtsHidlC2V1_0TargetVideoEncTest",
-    defaults: ["VtsMediaC2V1_0Defaults"],
-    srcs: ["VtsHidlC2V1_0TargetVideoEncTest.cpp"],
+    name: "VtsHalMediaC2V1_0TargetVideoEncTest",
+    defaults: ["VtsHalMediaC2V1_0Defaults"],
+    srcs: ["VtsHalMediaC2V1_0TargetVideoEncTest.cpp"],
 }
 
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
similarity index 97%
rename from media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 33fa848..5e28750 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -46,6 +46,10 @@
     explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
         : C2Buffer(
               {block->share(block->offset(), block->size(), ::C2Fence())}) {}
+
+    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block, size_t size)
+        : C2Buffer(
+              {block->share(block->offset(), size, ::C2Fence())}) {}
 };
 
 static ComponentTestEnvironment* gEnv = nullptr;
@@ -120,6 +124,13 @@
         mTimestampUs = 0u;
         mTimestampDevTest = false;
         if (mCompName == unknown_comp) mDisableTest = true;
+
+        C2SecureModeTuning secureModeTuning{};
+        mComponent->query({ &secureModeTuning }, {}, C2_MAY_BLOCK, nullptr);
+        if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) {
+            mDisableTest = true;
+        }
+
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
     }
 
@@ -371,11 +382,12 @@
         ASSERT_EQ(eleStream.gcount(), size);
 
         work->input.buffers.clear();
+        auto alignedSize = ALIGN(size, PAGE_SIZE);
         if (size) {
             std::shared_ptr<C2LinearBlock> block;
             ASSERT_EQ(C2_OK,
                     linearPool->fetchLinearBlock(
-                        size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+                        alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
                         &block));
             ASSERT_TRUE(block);
 
@@ -385,13 +397,13 @@
                 fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
                 break;
             }
-            ASSERT_EQ((size_t)size, view.capacity());
+            ASSERT_EQ((size_t)alignedSize, view.capacity());
             ASSERT_EQ(0u, view.offset());
-            ASSERT_EQ((size_t)size, view.size());
+            ASSERT_EQ((size_t)alignedSize, view.size());
 
             memcpy(view.base(), data, size);
 
-            work->input.buffers.emplace_back(new LinearBuffer(block));
+            work->input.buffers.emplace_back(new LinearBuffer(block, size));
             free(data);
         }
         work->worklets.clear();
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
similarity index 89%
rename from media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index 6bcf840..c1f5a92 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -284,15 +284,16 @@
                    std::list<std::unique_ptr<C2Work>>& workQueue,
                    std::list<uint64_t>& flushedIndices,
                    std::shared_ptr<C2BlockPool>& graphicPool,
-                   std::ifstream& eleStream, uint32_t frameID,
-                   uint32_t nFrames, uint32_t nWidth, int32_t nHeight,
-                   bool flushed = false,bool signalEOS = true) {
+                   std::ifstream& eleStream, bool& disableTest,
+                   uint32_t frameID, uint32_t nFrames, uint32_t nWidth,
+                   int32_t nHeight, bool flushed = false, bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
 
     uint32_t maxRetry = 0;
     int bytesCount = nWidth * nHeight * 3 >> 1;
     int32_t timestampIncr = ENCODER_TIMESTAMP_INCREMENT;
     uint64_t timestamp = 0;
+    c2_status_t err = C2_OK;
     while (1) {
         if (nFrames == 0) break;
         uint32_t flags = 0;
@@ -333,16 +334,21 @@
             ASSERT_EQ(eleStream.gcount(), bytesCount);
         }
         std::shared_ptr<C2GraphicBlock> block;
-        ASSERT_EQ(
-            C2_OK,
-            graphicPool->fetchGraphicBlock(
+        err = graphicPool->fetchGraphicBlock(
                 nWidth, nHeight, HAL_PIXEL_FORMAT_YV12,
-                {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
+                {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+        if (err != C2_OK) {
+            fprintf(stderr, "fetchGraphicBlock failed : %d\n", err);
+            disableTest = true;
+            break;
+        }
+
         ASSERT_TRUE(block);
         // Graphic View
         C2GraphicView view = block->map().get();
         if (view.error() != C2_OK) {
             fprintf(stderr, "C2GraphicBlock::map() failed : %d", view.error());
+            disableTest = true;
             break;
         }
 
@@ -420,8 +426,16 @@
     ASSERT_EQ(mComponent->start(), C2_OK);
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream,
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
                       0, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
+    // mDisableTest will be set if buffer was not fetched properly.
+    // This may happen when resolution is not proper but config suceeded
+    // In this cases, we skip encoding the input stream
+    if (mDisableTest) {
+        std::cout << "[   WARN   ] Test Disabled \n";
+        ASSERT_EQ(mComponent->stop(), C2_OK);
+        return;
+    }
 
     // If EOS is not sent, sending empty input with EOS flag
     inputFrames = ENC_NUM_FRAMES;
@@ -531,8 +545,17 @@
     ALOGV("mURL : %s", mURL);
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream,
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
                       0, numFramesFlushed, nWidth, nHeight));
+    // mDisableTest will be set if buffer was not fetched properly.
+    // This may happen when resolution is not proper but config suceeded
+    // In this cases, we skip encoding the input stream
+    if (mDisableTest) {
+        std::cout << "[   WARN   ] Test Disabled \n";
+        ASSERT_EQ(mComponent->stop(), C2_OK);
+        return;
+    }
+
     std::list<std::unique_ptr<C2Work>> flushedWork;
     c2_status_t err =
         mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
@@ -561,10 +584,19 @@
     mFlushedIndices.clear();
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream,
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
                       numFramesFlushed, numFrames - numFramesFlushed,
                       nWidth, nHeight, true));
     eleStream.close();
+    // mDisableTest will be set if buffer was not fetched properly.
+    // This may happen when resolution is not proper but config suceeded
+    // In this cases, we skip encoding the input stream
+    if (mDisableTest) {
+        std::cout << "[   WARN   ] Test Disabled \n";
+        ASSERT_EQ(mComponent->stop(), C2_OK);
+        return;
+    }
+
     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
     ASSERT_NO_FATAL_FAILURE(
@@ -607,19 +639,19 @@
 
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream,
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
                       0, 1, nWidth, nHeight, false, false));
 
     // Feed larger input buffer.
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream,
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
                       1, 1, nWidth*2, nHeight*2, false, false));
 
     // Feed smaller input buffer.
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream,
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
                       2, 1, nWidth/2, nHeight/2, false, true));
 
     // blocking call to ensures application to Wait till all the inputs are
@@ -629,15 +661,13 @@
         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
 
     if (mFramesReceived != 3) {
-        ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGE("framesReceived : %d inputFrames : 3", mFramesReceived);
-        ASSERT_TRUE(false);
+        std::cout << "[   WARN   ] Component didn't receive all buffers back \n";
+        ALOGW("framesReceived : %d inputFrames : 3", mFramesReceived);
     }
 
     if (mFailedWorkReceived == 0) {
-        ALOGE("Expected failed frame count mismatch");
-        ALOGE("failedFramesReceived : %d", mFailedWorkReceived);
-        ASSERT_TRUE(false);
+        std::cout << "[   WARN   ] Expected failed frame count mismatch \n";
+        ALOGW("failedFramesReceived : %d", mFailedWorkReceived);
     }
 
     ASSERT_EQ(mComponent->stop(), C2_OK);
@@ -665,8 +695,17 @@
 
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, 0,
-                      MAX_INPUT_BUFFERS, nWidth, nHeight));
+                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
+                      0, MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
+
+    // mDisableTest will be set if buffer was not fetched properly.
+    // This may happen when resolution is not proper but config suceeded
+    // In this cases, we skip encoding the input stream
+    if (mDisableTest) {
+        std::cout << "[   WARN   ] Test Disabled \n";
+        ASSERT_EQ(mComponent->stop(), C2_OK);
+        return;
+    }
 
     ALOGD("Waiting for input consumption");
     ASSERT_NO_FATAL_FAILURE(
@@ -676,6 +715,7 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
     ASSERT_EQ(mComponent->reset(), C2_OK);
 }
+
 INSTANTIATE_TEST_CASE_P(NonStdSizes, Codec2VideoEncResolutionTest, ::testing::Values(
     std::make_pair(52, 18),
     std::make_pair(365, 365),
diff --git a/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
index dd45557..e37ca38 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
@@ -23,6 +23,8 @@
 #define ENC_DEFAULT_FRAME_HEIGHT 288
 #define MAX_ITERATIONS 128
 
+#define ALIGN(_sz, _align) ((_sz + (_align - 1)) & ~(_align - 1))
+
 /*
  * Common video utils
  */
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 2b417a6..5ed54f1 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -959,9 +959,9 @@
 
 std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface(
         char const* serviceName) {
-    uint32_t inputSurfaceSetting = ::android::base::GetUintProperty(
-            "debug.stagefright.c2inputsurface", uint32_t(0));
-    if (inputSurfaceSetting == 0) {
+    int32_t inputSurfaceSetting = ::android::base::GetIntProperty(
+            "debug.stagefright.c2inputsurface", int32_t(0));
+    if (inputSurfaceSetting <= 0) {
         return nullptr;
     }
     size_t index = GetServiceNames().size();
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 8ae80ee..9c84c71 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -9,6 +9,7 @@
         "CCodecConfig.cpp",
         "Codec2Buffer.cpp",
         "Codec2InfoBuilder.cpp",
+        "Omx2IGraphicBufferSource.cpp",
         "PipelineWatcher.cpp",
         "ReflectedParamUpdater.cpp",
         "SkipCutBuffer.cpp",
@@ -41,8 +42,10 @@
         "libmedia",
         "libmedia_omx",
         "libsfplugin_ccodec_utils",
+        "libstagefright_bufferqueue_helper",
         "libstagefright_codecbase",
         "libstagefright_foundation",
+        "libstagefright_omx",
         "libstagefright_omx_utils",
         "libstagefright_xmlparser",
         "libui",
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 3a93c2a..78d221e 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -36,6 +36,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
+#include <utils/Thread.h>
 
 #include "C2OMXNode.h"
 
@@ -50,16 +51,128 @@
 
 }  // namespace
 
+class C2OMXNode::QueueThread : public Thread {
+public:
+    QueueThread() : Thread(false) {}
+    ~QueueThread() override = default;
+    void queue(
+            const std::shared_ptr<Codec2Client::Component> &comp,
+            int fenceFd,
+            std::unique_ptr<C2Work> &&work,
+            android::base::unique_fd &&fd0,
+            android::base::unique_fd &&fd1) {
+        Mutexed<Jobs>::Locked jobs(mJobs);
+        auto it = jobs->queues.try_emplace(comp, comp, systemTime()).first;
+        it->second.workList.emplace_back(
+                std::move(work), fenceFd, std::move(fd0), std::move(fd1));
+        jobs->cond.broadcast();
+    }
+
+protected:
+    bool threadLoop() override {
+        constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000;  // 10ms
+        constexpr nsecs_t kWaitNs = kIntervalNs * 2;
+        for (int i = 0; i < 2; ++i) {
+            Mutexed<Jobs>::Locked jobs(mJobs);
+            nsecs_t nowNs = systemTime();
+            bool queued = false;
+            for (auto it = jobs->queues.begin(); it != jobs->queues.end(); ) {
+                Queue &queue = it->second;
+                if (queue.workList.empty()
+                        || nowNs - queue.lastQueuedTimestampNs < kIntervalNs) {
+                    ++it;
+                    continue;
+                }
+                std::shared_ptr<Codec2Client::Component> comp = queue.component.lock();
+                if (!comp) {
+                    it = jobs->queues.erase(it);
+                    continue;
+                }
+                std::list<std::unique_ptr<C2Work>> items;
+                std::vector<int> fenceFds;
+                std::vector<android::base::unique_fd> uniqueFds;
+                while (!queue.workList.empty()) {
+                    items.push_back(std::move(queue.workList.front().work));
+                    fenceFds.push_back(queue.workList.front().fenceFd);
+                    uniqueFds.push_back(std::move(queue.workList.front().fd0));
+                    uniqueFds.push_back(std::move(queue.workList.front().fd1));
+                    queue.workList.pop_front();
+                }
+
+                jobs.unlock();
+                for (int fenceFd : fenceFds) {
+                    sp<Fence> fence(new Fence(fenceFd));
+                    fence->waitForever(LOG_TAG);
+                }
+                comp->queue(&items);
+                for (android::base::unique_fd &ufd : uniqueFds) {
+                    (void)ufd.release();
+                }
+                jobs.lock();
+
+                it = jobs->queues.upper_bound(comp);
+                queued = true;
+            }
+            if (queued) {
+                return true;
+            }
+            if (i == 0) {
+                jobs.waitForConditionRelative(jobs->cond, kWaitNs);
+            }
+        }
+        return true;
+    }
+
+private:
+    struct WorkFence {
+        WorkFence(std::unique_ptr<C2Work> &&w, int fd) : work(std::move(w)), fenceFd(fd) {}
+
+        WorkFence(
+                std::unique_ptr<C2Work> &&w,
+                int fd,
+                android::base::unique_fd &&uniqueFd0,
+                android::base::unique_fd &&uniqueFd1)
+            : work(std::move(w)),
+              fenceFd(fd),
+              fd0(std::move(uniqueFd0)),
+              fd1(std::move(uniqueFd1)) {}
+
+        std::unique_ptr<C2Work> work;
+        int fenceFd;
+        android::base::unique_fd fd0;
+        android::base::unique_fd fd1;
+    };
+    struct Queue {
+        Queue(const std::shared_ptr<Codec2Client::Component> &comp, nsecs_t timestamp)
+            : component(comp), lastQueuedTimestampNs(timestamp) {}
+        Queue(const Queue &) = delete;
+        Queue &operator =(const Queue &) = delete;
+
+        std::weak_ptr<Codec2Client::Component> component;
+        std::list<WorkFence> workList;
+        nsecs_t lastQueuedTimestampNs;
+    };
+    struct Jobs {
+        std::map<std::weak_ptr<Codec2Client::Component>,
+                 Queue,
+                 std::owner_less<std::weak_ptr<Codec2Client::Component>>> queues;
+        Condition cond;
+    };
+    Mutexed<Jobs> mJobs;
+};
+
 C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp)
     : mComp(comp), mFrameIndex(0), mWidth(0), mHeight(0), mUsage(0),
-      mAdjustTimestampGapUs(0), mFirstInputFrame(true) {
+      mAdjustTimestampGapUs(0), mFirstInputFrame(true),
+      mQueueThread(new QueueThread) {
     android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
+    mQueueThread->run("C2OMXNode", PRIORITY_AUDIO);
 }
 
 status_t C2OMXNode::freeNode() {
     mComp.reset();
     android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
-    return OK;
+    return mQueueThread->requestExitAndWait();
 }
 
 status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
@@ -216,11 +329,6 @@
 status_t C2OMXNode::emptyBuffer(
         buffer_id buffer, const OMXBuffer &omxBuf,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
-    // TODO: better fence handling
-    if (fenceFd >= 0) {
-        sp<Fence> fence = new Fence(fenceFd);
-        fence->waitForever(LOG_TAG);
-    }
     std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
     if (!comp) {
         return NO_INIT;
@@ -299,22 +407,8 @@
     }
     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);
-    if (err != C2_OK) {
-        (void)fd0.release();
-        (void)fd1.release();
-        return UNKNOWN_ERROR;
-    }
-
-    mBufferIdsInUse.lock()->emplace(index, buffer);
-
-    // release ownership of the fds
-    (void)fd0.release();
-    (void)fd1.release();
+    mBufferIdsInUse.lock()->emplace(work->input.ordinal.frameIndex.peeku(), buffer);
+    mQueueThread->queue(comp, fenceFd, std::move(work), std::move(fd0), std::move(fd1));
 
     return OK;
 }
diff --git a/media/codec2/sfplugin/C2OMXNode.h b/media/codec2/sfplugin/C2OMXNode.h
index 3ca6c0a..1717c96 100644
--- a/media/codec2/sfplugin/C2OMXNode.h
+++ b/media/codec2/sfplugin/C2OMXNode.h
@@ -113,6 +113,9 @@
     c2_cntr64_t mPrevCodecTimestamp; // adjusted (codec) timestamp for previous frame
 
     Mutexed<std::map<uint64_t, buffer_id>> mBufferIdsInUse;
+
+    class QueueThread;
+    sp<QueueThread> mQueueThread;
 };
 
 }  // namespace android
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index aa7189c..9d1cc60 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -45,6 +45,7 @@
 #include "CCodec.h"
 #include "CCodecBufferChannel.h"
 #include "InputSurfaceWrapper.h"
+#include "Omx2IGraphicBufferSource.h"
 
 extern "C" android::PersistentSurface *CreateInputSurface();
 
@@ -1067,6 +1068,7 @@
     OmxStatus s;
     android::sp<HGraphicBufferProducer> gbp;
     android::sp<HGraphicBufferSource> gbs;
+
     using ::android::hardware::Return;
     Return<void> transStatus = omx->createInputSurface(
             [&s, &gbp, &gbs](
@@ -1852,15 +1854,30 @@
 
 // Create Codec 2.0 input surface
 extern "C" android::PersistentSurface *CreateInputSurface() {
+    using namespace android;
     // Attempt to create a Codec2's input surface.
-    std::shared_ptr<android::Codec2Client::InputSurface> inputSurface =
-            android::Codec2Client::CreateInputSurface();
+    std::shared_ptr<Codec2Client::InputSurface> inputSurface =
+            Codec2Client::CreateInputSurface();
     if (!inputSurface) {
-        return nullptr;
+        if (property_get_int32("debug.stagefright.c2inputsurface", 0) == -1) {
+            sp<IGraphicBufferProducer> gbp;
+            sp<OmxGraphicBufferSource> gbs = new OmxGraphicBufferSource();
+            status_t err = gbs->initCheck();
+            if (err != OK) {
+                ALOGE("Failed to create persistent input surface: error %d", err);
+                return nullptr;
+            }
+            return new PersistentSurface(
+                    gbs->getIGraphicBufferProducer(),
+                    sp<IGraphicBufferSource>(
+                        new Omx2IGraphicBufferSource(gbs)));
+        } else {
+            return nullptr;
+        }
     }
-    return new android::PersistentSurface(
+    return new PersistentSurface(
             inputSurface->getGraphicBufferProducer(),
-            static_cast<android::sp<android::hidl::base::V1_0::IBase>>(
+            static_cast<sp<android::hidl::base::V1_0::IBase>>(
             inputSurface->getHalInterface()));
 }
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 8be9a1d..8308292 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -220,7 +220,6 @@
         const std::shared_ptr<CCodecCallback> &callback)
     : mHeapSeqNum(-1),
       mCCodecCallback(callback),
-      mDelay(0),
       mFrameIndex(0u),
       mFirstValidFrameIndex(0u),
       mMetaMode(MODE_NONE),
@@ -814,7 +813,6 @@
 
     size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
     size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
-    mDelay = inputDelayValue + pipelineDelayValue + outputDelayValue;
 
     // TODO: get this from input format
     bool secure = mComponent->getName().find(".secure") != std::string::npos;
@@ -888,6 +886,8 @@
 
         bool forceArrayMode = false;
         Mutexed<Input>::Locked input(mInput);
+        input->inputDelay = inputDelayValue;
+        input->pipelineDelay = pipelineDelayValue;
         input->numSlots = numInputSlots;
         input->extraBuffers.flush();
         input->numExtraSlots = 0u;
@@ -896,6 +896,9 @@
                 input->buffers.reset(new DummyInputBuffers(mName));
             } else if (mMetaMode == MODE_ANW) {
                 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
+                // This is to ensure buffers do not get released prematurely.
+                // TODO: handle this without going into array mode
+                forceArrayMode = true;
             } else {
                 input->buffers.reset(new GraphicInputBuffers(numInputSlots, mName));
             }
@@ -1054,6 +1057,7 @@
         }
 
         Mutexed<Output>::Locked output(mOutput);
+        output->outputDelay = outputDelayValue;
         output->numSlots = numOutputSlots;
         if (graphic) {
             if (outputSurface) {
@@ -1377,25 +1381,35 @@
                         (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
 
                         bool outputBuffersChanged = false;
-                        Mutexed<Output>::Locked output(mOutput);
-                        output->outputDelay = outputDelay.value;
-                        size_t numOutputSlots = outputDelay.value + kSmoothnessFactor;
-                        if (output->numSlots < numOutputSlots) {
-                            output->numSlots = numOutputSlots;
-                            if (output->buffers->isArrayMode()) {
-                                OutputBuffersArray *array =
-                                    (OutputBuffersArray *)output->buffers.get();
-                                ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
-                                      mName, numOutputSlots);
-                                array->grow(numOutputSlots);
-                                outputBuffersChanged = true;
+                        size_t numOutputSlots = 0;
+                        {
+                            Mutexed<Output>::Locked output(mOutput);
+                            output->outputDelay = outputDelay.value;
+                            numOutputSlots = outputDelay.value + kSmoothnessFactor;
+                            if (output->numSlots < numOutputSlots) {
+                                output->numSlots = numOutputSlots;
+                                if (output->buffers->isArrayMode()) {
+                                    OutputBuffersArray *array =
+                                        (OutputBuffersArray *)output->buffers.get();
+                                    ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
+                                          mName, numOutputSlots);
+                                    array->grow(numOutputSlots);
+                                    outputBuffersChanged = true;
+                                }
                             }
+                            numOutputSlots = output->numSlots;
                         }
-                        output.unlock();
 
                         if (outputBuffersChanged) {
                             mCCodecCallback->onOutputBuffersChanged();
                         }
+
+                        uint32_t depth = mReorderStash.lock()->depth();
+                        Mutexed<OutputSurface>::Locked output(mOutputSurface);
+                        output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
+                        if (output->surface) {
+                            output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
+                        }
                     }
                 }
                 break;
@@ -1620,7 +1634,12 @@
     // When client pushed EOS, we want all the work to be done quickly.
     // Otherwise, component may have stalled work due to input starvation up to
     // the sum of the delay in the pipeline.
-    size_t n = mInputMetEos ? 0 : mDelay;
+    size_t n = 0;
+    if (!mInputMetEos) {
+        size_t outputDelay = mOutput.lock()->outputDelay;
+        Mutexed<Input>::Locked input(mInput);
+        n = input->inputDelay + input->pipelineDelay + outputDelay;
+    }
     return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
 }
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index ae57678..ee3455d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -228,8 +228,6 @@
     QueueSync mQueueSync;
     std::vector<std::unique_ptr<C2Param>> mParamsToBeSet;
 
-    size_t mDelay;
-
     struct Input {
         Input();
 
@@ -306,6 +304,7 @@
                 const C2WorkOrdinalStruct &ordinal);
         void defer(const Entry &entry);
         bool hasPending() const;
+        uint32_t depth() const { return mDepth; }
 
     private:
         std::list<Entry> mPending;
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 5ebd5bd..26c702d 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -439,6 +439,10 @@
             });
 }
 
+size_t BuffersArrayImpl::arraySize() const {
+    return mBuffers.size();
+}
+
 // InputBuffersArray
 
 void InputBuffersArray::initialize(
@@ -883,11 +887,24 @@
             mAlloc = [format = mFormat, size] {
                 return new LocalLinearBuffer(format, new ABuffer(size));
             };
+            ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
             break;
         }
 
-        // TODO: add support
-        case C2BufferData::GRAPHIC:         [[fallthrough]];
+        case C2BufferData::GRAPHIC: {
+            // This is only called for RawGraphicOutputBuffers.
+            mAlloc = [format = mFormat,
+                      lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
+                return ConstGraphicBlockBuffer::AllocateEmpty(
+                        format,
+                        [lbp](size_t capacity) {
+                            return lbp->newBuffer(capacity);
+                        });
+            };
+            ALOGD("[%s] reallocating with graphic buffer: format = %s",
+                  mName, mFormat->debugString().c_str());
+            break;
+        }
 
         case C2BufferData::INVALID:         [[fallthrough]];
         case C2BufferData::LINEAR_CHUNKS:   [[fallthrough]];
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index e4f2809..2cb6b81 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -478,6 +478,11 @@
      */
     size_t numClientBuffers() const;
 
+    /**
+     * Return the size of the array.
+     */
+    size_t arraySize() const;
+
 private:
     std::string mImplName; ///< name for debugging
     const char *mName; ///< C-string version of name
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 702ad6f..5c8ad56 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -25,6 +25,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <nativebase/nativebase.h>
+#include <ui/Fence.h>
 
 #include <C2AllocatorGralloc.h>
 #include <C2BlockInternal.h>
@@ -590,7 +591,12 @@
     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
 
     meta->pBuffer = 0;
-    // TODO: fence
+    // TODO: wrap this in C2Fence so that the component can wait when it
+    //       actually starts processing.
+    if (meta->nFenceFd >= 0) {
+        sp<Fence> fence(new Fence(meta->nFenceFd));
+        fence->waitForever(LOG_TAG);
+    }
     return C2Buffer::CreateGraphicBuffer(
             block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
 #else
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index c54c601..6b75eba 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -194,7 +194,8 @@
     // TODO: get this from intf() as well, but how do we map them to
     // MediaCodec color formats?
     bool encoder = trait.kind == C2Component::KIND_ENCODER;
-    if (mediaType.find("video") != std::string::npos) {
+    if (mediaType.find("video") != std::string::npos
+            || mediaType.find("image") != std::string::npos) {
         // vendor video codecs prefer opaque format
         if (trait.name.find("android") == std::string::npos) {
             caps->addColorFormat(COLOR_FormatSurface);
diff --git a/media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp b/media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp
new file mode 100644
index 0000000..764fa00
--- /dev/null
+++ b/media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Omx2IGraphicBufferSource"
+#include <android-base/logging.h>
+
+#include "Omx2IGraphicBufferSource.h"
+
+#include <android/BnOMXBufferSource.h>
+#include <media/OMXBuffer.h>
+#include <media/stagefright/omx/OMXUtils.h>
+
+#include <OMX_Component.h>
+#include <OMX_Index.h>
+#include <OMX_IndexExt.h>
+
+namespace android {
+
+namespace /* unnamed */ {
+
+// OmxGraphicBufferSource -> IOMXBufferSource
+
+struct OmxGbs2IOmxBs : public BnOMXBufferSource {
+    sp<OmxGraphicBufferSource> mBase;
+    OmxGbs2IOmxBs(sp<OmxGraphicBufferSource> const& base) : mBase{base} {}
+    BnStatus onOmxExecuting() override {
+        return mBase->onOmxExecuting();
+    }
+    BnStatus onOmxIdle() override {
+        return mBase->onOmxIdle();
+    }
+    BnStatus onOmxLoaded() override {
+        return mBase->onOmxLoaded();
+    }
+    BnStatus onInputBufferAdded(int32_t bufferId) override {
+        return mBase->onInputBufferAdded(bufferId);
+    }
+    BnStatus onInputBufferEmptied(
+            int32_t bufferId,
+            OMXFenceParcelable const& fenceParcel) override {
+        return mBase->onInputBufferEmptied(bufferId, fenceParcel.get());
+    }
+};
+
+struct OmxNodeWrapper : public IOmxNodeWrapper {
+    sp<IOMXNode> mBase;
+    OmxNodeWrapper(sp<IOMXNode> const& base) : mBase{base} {}
+    status_t emptyBuffer(
+            int32_t bufferId, uint32_t flags,
+            const sp<GraphicBuffer> &buffer,
+            int64_t timestamp, int fenceFd) override {
+        return mBase->emptyBuffer(bufferId, buffer, flags, timestamp, fenceFd);
+    }
+    void dispatchDataSpaceChanged(
+            int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
+        omx_message msg{};
+        msg.type = omx_message::EVENT;
+        msg.fenceFd = -1;
+        msg.u.event_data.event = OMX_EventDataSpaceChanged;
+        msg.u.event_data.data1 = dataSpace;
+        msg.u.event_data.data2 = aspects;
+        msg.u.event_data.data3 = pixelFormat;
+        mBase->dispatchMessage(msg);
+    }
+};
+
+} // unnamed namespace
+
+// Omx2IGraphicBufferSource
+Omx2IGraphicBufferSource::Omx2IGraphicBufferSource(
+        sp<OmxGraphicBufferSource> const& base)
+      : mBase{base},
+        mOMXBufferSource{new OmxGbs2IOmxBs(base)} {
+}
+
+BnStatus Omx2IGraphicBufferSource::setSuspend(
+        bool suspend, int64_t timeUs) {
+    return BnStatus::fromStatusT(mBase->setSuspend(suspend, timeUs));
+}
+
+BnStatus Omx2IGraphicBufferSource::setRepeatPreviousFrameDelayUs(
+        int64_t repeatAfterUs) {
+    return BnStatus::fromStatusT(mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs));
+}
+
+BnStatus Omx2IGraphicBufferSource::setMaxFps(float maxFps) {
+    return BnStatus::fromStatusT(mBase->setMaxFps(maxFps));
+}
+
+BnStatus Omx2IGraphicBufferSource::setTimeLapseConfig(
+        double fps, double captureFps) {
+    return BnStatus::fromStatusT(mBase->setTimeLapseConfig(fps, captureFps));
+}
+
+BnStatus Omx2IGraphicBufferSource::setStartTimeUs(
+        int64_t startTimeUs) {
+    return BnStatus::fromStatusT(mBase->setStartTimeUs(startTimeUs));
+}
+
+BnStatus Omx2IGraphicBufferSource::setStopTimeUs(
+        int64_t stopTimeUs) {
+    return BnStatus::fromStatusT(mBase->setStopTimeUs(stopTimeUs));
+}
+
+BnStatus Omx2IGraphicBufferSource::getStopTimeOffsetUs(
+        int64_t *stopTimeOffsetUs) {
+    return BnStatus::fromStatusT(mBase->getStopTimeOffsetUs(stopTimeOffsetUs));
+}
+
+BnStatus Omx2IGraphicBufferSource::setColorAspects(
+        int32_t aspects) {
+    return BnStatus::fromStatusT(mBase->setColorAspects(aspects));
+}
+
+BnStatus Omx2IGraphicBufferSource::setTimeOffsetUs(
+        int64_t timeOffsetsUs) {
+    return BnStatus::fromStatusT(mBase->setTimeOffsetUs(timeOffsetsUs));
+}
+
+BnStatus Omx2IGraphicBufferSource::signalEndOfInputStream() {
+    return BnStatus::fromStatusT(mBase->signalEndOfInputStream());
+}
+
+BnStatus Omx2IGraphicBufferSource::configure(
+        const sp<IOMXNode>& omxNode, int32_t dataSpace) {
+    if (omxNode == NULL) {
+        return BnStatus::fromServiceSpecificError(BAD_VALUE);
+    }
+
+    // Do setInputSurface() first, the node will try to enable metadata
+    // mode on input, and does necessary error checking. If this fails,
+    // we can't use this input surface on the node.
+    status_t err = omxNode->setInputSurface(mOMXBufferSource);
+    if (err != NO_ERROR) {
+        ALOGE("Unable to set input surface: %d", err);
+        return BnStatus::fromServiceSpecificError(err);
+    }
+
+    uint32_t consumerUsage;
+    if (omxNode->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+            &consumerUsage, sizeof(consumerUsage)) != OK) {
+        consumerUsage = 0;
+    }
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = 0; // kPortIndexInput
+
+    err = omxNode->getParameter(
+            OMX_IndexParamPortDefinition, &def, sizeof(def));
+    if (err != NO_ERROR) {
+        ALOGE("Failed to get port definition: %d", err);
+        return BnStatus::fromServiceSpecificError(UNKNOWN_ERROR);
+    }
+
+    return BnStatus::fromStatusT(mBase->configure(
+            new OmxNodeWrapper(omxNode),
+            dataSpace,
+            def.nBufferCountActual,
+            def.format.video.nFrameWidth,
+            def.format.video.nFrameHeight,
+            consumerUsage));
+}
+
+} // namespace android
+
diff --git a/media/codec2/sfplugin/Omx2IGraphicBufferSource.h b/media/codec2/sfplugin/Omx2IGraphicBufferSource.h
new file mode 100644
index 0000000..20fd1ec
--- /dev/null
+++ b/media/codec2/sfplugin/Omx2IGraphicBufferSource.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OMX_2_IGRAPHICBUFFERSOURCE_H_
+#define OMX_2_IGRAPHICBUFFERSOURCE_H_
+
+#include <android/BnGraphicBufferSource.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
+
+namespace android {
+
+using BnStatus = ::android::binder::Status;
+
+struct Omx2IGraphicBufferSource : public BnGraphicBufferSource {
+    sp<OmxGraphicBufferSource> mBase;
+    sp<IOMXBufferSource> mOMXBufferSource;
+    Omx2IGraphicBufferSource(sp<OmxGraphicBufferSource> const& base);
+    BnStatus configure(const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
+    BnStatus setSuspend(bool suspend, int64_t timeUs) override;
+    BnStatus setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
+    BnStatus setMaxFps(float maxFps) override;
+    BnStatus setTimeLapseConfig(double fps, double captureFps) override;
+    BnStatus setStartTimeUs(int64_t startTimeUs) override;
+    BnStatus setStopTimeUs(int64_t stopTimeUs) override;
+    BnStatus getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) override;
+    BnStatus setColorAspects(int32_t aspects) override;
+    BnStatus setTimeOffsetUs(int64_t timeOffsetsUs) override;
+    BnStatus signalEndOfInputStream() override;
+};
+
+} // namespace android
+
+#endif // OMX_2_IGRAPHICBUFFERSOURCE_H_
+
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index ca69810..b6ddfab 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -50,8 +50,10 @@
 
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.media.bufferpool@2.0",
         "libbase",
         "libbinder",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 286c48a..af97e61 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -20,6 +20,8 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
 #include <cutils/native_handle.h>
 #include <hardware/gralloc.h>
 
@@ -29,7 +31,7 @@
 
 namespace android {
 
-namespace {
+namespace /* unnamed */ {
     enum : uint64_t {
         /**
          * Usage mask that is passed through from gralloc to Codec 2.0 usage.
@@ -40,7 +42,7 @@
 
     // verify that passthrough mask is within the platform mask
     static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, "");
-}
+} // unnamed
 
 C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) {
     // gralloc does not support WRITE_PROTECTED
@@ -59,39 +61,59 @@
             (expected & PASSTHROUGH_USAGE_MASK));
 }
 
-using ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using ::android::hardware::graphics::mapper::V2_0::Error;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using PixelFormat2 = ::android::hardware::graphics::common::V1_0::PixelFormat;
+using PixelFormat3 = ::android::hardware::graphics::common::V1_2::PixelFormat;
 
-namespace {
+using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using BufferDescriptor2 = ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
+using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
 
-struct BufferDescriptorInfo {
-    IMapper::BufferDescriptorInfo mapperInfo;
+using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
+using BufferDescriptor3 = ::android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
+using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
+
+namespace /* unnamed */ {
+
+struct BufferDescriptorInfo2 {
+    IMapper2::BufferDescriptorInfo mapperInfo;
     uint32_t stride;
 };
 
-}
+struct BufferDescriptorInfo3 {
+    IMapper3::BufferDescriptorInfo mapperInfo;
+    uint32_t stride;
+};
 
 /* ===================================== GRALLOC ALLOCATION ==================================== */
-static c2_status_t maperr2error(Error maperr) {
+c2_status_t maperr2error(Error2 maperr) {
     switch (maperr) {
-        case Error::NONE:           return C2_OK;
-        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
-        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
-        case Error::BAD_VALUE:      return C2_BAD_VALUE;
-        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
-        case Error::UNSUPPORTED:    return C2_CANNOT_DO;
+        case Error2::NONE:           return C2_OK;
+        case Error2::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error2::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error2::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error2::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error2::UNSUPPORTED:    return C2_CANNOT_DO;
     }
     return C2_CORRUPTED;
 }
 
-static
+c2_status_t maperr2error(Error3 maperr) {
+    switch (maperr) {
+        case Error3::NONE:           return C2_OK;
+        case Error3::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error3::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error3::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error3::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error3::UNSUPPORTED:    return C2_CANNOT_DO;
+    }
+    return C2_CORRUPTED;
+}
+
 bool native_handle_is_invalid(const native_handle_t *const handle) {
     // perform basic validation of a native handle
     if (handle == nullptr) {
@@ -230,23 +252,6 @@
         return res;
     }
 
-    static native_handle_t* UnwrapNativeHandle(
-            const C2Handle *const handle,
-            uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
-        const ExtraData *xd = getExtraData(handle);
-        if (xd == nullptr || xd->magic != MAGIC) {
-            return nullptr;
-        }
-        *generation = xd->generation;
-        *igbp_id = unsigned(xd->igbp_id_lo) | uint64_t(unsigned(xd->igbp_id_hi)) << 32;
-        *igbp_slot = xd->igbp_slot;
-        native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS);
-        if (res != nullptr) {
-            memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts));
-        }
-        return res;
-    }
-
     static const C2HandleGralloc* Import(
             const C2Handle *const handle,
             uint32_t *width, uint32_t *height, uint32_t *format,
@@ -268,16 +273,12 @@
     }
 };
 
+} // unnamed namespace
+
 native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
     return C2HandleGralloc::UnwrapNativeHandle(handle);
 }
 
-native_handle_t *UnwrapNativeCodec2GrallocHandle(
-        const C2Handle *const handle,
-        uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
-    return C2HandleGralloc::UnwrapNativeHandle(handle, generation, igbp_id, igbp_slot);
-}
-
 C2Handle *WrapNativeCodec2GrallocHandle(
         const native_handle_t *const handle,
         uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
@@ -309,8 +310,14 @@
     // internal methods
     // |handle| will be moved.
     C2AllocationGralloc(
-              const BufferDescriptorInfo &info,
-              const sp<IMapper> &mapper,
+              const BufferDescriptorInfo2 &info,
+              const sp<IMapper2> &mapper,
+              hidl_handle &hidlHandle,
+              const C2HandleGralloc *const handle,
+              C2Allocator::id_t allocatorId);
+    C2AllocationGralloc(
+              const BufferDescriptorInfo3 &info,
+              const sp<IMapper3> &mapper,
               hidl_handle &hidlHandle,
               const C2HandleGralloc *const handle,
               C2Allocator::id_t allocatorId);
@@ -318,8 +325,10 @@
     c2_status_t status() const;
 
 private:
-    const BufferDescriptorInfo mInfo;
-    const sp<IMapper> mMapper;
+    const BufferDescriptorInfo2 mInfo2{};
+    const sp<IMapper2> mMapper2{nullptr};
+    const BufferDescriptorInfo3 mInfo3{};
+    const sp<IMapper3> mMapper3{nullptr};
     const hidl_handle mHidlHandle;
     const C2HandleGralloc *mHandle;
     buffer_handle_t mBuffer;
@@ -330,14 +339,31 @@
 };
 
 C2AllocationGralloc::C2AllocationGralloc(
-          const BufferDescriptorInfo &info,
-          const sp<IMapper> &mapper,
+          const BufferDescriptorInfo2 &info,
+          const sp<IMapper2> &mapper,
           hidl_handle &hidlHandle,
           const C2HandleGralloc *const handle,
           C2Allocator::id_t allocatorId)
     : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
-      mInfo(info),
-      mMapper(mapper),
+      mInfo2(info),
+      mMapper2(mapper),
+      mHidlHandle(std::move(hidlHandle)),
+      mHandle(handle),
+      mBuffer(nullptr),
+      mLockedHandle(nullptr),
+      mLocked(false),
+      mAllocatorId(allocatorId) {
+}
+
+C2AllocationGralloc::C2AllocationGralloc(
+          const BufferDescriptorInfo3 &info,
+          const sp<IMapper3> &mapper,
+          hidl_handle &hidlHandle,
+          const C2HandleGralloc *const handle,
+          C2Allocator::id_t allocatorId)
+    : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
+      mInfo3(info),
+      mMapper3(mapper),
       mHidlHandle(std::move(hidlHandle)),
       mHandle(handle),
       mBuffer(nullptr),
@@ -353,7 +379,17 @@
         unmap(addr, C2Rect(), nullptr);
     }
     if (mBuffer) {
-        mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+        if (mMapper2) {
+            if (!mMapper2->freeBuffer(const_cast<native_handle_t *>(
+                    mBuffer)).isOk()) {
+                ALOGE("failed transaction: freeBuffer");
+            }
+        } else {
+            if (!mMapper3->freeBuffer(const_cast<native_handle_t *>(
+                    mBuffer)).isOk()) {
+                ALOGE("failed transaction: freeBuffer");
+            }
+        }
     }
     if (mHandle) {
         native_handle_delete(
@@ -388,13 +424,29 @@
 
     c2_status_t err = C2_OK;
     if (!mBuffer) {
-        mMapper->importBuffer(
-                mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        mBuffer = static_cast<buffer_handle_t>(buffer);
-                    }
-                });
+        if (mMapper2) {
+            if (!mMapper2->importBuffer(
+                    mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                        err = maperr2error(maperr);
+                        if (err == C2_OK) {
+                            mBuffer = static_cast<buffer_handle_t>(buffer);
+                        }
+                    }).isOk()) {
+                ALOGE("failed transaction: importBuffer");
+                return C2_CORRUPTED;
+            }
+        } else {
+            if (!mMapper3->importBuffer(
+                    mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                        err = maperr2error(maperr);
+                        if (err == C2_OK) {
+                            mBuffer = static_cast<buffer_handle_t>(buffer);
+                        }
+                    }).isOk()) {
+                ALOGE("failed transaction: importBuffer (@3.0)");
+                return C2_CORRUPTED;
+            }
+        }
         if (err != C2_OK) {
             ALOGD("importBuffer failed: %d", err);
             return err;
@@ -409,30 +461,66 @@
         if (mHandle) {
             mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot);
         }
-        mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
-                mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height,
-                (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride,
-                generation, igbp_id, igbp_slot);
+        if (mMapper2) {
+            mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
+                    mBuffer, mInfo2.mapperInfo.width, mInfo2.mapperInfo.height,
+                    (uint32_t)mInfo2.mapperInfo.format, mInfo2.mapperInfo.usage,
+                    mInfo2.stride, generation, igbp_id, igbp_slot);
+        } else {
+            mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
+                    mBuffer, mInfo3.mapperInfo.width, mInfo3.mapperInfo.height,
+                    (uint32_t)mInfo3.mapperInfo.format, mInfo3.mapperInfo.usage,
+                    mInfo3.stride, generation, igbp_id, igbp_slot);
+        }
     }
 
-    switch (mInfo.mapperInfo.format) {
-        case PixelFormat::RGBA_1010102: {
+    PixelFormat3 format = mMapper2 ?
+            PixelFormat3(mInfo2.mapperInfo.format) :
+            PixelFormat3(mInfo3.mapperInfo.format);
+    switch (format) {
+        case PixelFormat3::RGBA_1010102: {
             // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
             // Surface. In all other cases it is RGBA. We don't know which case it is here, so
             // default to YUV for now.
             void *pointer = nullptr;
-            mMapper->lock(
-                    const_cast<native_handle_t *>(mBuffer),
-                    grallocUsage,
-                    { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
-                    // TODO: fence
-                    hidl_handle(),
-                    [&err, &pointer](const auto &maperr, const auto &mapPointer) {
-                        err = maperr2error(maperr);
-                        if (err == C2_OK) {
-                            pointer = mapPointer;
-                        }
-                    });
+            if (mMapper2) {
+                if (!mMapper2->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_1010102)");
+                    return C2_CORRUPTED;
+                }
+            } else {
+                if (!mMapper3->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer,
+                                         int32_t bytesPerPixel, int32_t bytesPerStride) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                            (void)bytesPerPixel;
+                            (void)bytesPerStride;
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_1010102) (@3.0)");
+                    return C2_CORRUPTED;
+                }
+            }
             if (err != C2_OK) {
                 ALOGD("lock failed: %d", err);
                 return err;
@@ -445,10 +533,13 @@
             layout->type = C2PlanarLayout::TYPE_YUVA;
             layout->numPlanes = 4;
             layout->rootPlanes = 1;
+            int32_t stride = mMapper2 ?
+                    int32_t(mInfo2.stride) :
+                    int32_t(mInfo3.stride);
             layout->planes[C2PlanarLayout::PLANE_Y] = {
                 C2PlaneInfo::CHANNEL_Y,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -461,7 +552,7 @@
             layout->planes[C2PlanarLayout::PLANE_U] = {
                 C2PlaneInfo::CHANNEL_CB,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -474,7 +565,7 @@
             layout->planes[C2PlanarLayout::PLANE_V] = {
                 C2PlaneInfo::CHANNEL_CR,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -487,7 +578,7 @@
             layout->planes[C2PlanarLayout::PLANE_A] = {
                 C2PlaneInfo::CHANNEL_A,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -500,23 +591,49 @@
             break;
         }
 
-        case PixelFormat::RGBA_8888:
+        case PixelFormat3::RGBA_8888:
             // TODO: alpha channel
             // fall-through
-        case PixelFormat::RGBX_8888: {
+        case PixelFormat3::RGBX_8888: {
             void *pointer = nullptr;
-            mMapper->lock(
-                    const_cast<native_handle_t *>(mBuffer),
-                    grallocUsage,
-                    { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
-                    // TODO: fence
-                    hidl_handle(),
-                    [&err, &pointer](const auto &maperr, const auto &mapPointer) {
-                        err = maperr2error(maperr);
-                        if (err == C2_OK) {
-                            pointer = mapPointer;
-                        }
-                    });
+            if (mMapper2) {
+                if (!mMapper2->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_8888)");
+                    return C2_CORRUPTED;
+                }
+            } else {
+                if (!mMapper3->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer,
+                                         int32_t bytesPerPixel, int32_t bytesPerStride) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                            (void)bytesPerPixel;
+                            (void)bytesPerStride;
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_8888) (@3.0)");
+                    return C2_CORRUPTED;
+                }
+            }
             if (err != C2_OK) {
                 ALOGD("lock failed: %d", err);
                 return err;
@@ -527,10 +644,13 @@
             layout->type = C2PlanarLayout::TYPE_RGB;
             layout->numPlanes = 3;
             layout->rootPlanes = 1;
+            int32_t stride = mMapper2 ?
+                    int32_t(mInfo2.stride) :
+                    int32_t(mInfo3.stride);
             layout->planes[C2PlanarLayout::PLANE_R] = {
                 C2PlaneInfo::CHANNEL_R,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 8,                              // allocatedDepth
@@ -543,7 +663,7 @@
             layout->planes[C2PlanarLayout::PLANE_G] = {
                 C2PlaneInfo::CHANNEL_G,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 8,                              // allocatedDepth
@@ -556,7 +676,7 @@
             layout->planes[C2PlanarLayout::PLANE_B] = {
                 C2PlaneInfo::CHANNEL_B,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 8,                              // allocatedDepth
@@ -569,23 +689,65 @@
             break;
         }
 
-        case PixelFormat::YCBCR_420_888:
+        case PixelFormat3::YCBCR_420_888:
             // fall-through
-        case PixelFormat::YV12:
+        case PixelFormat3::YV12:
             // fall-through
         default: {
+            struct YCbCrLayout {
+                void* y;
+                void* cb;
+                void* cr;
+                uint32_t yStride;
+                uint32_t cStride;
+                uint32_t chromaStep;
+            };
             YCbCrLayout ycbcrLayout;
-            mMapper->lockYCbCr(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage,
-                    { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
-                    // TODO: fence
-                    hidl_handle(),
-                    [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
-                        err = maperr2error(maperr);
-                        if (err == C2_OK) {
-                            ycbcrLayout = mapLayout;
-                        }
-                    });
+            if (mMapper2) {
+                if (!mMapper2->lockYCbCr(
+                        const_cast<native_handle_t *>(mBuffer), grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                ycbcrLayout = YCbCrLayout{
+                                        mapLayout.y,
+                                        mapLayout.cb,
+                                        mapLayout.cr,
+                                        mapLayout.yStride,
+                                        mapLayout.cStride,
+                                        mapLayout.chromaStep};
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lockYCbCr");
+                    return C2_CORRUPTED;
+                }
+            } else {
+                if (!mMapper3->lockYCbCr(
+                        const_cast<native_handle_t *>(mBuffer), grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                ycbcrLayout = YCbCrLayout{
+                                        mapLayout.y,
+                                        mapLayout.cb,
+                                        mapLayout.cr,
+                                        mapLayout.yStride,
+                                        mapLayout.cStride,
+                                        mapLayout.chromaStep};
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lockYCbCr (@3.0)");
+                    return C2_CORRUPTED;
+                }
+            }
             if (err != C2_OK) {
                 ALOGD("lockYCbCr failed: %d", err);
                 return err;
@@ -662,17 +824,37 @@
 
     std::lock_guard<std::mutex> lock(mMappedLock);
     c2_status_t err = C2_OK;
-    mMapper->unlock(
-            const_cast<native_handle_t *>(mBuffer),
-            [&err, &fence](const auto &maperr, const auto &releaseFence) {
-                // TODO
-                (void) fence;
-                (void) releaseFence;
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    // TODO: fence
-                }
-            });
+    if (mMapper2) {
+        if (!mMapper2->unlock(
+                const_cast<native_handle_t *>(mBuffer),
+                [&err, &fence](const auto &maperr, const auto &releaseFence) {
+                    // TODO
+                    (void) fence;
+                    (void) releaseFence;
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        // TODO: fence
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: unlock");
+            return C2_CORRUPTED;
+        }
+    } else {
+        if (!mMapper3->unlock(
+                const_cast<native_handle_t *>(mBuffer),
+                [&err, &fence](const auto &maperr, const auto &releaseFence) {
+                    // TODO
+                    (void) fence;
+                    (void) releaseFence;
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        // TODO: fence
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: unlock (@3.0)");
+            return C2_CORRUPTED;
+        }
+    }
     if (err == C2_OK) {
         mLocked = false;
     }
@@ -713,8 +895,10 @@
 private:
     std::shared_ptr<C2Allocator::Traits> mTraits;
     c2_status_t mInit;
-    sp<IAllocator> mAllocator;
-    sp<IMapper> mMapper;
+    sp<IAllocator2> mAllocator2;
+    sp<IMapper2> mMapper2;
+    sp<IAllocator3> mAllocator3;
+    sp<IMapper3> mMapper3;
     const bool mBufferQueue;
 };
 
@@ -734,10 +918,18 @@
     mTraits = std::make_shared<C2Allocator::Traits>(traits);
 
     // gralloc allocator is a singleton, so all objects share a global service
-    mAllocator = IAllocator::getService();
-    mMapper = IMapper::getService();
-    if (mAllocator == nullptr || mMapper == nullptr) {
-        mInit = C2_CORRUPTED;
+    mAllocator3 = IAllocator3::getService();
+    mMapper3 = IMapper3::getService();
+    if (!mAllocator3 || !mMapper3) {
+        mAllocator3 = nullptr;
+        mMapper3 = nullptr;
+        mAllocator2 = IAllocator2::getService();
+        mMapper2 = IMapper2::getService();
+        if (!mAllocator2 || !mMapper2) {
+            mAllocator2 = nullptr;
+            mMapper2 = nullptr;
+            mInit = C2_CORRUPTED;
+        }
     }
 }
 
@@ -748,84 +940,176 @@
     ALOGV("allocating buffer with usage %#llx => %#llx",
           (long long)usage.expected, (long long)grallocUsage);
 
-    BufferDescriptorInfo info = {
-        {
-            width,
-            height,
-            1u,  // layerCount
-            (PixelFormat)format,
-            grallocUsage,
-        },
-        0u,  // stride placeholder
-    };
     c2_status_t err = C2_OK;
-    BufferDescriptor desc;
-    mMapper->createDescriptor(
-            info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    desc = descriptor;
-                }
-            });
-    if (err != C2_OK) {
-        return err;
+    hidl_handle buffer{};
+
+    if (mMapper2) {
+        BufferDescriptorInfo2 info = {
+            {
+                width,
+                height,
+                1u,  // layerCount
+                PixelFormat2(format),
+                grallocUsage,
+            },
+            0u,  // stride placeholder
+        };
+        BufferDescriptor2 desc;
+        if (!mMapper2->createDescriptor(
+                info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        desc = descriptor;
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: createDescriptor");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+
+        // IAllocator shares IMapper error codes.
+        if (!mAllocator2->allocate(
+                desc,
+                1u,
+                [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
+                    err = maperr2error(maperr);
+                    if (err != C2_OK) {
+                        return;
+                    }
+                    if (buffers.size() != 1u) {
+                        err = C2_CORRUPTED;
+                        return;
+                    }
+                    info.stride = stride;
+                    buffer = buffers[0];
+                }).isOk()) {
+            ALOGE("failed transaction: allocate");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper2, buffer,
+                C2HandleGralloc::WrapAndMoveNativeHandle(
+                        buffer.getNativeHandle(),
+                        width, height,
+                        format, grallocUsage, info.stride,
+                        0, 0, mBufferQueue ? ~0 : 0),
+                mTraits->id));
+        return C2_OK;
+    } else {
+        BufferDescriptorInfo3 info = {
+            {
+                width,
+                height,
+                1u,  // layerCount
+                PixelFormat3(format),
+                grallocUsage,
+            },
+            0u,  // stride placeholder
+        };
+        BufferDescriptor3 desc;
+        if (!mMapper3->createDescriptor(
+                info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        desc = descriptor;
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: createDescriptor");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+
+        // IAllocator shares IMapper error codes.
+        if (!mAllocator3->allocate(
+                desc,
+                1u,
+                [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
+                    err = maperr2error(maperr);
+                    if (err != C2_OK) {
+                        return;
+                    }
+                    if (buffers.size() != 1u) {
+                        err = C2_CORRUPTED;
+                        return;
+                    }
+                    info.stride = stride;
+                    buffer = buffers[0];
+                }).isOk()) {
+            ALOGE("failed transaction: allocate");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper3, buffer,
+                C2HandleGralloc::WrapAndMoveNativeHandle(
+                        buffer.getNativeHandle(),
+                        width, height,
+                        format, grallocUsage, info.stride,
+                        0, 0, mBufferQueue ? ~0 : 0),
+                mTraits->id));
+        return C2_OK;
     }
-
-    // IAllocator shares IMapper error codes.
-    hidl_handle buffer;
-    mAllocator->allocate(
-            desc,
-            1u,
-            [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
-                err = maperr2error(maperr);
-                if (err != C2_OK) {
-                    return;
-                }
-                if (buffers.size() != 1u) {
-                    err = C2_CORRUPTED;
-                    return;
-                }
-                info.stride = stride;
-                buffer = buffers[0];
-            });
-    if (err != C2_OK) {
-        return err;
-    }
-
-
-    allocation->reset(new C2AllocationGralloc(
-            info, mMapper, buffer,
-            C2HandleGralloc::WrapAndMoveNativeHandle(
-                    buffer.getNativeHandle(),
-                    info.mapperInfo.width, info.mapperInfo.height,
-                    (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride,
-                    0, 0, mBufferQueue ? ~0 : 0),
-            mTraits->id));
-    return C2_OK;
 }
 
 c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation(
         const C2Handle *handle,
         std::shared_ptr<C2GraphicAllocation> *allocation) {
-    BufferDescriptorInfo info;
-    info.mapperInfo.layerCount = 1u;
-    uint32_t generation;
-    uint64_t igbp_id;
-    uint32_t igbp_slot;
-    const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
-            handle,
-            &info.mapperInfo.width, &info.mapperInfo.height,
-            (uint32_t *)&info.mapperInfo.format, (uint64_t *)&info.mapperInfo.usage, &info.stride,
-            &generation, &igbp_id, &igbp_slot);
-    if (grallocHandle == nullptr) {
-        return C2_BAD_VALUE;
+    if (mMapper2) {
+        BufferDescriptorInfo2 info;
+        info.mapperInfo.layerCount = 1u;
+        uint32_t generation;
+        uint64_t igbp_id;
+        uint32_t igbp_slot;
+        const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+                handle,
+                &info.mapperInfo.width, &info.mapperInfo.height,
+                (uint32_t *)&info.mapperInfo.format,
+                (uint64_t *)&info.mapperInfo.usage,
+                &info.stride,
+                &generation, &igbp_id, &igbp_slot);
+        if (grallocHandle == nullptr) {
+            return C2_BAD_VALUE;
+        }
+
+        hidl_handle hidlHandle;
+        hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper2, hidlHandle, grallocHandle, mTraits->id));
+        return C2_OK;
+    } else {
+        BufferDescriptorInfo3 info;
+        info.mapperInfo.layerCount = 1u;
+        uint32_t generation;
+        uint64_t igbp_id;
+        uint32_t igbp_slot;
+        const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+                handle,
+                &info.mapperInfo.width, &info.mapperInfo.height,
+                (uint32_t *)&info.mapperInfo.format,
+                (uint64_t *)&info.mapperInfo.usage,
+                &info.stride,
+                &generation, &igbp_id, &igbp_slot);
+        if (grallocHandle == nullptr) {
+            return C2_BAD_VALUE;
+        }
+
+        hidl_handle hidlHandle;
+        hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper3, hidlHandle, grallocHandle, mTraits->id));
+        return C2_OK;
     }
-
-    hidl_handle hidlHandle;
-    hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
-
-    allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id));
-    return C2_OK;
 }
 
 C2AllocatorGralloc::C2AllocatorGralloc(id_t id, bool bufferQueue)
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 5fa48a8..8304f74 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -413,6 +413,7 @@
         }
 
         sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
+        uint32_t outGeneration;
         if (bufferNeedsReallocation || !slotBuffer) {
             if (!slotBuffer) {
                 slotBuffer = new GraphicBuffer();
@@ -421,7 +422,7 @@
             // instead of a new allocation.
             Return<void> transResult = mProducer->requestBuffer(
                     slot,
-                    [&status, &slotBuffer](
+                    [&status, &slotBuffer, &outGeneration](
                             HStatus hStatus,
                             HBuffer const& hBuffer,
                             uint32_t generationNumber){
@@ -429,17 +430,23 @@
                                 h2b(hBuffer, &slotBuffer) &&
                                 slotBuffer) {
                             slotBuffer->setGenerationNumber(generationNumber);
+                            outGeneration = generationNumber;
                         } else {
                             status = android::BAD_VALUE;
                         }
                     });
             if (!transResult.isOk()) {
+                slotBuffer.clear();
                 return C2_BAD_VALUE;
             } else if (status != android::NO_ERROR) {
                 slotBuffer.clear();
                 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
                 return C2_BAD_VALUE;
             }
+            if (mGeneration == 0) {
+                // getting generation # lazily due to dequeue failure.
+                mGeneration = outGeneration;
+            }
         }
         if (slotBuffer) {
             ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
@@ -563,6 +570,10 @@
             producerId = static_cast<uint64_t>(transResult);
             // TODO: provide gneration number from parameter.
             haveGeneration = getGenerationNumber(producer, &generation);
+            if (!haveGeneration) {
+                ALOGW("get generationNumber failed %llu",
+                      (unsigned long long)producerId);
+            }
         }
         int migrated = 0;
         {
@@ -580,10 +591,10 @@
                 }
             }
             int32_t oldGeneration = mGeneration;
-            if (producer && haveGeneration) {
+            if (producer) {
                 mProducer = producer;
                 mProducerId = producerId;
-                mGeneration = generation;
+                mGeneration = haveGeneration ? generation : 0;
             } else {
                 mProducer = nullptr;
                 mProducerId = 0;
@@ -591,7 +602,7 @@
                 ALOGW("invalid producer producer(%d), generation(%d)",
                       (bool)producer, haveGeneration);
             }
-            if (mProducer) { // migrate buffers
+            if (mProducer && haveGeneration) { // migrate buffers
                 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
                     std::shared_ptr<C2BufferQueueBlockPoolData> data =
                             mPoolDatas[i].lock();
diff --git a/media/libmedia/xsd/vts/Android.bp b/media/libmedia/xsd/vts/Android.bp
index b590a12..4739504 100644
--- a/media/libmedia/xsd/vts/Android.bp
+++ b/media/libmedia/xsd/vts/Android.bp
@@ -24,6 +24,7 @@
         "libxml2",
     ],
     shared_libs: [
+        "libbase",
         "liblog",
     ],
     cflags: [
diff --git a/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp b/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp
index ff9b060..7729d52 100644
--- a/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp
+++ b/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
 #include "utility/ValidateXml.h"
 
 TEST(CheckConfig, mediaProfilesValidation) {
@@ -21,8 +25,12 @@
                    "Verify that the media profiles file "
                    "is valid according to the schema");
 
-    const char* location = "/vendor/etc";
+    std::string mediaSettingsPath = android::base::GetProperty("media.settings.xml", "");
+    if (mediaSettingsPath.empty()) {
+        mediaSettingsPath.assign("/vendor/etc/media_profiles_V1_0.xml");
+    }
 
-    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("media_profiles_V1_0.xml", {location},
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(android::base::Basename(mediaSettingsPath).c_str(),
+                                            {android::base::Dirname(mediaSettingsPath).c_str()},
                                             "/data/local/tmp/media_profiles.xsd");
 }
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 2cd920a..4653711 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1578,7 +1578,7 @@
         }
 
         if (mPreparing) {
-            notifyPreparedAndCleanup(finalStatus);
+            notifyPreparedAndCleanup(finalStatus == ERROR_END_OF_STREAM ? OK : finalStatus);
             mPreparing = false;
         } else if (mSentPauseOnBuffering) {
             sendCacheStats();
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/packet_util.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/packet_util.cpp
index 48414d7..5880e32 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/packet_util.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/packet_util.cpp
@@ -52,7 +52,11 @@
         PV_BitstreamByteAlign(stream);
         BitstreamReadBits32(stream, resync_marker_length);
 
-        *next_MB = (int) BitstreamReadBits16(stream, nbits);
+        int mbnum = (int) BitstreamReadBits16(stream, nbits);
+        if (mbnum < 0) {
+            return PV_FAIL;
+        }
+        *next_MB = mbnum;
 //      if (*next_MB <= video->mbnum)   /*  needs more investigation */
 //          *next_MB = video->mbnum+1;
 
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
index f18f789..679b091 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
@@ -1355,6 +1355,14 @@
             int tmpHeight = (tmpDisplayHeight + 15) & -16;
             int tmpWidth = (tmpDisplayWidth + 15) & -16;
 
+            if (tmpWidth > video->width)
+            {
+                // while allowed by the spec, this decoder does not actually
+                // support an increase in size.
+                ALOGE("width increase not supported");
+                status = PV_FAIL;
+                goto return_point;
+            }
             if (tmpHeight * tmpWidth > video->size)
             {
                 // This is just possibly "b/37079296".
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index e260cae..7d03d98 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -72,7 +72,6 @@
         cfi: true,
     },
 
-    compile_multilib: "32",
 }
 
 cc_library_shared {
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index 9d7c57d..16c8af8 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -138,7 +138,12 @@
 
   public class Variant {
     ctor public Variant();
+    method public java.util.List<media.codecs.Alias> getAlias_optional();
+    method public java.util.List<media.codecs.Quirk> getAttribute_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_optional();
     method public void setName(String);
   }
 
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 63ec5d0..3b5681f 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -107,6 +107,13 @@
         <xs:attribute name="value" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Variant">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Quirk" type="Quirk"/>
+            <xs:element name="Attribute" type="Quirk"/>
+            <xs:element name="Alias" type="Alias"/>
+            <xs:element name="Limit" type="Limit"/>
+            <xs:element name="Feature" type="Feature"/>
+        </xs:choice>
         <xs:attribute name="name" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Setting">
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a6730fc..1d4dacd 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2396,7 +2396,8 @@
     for (size_t i = 0; i < mInputs.size(); i++) {
         const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
         if (input->clientsList().size() == 0
-                || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) {
+                || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())
+                || (input->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             inputsToClose.push_back(mInputs.keyAt(i));
         } else {
             bool close = false;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 9525ad2..8ebaa2b 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -58,8 +58,8 @@
 
         entry = staticInfo.find(ANDROID_LENS_INTRINSIC_CALIBRATION);
         if (entry.count == 5) {
-            mInstrinsicCalibration.reserve(5);
-            mInstrinsicCalibration.insert(mInstrinsicCalibration.end(), entry.data.f,
+            mIntrinsicCalibration.reserve(5);
+            mIntrinsicCalibration.insert(mIntrinsicCalibration.end(), entry.data.f,
                     entry.data.f + 5);
         } else {
             ALOGW("%s: Intrinsic calibration absent from camera characteristics!", __FUNCTION__);
@@ -323,12 +323,12 @@
     depthPhoto.mMaxJpegSize = maxDepthJpegSize;
     // The camera intrinsic calibration layout is as follows:
     // [focalLengthX, focalLengthY, opticalCenterX, opticalCenterY, skew]
-    if (mInstrinsicCalibration.size() == 5) {
-        memcpy(depthPhoto.mInstrinsicCalibration, mInstrinsicCalibration.data(),
-                sizeof(depthPhoto.mInstrinsicCalibration));
-        depthPhoto.mIsInstrinsicCalibrationValid = 1;
+    if (mIntrinsicCalibration.size() == 5) {
+        memcpy(depthPhoto.mIntrinsicCalibration, mIntrinsicCalibration.data(),
+                sizeof(depthPhoto.mIntrinsicCalibration));
+        depthPhoto.mIsIntrinsicCalibrationValid = 1;
     } else {
-        depthPhoto.mIsInstrinsicCalibrationValid = 0;
+        depthPhoto.mIsIntrinsicCalibrationValid = 0;
     }
     // The camera lens distortion contains the following lens correction coefficients.
     // [kappa_1, kappa_2, kappa_3 kappa_4, kappa_5]
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 1bf31f4..975c59b 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -124,7 +124,7 @@
 
     ssize_t              mMaxJpegSize;
     std::vector<std::tuple<size_t, size_t>> mSupportedDepthSizes;
-    std::vector<float>   mInstrinsicCalibration, mLensDistortion;
+    std::vector<float>   mIntrinsicCalibration, mLensDistortion;
     bool                 mIsLogicalCamera;
     void*                mDepthPhotoLibHandle;
     process_depth_photo_frame mDepthPhotoProcess;
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
index fc79150..3c90de0 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
@@ -61,6 +61,13 @@
 using dynamic_depth::Profile;
 using dynamic_depth::Profiles;
 
+template<>
+struct std::default_delete<jpeg_compress_struct> {
+    inline void operator()(jpeg_compress_struct* cinfo) const {
+        jpeg_destroy_compress(cinfo);
+    }
+};
+
 namespace android {
 namespace camera3 {
 
@@ -118,16 +125,16 @@
         bool mSuccess;
     } dmgr;
 
-    jpeg_compress_struct cinfo = {};
+    std::unique_ptr<jpeg_compress_struct> cinfo = std::make_unique<jpeg_compress_struct>();
     jpeg_error_mgr jerr;
 
     // Initialize error handling with standard callbacks, but
     // then override output_message (to print to ALOG) and
     // error_exit to set a flag and print a message instead
     // of killing the whole process.
-    cinfo.err = jpeg_std_error(&jerr);
+    cinfo->err = jpeg_std_error(&jerr);
 
-    cinfo.err->output_message = [](j_common_ptr cinfo) {
+    cinfo->err->output_message = [](j_common_ptr cinfo) {
         char buffer[JMSG_LENGTH_MAX];
 
         /* Create the message */
@@ -135,7 +142,7 @@
         ALOGE("libjpeg error: %s", buffer);
     };
 
-    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+    cinfo->err->error_exit = [](j_common_ptr cinfo) {
         (*cinfo->err->output_message)(cinfo);
         if(cinfo->client_data) {
             auto & dmgr = *static_cast<CustomJpegDestMgr*>(cinfo->client_data);
@@ -144,12 +151,12 @@
     };
 
     // Now that we initialized some callbacks, let's create our compressor
-    jpeg_create_compress(&cinfo);
+    jpeg_create_compress(cinfo.get());
     dmgr.mBuffer = static_cast<JOCTET*>(out);
     dmgr.mBufferSize = maxOutSize;
     dmgr.mEncodedSize = 0;
     dmgr.mSuccess = true;
-    cinfo.client_data = static_cast<void*>(&dmgr);
+    cinfo->client_data = static_cast<void*>(&dmgr);
 
     // These lambdas become C-style function pointers and as per C++11 spec
     // may not capture anything.
@@ -171,28 +178,28 @@
         dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.free_in_buffer;
         ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
     };
-    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-    cinfo.image_width = width;
-    cinfo.image_height = height;
-    cinfo.input_components = 1;
-    cinfo.in_color_space = JCS_GRAYSCALE;
+    cinfo->dest = static_cast<struct jpeg_destination_mgr*>(&dmgr);
+    cinfo->image_width = width;
+    cinfo->image_height = height;
+    cinfo->input_components = 1;
+    cinfo->in_color_space = JCS_GRAYSCALE;
 
     // Initialize defaults and then override what we want
-    jpeg_set_defaults(&cinfo);
+    jpeg_set_defaults(cinfo.get());
 
-    jpeg_set_quality(&cinfo, jpegQuality, 1);
-    jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
-    cinfo.raw_data_in = 0;
-    cinfo.dct_method = JDCT_IFAST;
+    jpeg_set_quality(cinfo.get(), jpegQuality, 1);
+    jpeg_set_colorspace(cinfo.get(), JCS_GRAYSCALE);
+    cinfo->raw_data_in = 0;
+    cinfo->dct_method = JDCT_IFAST;
 
-    cinfo.comp_info[0].h_samp_factor = 1;
-    cinfo.comp_info[1].h_samp_factor = 1;
-    cinfo.comp_info[2].h_samp_factor = 1;
-    cinfo.comp_info[0].v_samp_factor = 1;
-    cinfo.comp_info[1].v_samp_factor = 1;
-    cinfo.comp_info[2].v_samp_factor = 1;
+    cinfo->comp_info[0].h_samp_factor = 1;
+    cinfo->comp_info[1].h_samp_factor = 1;
+    cinfo->comp_info[2].h_samp_factor = 1;
+    cinfo->comp_info[0].v_samp_factor = 1;
+    cinfo->comp_info[1].v_samp_factor = 1;
+    cinfo->comp_info[2].v_samp_factor = 1;
 
-    jpeg_start_compress(&cinfo, TRUE);
+    jpeg_start_compress(cinfo.get(), TRUE);
 
     if (exifOrientation != ExifOrientation::ORIENTATION_UNDEFINED) {
         std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -204,19 +211,19 @@
         if (utils->generateApp1()) {
             const uint8_t* exifBuffer = utils->getApp1Buffer();
             size_t exifBufferSize = utils->getApp1Length();
-            jpeg_write_marker(&cinfo, JPEG_APP0 + 1, static_cast<const JOCTET*>(exifBuffer),
+            jpeg_write_marker(cinfo.get(), JPEG_APP0 + 1, static_cast<const JOCTET*>(exifBuffer),
                     exifBufferSize);
         } else {
             ALOGE("%s: Unable to generate App1 buffer", __FUNCTION__);
         }
     }
 
-    for (size_t i = 0; i < cinfo.image_height; i++) {
+    for (size_t i = 0; i < cinfo->image_height; i++) {
         auto currentRow  = static_cast<JSAMPROW>(in + i*width);
-        jpeg_write_scanlines(&cinfo, &currentRow, /*num_lines*/1);
+        jpeg_write_scanlines(cinfo.get(), &currentRow, /*num_lines*/1);
     }
 
-    jpeg_finish_compress(&cinfo);
+    jpeg_finish_compress(cinfo.get());
 
     actualSize = dmgr.mEncodedSize;
     if (dmgr.mSuccess) {
@@ -430,12 +437,12 @@
         return BAD_VALUE;
     }
 
-    // It is not possible to generate an imaging model without instrinsic calibration.
-    if (inputFrame.mIsInstrinsicCalibrationValid) {
+    // It is not possible to generate an imaging model without intrinsic calibration.
+    if (inputFrame.mIsIntrinsicCalibrationValid) {
         // The camera intrinsic calibration layout is as follows:
         // [focalLengthX, focalLengthY, opticalCenterX, opticalCenterY, skew]
-        const dynamic_depth::Point<double> focalLength(inputFrame.mInstrinsicCalibration[0],
-                inputFrame.mInstrinsicCalibration[1]);
+        const dynamic_depth::Point<double> focalLength(inputFrame.mIntrinsicCalibration[0],
+                inputFrame.mIntrinsicCalibration[1]);
         size_t width = inputFrame.mMainJpegWidth;
         size_t height = inputFrame.mMainJpegHeight;
         if (switchDimensions) {
@@ -444,9 +451,9 @@
         }
         const Dimension imageSize(width, height);
         ImagingModelParams imagingParams(focalLength, imageSize);
-        imagingParams.principal_point.x = inputFrame.mInstrinsicCalibration[2];
-        imagingParams.principal_point.y = inputFrame.mInstrinsicCalibration[3];
-        imagingParams.skew = inputFrame.mInstrinsicCalibration[4];
+        imagingParams.principal_point.x = inputFrame.mIntrinsicCalibration[2];
+        imagingParams.principal_point.y = inputFrame.mIntrinsicCalibration[3];
+        imagingParams.skew = inputFrame.mIntrinsicCalibration[4];
 
         // The camera lens distortion contains the following lens correction coefficients.
         // [kappa_1, kappa_2, kappa_3 kappa_4, kappa_5]
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.h b/services/camera/libcameraservice/common/DepthPhotoProcessor.h
index 6a2fbff..ba5ca9e 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.h
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.h
@@ -39,8 +39,8 @@
     size_t                mMaxJpegSize;
     uint8_t               mJpegQuality;
     uint8_t               mIsLogical;
-    float                 mInstrinsicCalibration[5];
-    uint8_t               mIsInstrinsicCalibrationValid;
+    float                 mIntrinsicCalibration[5];
+    uint8_t               mIsIntrinsicCalibrationValid;
     float                 mLensDistortion[5];
     uint8_t               mIsLensDistortionValid;
     DepthPhotoOrientation mOrientation;
@@ -57,8 +57,8 @@
             mMaxJpegSize(0),
             mJpegQuality(100),
             mIsLogical(0),
-            mInstrinsicCalibration{0.f},
-            mIsInstrinsicCalibrationValid(0),
+            mIntrinsicCalibration{0.f},
+            mIsIntrinsicCalibrationValid(0),
             mLensDistortion{0.f},
             mIsLensDistortionValid(0),
             mOrientation(DepthPhotoOrientation::DEPTH_ORIENTATION_0_DEGREES) {}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9771f9e..a8e80fa 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4364,7 +4364,7 @@
         int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
         android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
 
-        if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+        if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
             dstStream->setFormatOverride(false);
             dstStream->setDataSpaceOverride(false);
             if (dst->format != overrideFormat) {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 2df084b..fd9b4b0 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -68,7 +68,7 @@
     mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX),
     mBufferLimitLatency(kBufferLimitLatencyBinSize),
     mFormatOverridden(false),
-    mOriginalFormat(-1),
+    mOriginalFormat(format),
     mDataSpaceOverridden(false),
     mOriginalDataSpace(HAL_DATASPACE_UNKNOWN),
     mPhysicalCameraId(physicalCameraId),
@@ -125,9 +125,6 @@
 
 void Camera3Stream::setFormatOverride(bool formatOverridden) {
     mFormatOverridden = formatOverridden;
-    if (formatOverridden && mOriginalFormat == -1) {
-        mOriginalFormat = camera3_stream::format;
-    }
 }
 
 bool Camera3Stream::isFormatOverridden() const {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 533318f..67afd0f 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -582,9 +582,9 @@
     static const int32_t kBufferLimitLatencyBinSize = 33; //in ms
     CameraLatencyHistogram mBufferLimitLatency;
 
-    //Keep track of original format in case it gets overridden
+    //Keep track of original format when the stream is created in case it gets overridden
     bool mFormatOverridden;
-    int mOriginalFormat;
+    const int mOriginalFormat;
 
     //Keep track of original dataSpace in case it gets overridden
     bool mDataSpaceOverridden;