Add FMQ support to camera2 SDK for metadata transfer

This CL adds support for CaptureResult metadata to be transferred over
FMQ instead of binder copies.

Bug: 362791857

Flag: com.android.internal.camera.flags.fmq_metadata

Test: GCA
Test: Perfetto profiling shows decreased cameraserver to client
      onResultReceived latency

Change-Id: Ia8df1a4cef5008c06dc2ca4fdd319704d5e049ab
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/camera/Android.bp b/camera/Android.bp
index 25b5e2c..71c1673 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -82,6 +82,8 @@
         include_dirs: [
             "frameworks/native/aidl/gui",
             "frameworks/native/libs/permission/aidl",
+            "hardware/interfaces/common/fmq/aidl",
+            "hardware/interfaces/common/aidl",
         ],
     },
 
@@ -112,6 +114,8 @@
     ],
 
     shared_libs: [
+        "android.hardware.common.fmq-V1-cpp",
+        "android.hardware.common-V2-cpp",
         "camera_platform_flags_c_lib",
         "framework-permission-aidl-cpp",
         "lib-platform-compat-native-api",
@@ -136,6 +140,8 @@
     ],
     export_shared_lib_headers: [
         "framework-permission-aidl-cpp",
+        "android.hardware.common.fmq-V1-cpp",
+        "android.hardware.common-V2-cpp",
         "libcamera_metadata",
         "libgui",
         "libnativewindow",
@@ -187,6 +193,7 @@
         "aidl/android/hardware/camera2/ICameraInjectionCallback.aidl",
         "aidl/android/hardware/camera2/ICameraInjectionSession.aidl",
         "aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
+        "aidl/android/hardware/camera2/CameraMetadataInfo.aidl",
     ],
     path: "aidl",
 }
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 9ff2578..254984f 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -98,7 +98,6 @@
     status_t res;
 
     mPhysicalCameraId = "";
-    mPhysicalCameraMetadata.clear();
 
     String16 physicalCameraId;
     if ((res = parcel->readString16(&physicalCameraId)) != OK) {
@@ -107,10 +106,11 @@
     }
     mPhysicalCameraId = toStdString(physicalCameraId);
 
-    if ((res = mPhysicalCameraMetadata.readFromParcel(parcel)) != OK) {
+    if ((res = mCameraMetadataInfo.readFromParcel(parcel)) != OK) {
         ALOGE("%s: Failed to read metadata from parcel: %d", __FUNCTION__, res);
         return res;
     }
+
     return OK;
 }
 
@@ -121,11 +121,13 @@
                 __FUNCTION__, res);
         return res;
     }
-    if ((res = mPhysicalCameraMetadata.writeToParcel(parcel)) != OK) {
+
+    if ((res = mCameraMetadataInfo.writeToParcel(parcel)) != OK) {
         ALOGE("%s: Failed to write physical camera metadata to parcel: %d",
                 __FUNCTION__, res);
         return res;
     }
+
     return OK;
 }
 
@@ -178,20 +180,12 @@
     }
 
     for (int32_t i = 0; i < physicalMetadataCount; i++) {
-        String16 cameraId;
-        if ((res = parcel->readString16(&cameraId)) != OK) {
-            ALOGE("%s: Failed to read camera id: %d", __FUNCTION__, res);
+        PhysicalCaptureResultInfo result;
+        if ((res = result.readFromParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to read physical result from parcel: %d", __FUNCTION__, res);
             return res;
         }
-
-        CameraMetadata physicalMetadata;
-        if ((res = physicalMetadata.readFromParcel(parcel)) != OK) {
-            ALOGE("%s: Failed to read metadata from parcel: %d", __FUNCTION__, res);
-            return res;
-        }
-
-        mPhysicalMetadatas.emplace(mPhysicalMetadatas.end(), toStdString(cameraId),
-                physicalMetadata);
+        mPhysicalMetadatas.emplace(mPhysicalMetadatas.end(), result);
     }
     ALOGV("%s: Read physical metadata from parcel", __FUNCTION__);
 
@@ -232,13 +226,8 @@
         return BAD_VALUE;
     }
     for (const auto& physicalMetadata : mPhysicalMetadatas) {
-        if ((res = parcel->writeString16(toString16(physicalMetadata.mPhysicalCameraId))) != OK) {
-            ALOGE("%s: Failed to write physical camera ID to parcel: %d",
-                    __FUNCTION__, res);
-            return res;
-        }
-        if ((res = physicalMetadata.mPhysicalCameraMetadata.writeToParcel(parcel)) != OK) {
-            ALOGE("%s: Failed to write physical camera metadata to parcel: %d",
+        if ((res = physicalMetadata.writeToParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to write physicalMetadata to parcel: %d",
                     __FUNCTION__, res);
             return res;
         }
diff --git a/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl b/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl
new file mode 100644
index 0000000..74c207e
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+package android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+union CameraMetadataInfo {
+    long fmqSize;
+    CameraMetadataNative metadata;
+}
\ No newline at end of file
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 49e9920..68e6354 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.hardware.camera2.CameraMetadataInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
@@ -36,7 +37,7 @@
     oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
     oneway void onDeviceIdle();
     oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
-    oneway void onResultReceived(in CameraMetadataNative result,
+    oneway void onResultReceived(in CameraMetadataInfo resultInfo,
                                  in CaptureResultExtras resultExtras,
                                  in PhysicalCaptureResultInfo[] physicalCaptureResultInfos);
     oneway void onPrepared(int streamId);
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index c1da126..a9191eb 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -23,6 +23,8 @@
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.utils.SubmitInfo;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
 import android.view.Surface;
 
 /** @hide */
@@ -173,6 +175,7 @@
 
     void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
 
+    MQDescriptor<byte, SynchronizedReadWrite> getCaptureResultMetadataQueue();
 
     // Keep in sync with public API in
     // frameworks/base/core/java/android/hardware/camera2/CameraDevice.java
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 3b199b3..5682ad2 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -263,3 +263,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    namespace: "camera_platform"
+    name: "fmq_metadata"
+    description: "Allow CameraMetadata transfer for ndk / sdk clients."
+    bug: "362791857"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
\ No newline at end of file
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index 2903dfb..10ecc4f 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -247,6 +247,38 @@
      */
     metadata_vendor_id_t getVendorId() const;
 
+   // Needed for auto-generated code if CameraMetadata is used in
+   // parcelables in .aidl files.
+   inline bool operator == (const CameraMetadata& rhs) const {
+        return mBuffer == rhs.mBuffer;
+    }
+
+    inline bool operator < (const CameraMetadata& rhs) const {
+        return mBuffer < rhs.mBuffer;
+    }
+
+    inline bool operator != (const CameraMetadata& rhs) const {
+        return !(*this == rhs);
+    }
+
+    inline bool operator > (const CameraMetadata& rhs) const {
+        return rhs < *this;
+    }
+
+    inline bool operator >= (const CameraMetadata& rhs) const {
+        return !(*this < rhs);
+    }
+
+    inline bool operator <= (const CameraMetadata& rhs) const {
+        return !(rhs < *this);
+    }
+
+  inline std::string toString() const {
+        std::string descStr = "CameraMetadata";
+        return descStr;
+  }
+
+
   private:
     camera_metadata_t *mBuffer;
     mutable bool       mLocked;
@@ -265,7 +297,6 @@
      * Resize metadata buffer if needed by reallocating it and copying it over.
      */
     status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
-
 };
 
 namespace hardware {
diff --git a/camera/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
index e08c9ca..cc6b529 100644
--- a/camera/include/camera/CaptureResult.h
+++ b/camera/include/camera/CaptureResult.h
@@ -20,7 +20,7 @@
 #include <utils/RefBase.h>
 #include <binder/Parcelable.h>
 #include <camera/CameraMetadata.h>
-
+#include <android/hardware/camera2/CameraMetadataInfo.h>
 
 namespace android {
 
@@ -145,19 +145,26 @@
 };
 
 struct PhysicalCaptureResultInfo : public android::Parcelable {
-
+    using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
     PhysicalCaptureResultInfo()
         : mPhysicalCameraId(),
-          mPhysicalCameraMetadata() {
+          mCameraMetadataInfo() {
     }
     PhysicalCaptureResultInfo(const std::string& cameraId,
             const CameraMetadata& cameraMetadata)
-            : mPhysicalCameraId(cameraId),
-              mPhysicalCameraMetadata(cameraMetadata) {
+            : mPhysicalCameraId(cameraId) {
+              mCameraMetadataInfo.set<CameraMetadataInfo::metadata>(cameraMetadata);
+    }
+
+   PhysicalCaptureResultInfo(const std::string& cameraId,
+            uint64_t fmqSize)
+            : mPhysicalCameraId(cameraId) {
+              mCameraMetadataInfo.set<CameraMetadataInfo::fmqSize>(fmqSize);
     }
 
     std::string mPhysicalCameraId;
-    CameraMetadata mPhysicalCameraMetadata;
+
+    CameraMetadataInfo mCameraMetadataInfo;
 
     virtual status_t                readFromParcel(const android::Parcel* parcel) override;
     virtual status_t                writeToParcel(android::Parcel* parcel) const override;
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 508808f..fc1e547 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -79,6 +79,8 @@
     shared_libs: [
         "android.companion.virtual.virtualdevice_aidl-cpp",
         "android.companion.virtualdevice.flags-aconfig-cc",
+        "android.hardware.common-V2-cpp",
+        "android.hardware.common.fmq-V1-cpp",
         "camera_platform_flags_c_lib",
         "framework-permission-aidl-cpp",
         "libandroid_runtime",
@@ -86,6 +88,7 @@
         "libcamera_client",
         "libcamera_metadata",
         "libcutils",
+        "libfmq",
         "libgui",
         "liblog",
         "libmediandk",
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index aed740f..7840fa0 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -37,6 +37,8 @@
 namespace android {
 namespace acam {
 
+using android::hardware::common::fmq::MQDescriptor;
+
 // Static member definitions
 const char* CameraDevice::kContextKey        = "Context";
 const char* CameraDevice::kDeviceKey         = "Device";
@@ -788,6 +790,27 @@
     mRemote = remote;
 }
 
+bool CameraDevice::setDeviceMetadataQueues() {
+    if (mRemote == nullptr) {
+        ALOGE("mRemote must not be null while trying to fetch metadata queues");
+        return false;
+    }
+    MQDescriptor<int8_t, SynchronizedReadWrite> resMqDescriptor;
+    binder::Status ret = mRemote->getCaptureResultMetadataQueue(&resMqDescriptor);
+    if (!ret.isOk()) {
+        ALOGE("Transaction error trying to get capture result metadata queue");
+        return false;
+    }
+    mCaptureResultMetadataQueue = std::make_unique<ResultMetadataQueue>(resMqDescriptor);
+    if (!mCaptureResultMetadataQueue->isValid()) {
+        ALOGE("Empty fmq from cameraserver");
+        mCaptureResultMetadataQueue = nullptr;
+        return false;
+    }
+
+    return true;
+}
+
 camera_status_t
 CameraDevice::checkCameraClosedOrErrorLocked() const {
     if (mRemote == nullptr) {
@@ -1247,7 +1270,9 @@
                         String8 physicalId8 = toString8(physicalResultInfo[i].mPhysicalCameraId);
                         physicalCameraIds.push_back(physicalId8.c_str());
 
-                        CameraMetadata clone = physicalResultInfo[i].mPhysicalCameraMetadata;
+                        CameraMetadata clone =
+                                physicalResultInfo[i].
+                                        mCameraMetadataInfo.get<CameraMetadataInfo::metadata>();
                         clone.update(ANDROID_SYNC_FRAME_NUMBER,
                                 &physicalResult->mFrameNumber, /*data_count*/1);
                         sp<ACameraMetadata> metadata =
@@ -1777,7 +1802,7 @@
 
 binder::Status
 CameraDevice::ServiceCallback::onResultReceived(
-        const CameraMetadata& metadata,
+        const CameraMetadataInfo &resultMetadata,
         const CaptureResultExtras& resultExtras,
         const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
     binder::Status ret = binder::Status::ok();
@@ -1786,11 +1811,11 @@
     if (dev == nullptr) {
         return ret; // device has been closed
     }
+
     int sequenceId = resultExtras.requestId;
     int64_t frameNumber = resultExtras.frameNumber;
     int32_t burstId = resultExtras.burstId;
     bool    isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
-
     if (!isPartialResult) {
         ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
     }
@@ -1808,7 +1833,13 @@
         return ret;
     }
 
-    CameraMetadata metadataCopy = metadata;
+    CameraMetadata metadataCopy;
+    camera_status_t status = readOneResultMetadata(resultMetadata,
+            dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
+    if (status != ACAMERA_OK) {
+        ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
+        return ret;
+    }
     metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
     metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
 
@@ -1824,8 +1855,24 @@
         sp<CaptureRequest> request = cbh.mRequests[burstId];
         sp<ACameraMetadata> result(new ACameraMetadata(
                 metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+        std::vector<PhysicalCaptureResultInfo> localPhysicalResult;
+        localPhysicalResult.resize(physicalResultInfos.size());
+        for (size_t i = 0; i < physicalResultInfos.size(); i++) {
+            CameraMetadata physicalMetadata;
+            localPhysicalResult[i].mPhysicalCameraId = physicalResultInfos[i].mPhysicalCameraId;
+            status = readOneResultMetadata(physicalResultInfos[i].mCameraMetadataInfo,
+                    dev->mCaptureResultMetadataQueue.get(),
+                    &physicalMetadata);
+            if (status != ACAMERA_OK) {
+                ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
+                return ret;
+            }
+            localPhysicalResult[i].mCameraMetadataInfo.set<CameraMetadataInfo::metadata>(
+                    std::move(physicalMetadata));
+        }
         sp<ACameraPhysicalCaptureResultInfo> physicalResult(
-                new ACameraPhysicalCaptureResultInfo(physicalResultInfos, frameNumber));
+                new ACameraPhysicalCaptureResultInfo(localPhysicalResult, frameNumber));
 
         sp<AMessage> msg = new AMessage(
                 cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
@@ -1946,5 +1993,28 @@
     }
 }
 
+camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
+        const CameraMetadataInfo& resultInfo, ResultMetadataQueue* metadataQueue,
+        CameraMetadata* metadata) {
+    if (metadataQueue == nullptr || metadata == nullptr) {
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (resultInfo.getTag() == CameraMetadataInfo::fmqSize) {
+        int64_t metadataSize = resultInfo.get<CameraMetadataInfo::fmqSize>();
+        auto metadataVec = std::make_unique<int8_t []>(metadataSize);
+        bool read = metadataQueue->read(reinterpret_cast<int8_t*>(metadataVec.get()), metadataSize);
+        if (!read) {
+            ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+        *metadata = CameraMetadata(reinterpret_cast<camera_metadata_t *>(metadataVec.release()));
+    } else {
+        *metadata =
+                resultInfo.get<CameraMetadataInfo::metadata>();
+    }
+
+    return ACAMERA_OK;
+}
+
 } // namespace acam
 } // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index d3aed4b..ff68bb9 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -37,6 +37,7 @@
 #include <camera/camera2/OutputConfiguration.h>
 #include <camera/camera2/SessionConfiguration.h>
 #include <camera/camera2/CaptureRequest.h>
+#include <fmq/AidlMessageQueueCpp.h>
 
 #include <camera/NdkCameraManager.h>
 #include <camera/NdkCameraCaptureSession.h>
@@ -46,6 +47,9 @@
 namespace android {
 namespace acam {
 
+using android::hardware::common::fmq::SynchronizedReadWrite;
+using ResultMetadataQueue = AidlMessageQueueCpp<int8_t, SynchronizedReadWrite>;
+
 // Wrap ACameraCaptureFailure so it can be ref-counted
 struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
 
@@ -61,6 +65,8 @@
 
 class CameraDevice final : public RefBase {
   public:
+
+    using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
     CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
                   sp<ACameraMetadata> chars,
                   ACameraDevice* wrapper, bool sharedMode);
@@ -91,7 +97,7 @@
         binder::Status onDeviceIdle() override;
         binder::Status onCaptureStarted(const CaptureResultExtras& resultExtras,
                               int64_t timestamp) override;
-        binder::Status onResultReceived(const CameraMetadata& metadata,
+        binder::Status onResultReceived(const CameraMetadataInfo &resultInfo,
                               const CaptureResultExtras& resultExtras,
                               const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) override;
         binder::Status onPrepared(int streamId) override;
@@ -100,6 +106,9 @@
                 int32_t stoppedSequenceId) override;
         binder::Status onClientSharedAccessPriorityChanged(bool isPrimaryClient) override;
       private:
+        camera_status_t readOneResultMetadata(
+                const CameraMetadataInfo& resultInfo, ResultMetadataQueue* metadataQueue,
+                CameraMetadata* metadata);
         const wp<CameraDevice> mDevice;
     };
     inline sp<hardware::camera2::ICameraDeviceCallbacks> getServiceCallback() {
@@ -108,6 +117,7 @@
 
     // Camera device is only functional after remote being set
     void setRemoteDevice(sp<hardware::camera2::ICameraDeviceUser> remote);
+    bool setDeviceMetadataQueues();
 
     inline ACameraDevice* getWrapper() const { return mWrapper; };
 
@@ -399,6 +409,9 @@
     int32_t mPartialResultCount;  // const after constructor
     std::vector<std::string> mPhysicalIds; // const after constructor
 
+    // Metadata queue to write the result metadata to.
+    std::unique_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue;
+
 };
 
 } // namespace acam;
@@ -452,6 +465,10 @@
         mDevice->setRemoteDevice(remote);
     }
 
+    inline bool setDeviceMetadataQueues() {
+        return mDevice->setDeviceMetadataQueues();
+    }
+
     inline void setPrimaryClient(bool isPrimary) {
         mDevice->setPrimaryClient(isPrimary);
     }
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f9c1a8a..acd7917 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -971,6 +971,7 @@
         return ACAMERA_ERROR_CAMERA_DISCONNECTED;
     }
     device->setRemoteDevice(deviceRemote);
+    device->setDeviceMetadataQueues();
     if (flags::camera_multi_client() && sharedMode) {
         binder::Status remoteRet = deviceRemote->isPrimaryClient(primaryClient);
         if (!remoteRet.isOk()) {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 4384df9..5f7f2f6 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -63,6 +63,7 @@
 using namespace android;
 using ::android::hardware::ICameraService;
 using ::android::hardware::camera2::ICameraDeviceUser;
+using ::android::hardware::camera2::CameraMetadataInfo;
 
 #define ASSERT_NOT_NULL(x) \
     ASSERT_TRUE((x) != nullptr)
@@ -249,10 +250,10 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onResultReceived(const CameraMetadata& metadata,
+    virtual binder::Status onResultReceived(const CameraMetadataInfo& resultInfo,
             const CaptureResultExtras& resultExtras,
             const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
-        (void) metadata;
+        (void) resultInfo;
         (void) resultExtras;
         (void) physicalResultInfos;
         Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index b9c8206..b44f949 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -87,7 +87,9 @@
         "android.hardware.camera.device@3.6",
         "android.hardware.camera.device@3.7",
         "android.hardware.common-V2-ndk",
+        "android.hardware.common-V2-cpp",
         "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.common.fmq-V1-cpp",
         "camera_platform_flags_c_lib",
         "com.android.window.flags.window-aconfig_flags_c_lib",
         "media_permission-aidl-cpp",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 31a45c3..fdb5b7d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1492,6 +1492,7 @@
         int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
         apiLevel effectiveApiLevel, bool overrideForPerfClass, int rotationOverride,
         bool forceSlowJpegMode, const std::string& originalCameraId, bool sharedMode,
+        bool isVendorClient,
         /*out*/sp<BasicClient>* client) {
     // For HIDL devices
     if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
@@ -1537,7 +1538,8 @@
                 cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
                 cameraService->mAttributionAndPermissionUtils, clientAttribution, callingPid,
                 systemNativeClient, cameraId, facing, sensorOrientation, servicePid,
-                overrideForPerfClass, rotationOverride, originalCameraId, sharedMode);
+                overrideForPerfClass, rotationOverride, originalCameraId, sharedMode,
+                isVendorClient);
         ALOGI("%s: Camera2 API, rotationOverride %d", __FUNCTION__, rotationOverride);
     }
     return Status::ok();
@@ -1638,7 +1640,7 @@
                   /*rotationOverride*/
                   hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
                   /*forceSlowJpegMode*/ false, cameraIdStr, /*isNonSystemNdk*/ false,
-                  /*sharedMode*/false, /*out*/ tmp))
+                  /*sharedMode*/false, /*isVendorClient*/false,/*out*/ tmp))
                  .isOk()) {
         ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().c_str());
     }
@@ -2202,7 +2204,8 @@
             cameraClient, cameraIdStr, api1CameraId, resolvedClientAttribution,
             /*systemNativeClient*/ false, API_1,
             /*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion, rotationOverride,
-            forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false, /*out*/ client);
+            forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false,
+            /*isVendorClient*/ false, /*out*/ client);
 
     if (!ret.isOk()) {
         logRejected(cameraIdStr, getCallingPid(),
@@ -2286,7 +2289,32 @@
         const std::string& unresolvedCameraId,
         int oomScoreOffset, int targetSdkVersion,
         int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
-        bool sharedMode, /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+        bool sharedMode,
+        /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+    return connectDeviceImpl(cameraCb, unresolvedCameraId, oomScoreOffset, targetSdkVersion,
+            rotationOverride, clientAttribution, devicePolicy, sharedMode,
+            /*isVendorClient*/false, device);
+}
+
+Status CameraService::connectDeviceVendor(
+        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+        const std::string& unresolvedCameraId,
+        int oomScoreOffset, int targetSdkVersion,
+        int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
+        bool sharedMode,
+        /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+            return connectDeviceImpl(cameraCb, unresolvedCameraId, oomScoreOffset, targetSdkVersion,
+                    rotationOverride, clientAttribution, devicePolicy, sharedMode,
+                    /*isVendorClient*/true, device);
+}
+
+Status CameraService::connectDeviceImpl(
+        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+        const std::string& unresolvedCameraId,
+        int oomScoreOffset, int targetSdkVersion,
+        int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
+        bool sharedMode, bool isVendorClient,
+        /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
     ATRACE_CALL();
     RunThreadWithRealtimePriority priorityBump;
     Status ret = Status::ok();
@@ -2367,7 +2395,7 @@
             cameraCb, cameraId, /*api1CameraId*/ -1, resolvedClientAttribution, systemNativeClient,
             API_2, /*shimUpdateOnly*/ false, oomScoreOffset, targetSdkVersion, rotationOverride,
             /*forceSlowJpegMode*/ false, unresolvedCameraId, isNonSystemNdk, sharedMode,
-            /*out*/ client);
+            isVendorClient, /*out*/ client);
 
     if (!ret.isOk()) {
         logRejected(cameraId, clientPid, clientPackageName, toStdString(ret.toString8()));
@@ -2447,7 +2475,8 @@
                                     bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
                                     int rotationOverride, bool forceSlowJpegMode,
                                     const std::string& originalCameraId, bool isNonSystemNdk,
-                                    bool sharedMode, /*out*/ sp<CLIENT>& device) {
+                                    bool sharedMode, bool isVendorClient,
+                                    /*out*/ sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
     nsecs_t openTimeNs = systemTime();
@@ -2546,7 +2575,7 @@
                                systemNativeClient, cameraId, api1CameraId, facing, orientation,
                                getpid(), deviceVersionAndTransport, effectiveApiLevel,
                                overrideForPerfClass, rotationOverride, forceSlowJpegMode,
-                               originalCameraId, sharedMode,
+                               originalCameraId, sharedMode, isVendorClient,
                                /*out*/ &tmp))
                      .isOk()) {
             return ret;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 6f29ff4..c4d2d67 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -280,6 +280,14 @@
             std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false,
             bool isProcessLocalTest = false);
 
+    binder::Status  connectDeviceVendor(
+            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+            const std::string& cameraId, int scoreOffset, int targetSdkVersion,
+            int rotationOverride, const AttributionSourceState& clientAttribution,
+            int32_t devicePolicy, bool sharedMode,
+            /*out*/
+            sp<hardware::camera2::ICameraDeviceUser>* device);
+
     // Monitored UIDs availability notification
     void                notifyMonitoredUids();
     void                notifyMonitoredUids(const std::unordered_set<uid_t> &notifyUidSet);
@@ -996,7 +1004,16 @@
                                  bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
                                  int rotationOverride, bool forceSlowJpegMode,
                                  const std::string& originalCameraId, bool isNonSystemNdk,
-                                 bool sharedMode, /*out*/ sp<CLIENT>& device);
+                                 bool sharedMode, bool isVendorClient,
+                                 /*out*/ sp<CLIENT>& device);
+
+    binder::Status connectDeviceImpl(
+            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+            const std::string& cameraId, int scoreOffset, int targetSdkVersion,
+            int rotationOverride, const AttributionSourceState& clientAttribution,
+            int32_t devicePolicy, bool sharedMode, bool isVendorClient,
+            /*out*/
+            sp<hardware::camera2::ICameraDeviceUser>* device);
 
     // Lock guarding camera service state
     Mutex               mServiceLock;
@@ -1493,6 +1510,7 @@
                                      apiLevel effectiveApiLevel, bool overrideForPerfClass,
                                      int rotationOverride, bool forceSlowJpegMode,
                                      const std::string& originalCameraId, bool sharedMode,
+                                     bool isVendorClient,
                                      /*out*/ sp<BasicClient>* client);
 
     static std::string toString(std::set<userid_t> intSet);
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
index 70647b4..950ea05 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
@@ -174,11 +174,19 @@
 }
 
 binder::Status AidlCameraDeviceCallbacks::onResultReceived(
-    const CameraMetadataNative& result,
+    const CameraMetadataInfo &resultInfo,
     const UCaptureResultExtras& resultExtras,
     const ::std::vector<UPhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
     // Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
     // sp<RefBase>-able structure and post it.
+    // We modify metadata - since we want to filter out tags based on the vndk
+    // version, and also this communication is an in process function call.
+    // So we don't use FMQ for the shim layer. FMQ is still used for VNDK IPC.
+    if (resultInfo.getTag() != CameraMetadataInfo::metadata) {
+        ALOGE("Vendor callbacks got metadata in fmq ? ");
+        return binder::Status::ok();
+    }
+    const CameraMetadataNative &result = resultInfo.get<CameraMetadataInfo::metadata>();
     sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
                                                         resultExtras, physicalCaptureResultInfos);
     sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
index 07bf7d8..6504cdc 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
@@ -46,6 +46,7 @@
 using ::android::frameworks::cameraservice::utils::DeathPipe;
 using ::android::hardware::camera2::impl::CameraMetadataNative;
 
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 using CaptureResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 
 class AidlCameraDeviceCallbacks : public UBnCameraDeviceCallbacks {
@@ -65,7 +66,8 @@
                                     int64_t timestamp) override;
 
     binder::Status onResultReceived(
-            const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+            const CameraMetadataInfo &resultInfo,
+            const CaptureResultExtras& resultExtras,
             const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
 
     binder::Status onPrepared(int32_t streamId) override;
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
index a2c431e..46e2280 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraService.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -177,7 +177,7 @@
                     kDefaultDeviceId);
     clientAttribution.packageName = "";
     clientAttribution.attributionTag = std::nullopt;
-    binder::Status serviceRet = mCameraService->connectDevice(
+    binder::Status serviceRet = mCameraService->connectDeviceVendor(
             callbacks,
             in_cameraId,
             /* scoreOffset= */ 0,
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
index 1ec5072..ea7b9c0 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.cpp
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -32,6 +32,7 @@
 
 using aimg::AImageReader_getHGBPFromHandle;
 using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 
 // Note: existing data in dst will be gone. Caller still owns the memory of src
 void cloneToAidl(const camera_metadata_t* src, SCameraMetadata* dst) {
@@ -254,7 +255,8 @@
     SPhysicalCaptureResultInfo dst;
     dst.physicalCameraId = src.mPhysicalCameraId;
 
-    const camera_metadata_t *rawMetadata = src.mPhysicalCameraMetadata.getAndLock();
+    const camera_metadata_t *rawMetadata =
+            src.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().getAndLock();
     // Try using fmq at first.
     size_t metadata_size = get_camera_metadata_size(rawMetadata);
     if ((metadata_size > 0) && (fmq->availableToWrite() > 0)) {
@@ -267,7 +269,7 @@
             dst.physicalCameraMetadata.set<SCaptureMetadataInfo::metadata>(std::move(metadata));
         }
     }
-    src.mPhysicalCameraMetadata.unlock(rawMetadata);
+    src.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().unlock(rawMetadata);
     return dst;
 }
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8c30d54..5679720 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -16,6 +16,11 @@
 
 #define LOG_TAG "CameraDeviceClient"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
 //#define LOG_NDEBUG 0
 
 #include <com_android_internal_camera_flags.h>
@@ -40,6 +45,7 @@
 #include "JpegRCompositeStream.h"
 
 // Convenience methods for constructing binder::Status objects for error returns
+constexpr int32_t METADATA_QUEUE_SIZE = 1 << 20;
 
 #define STATUS_ERROR(errorCode, errorString) \
     binder::Status::fromServiceSpecificError(errorCode, \
@@ -80,7 +86,7 @@
         const AttributionSourceState& clientAttribution, int callingPid, bool systemNativeClient,
         const std::string& cameraId, int cameraFacing, int sensorOrientation, int servicePid,
         bool overrideForPerfClass, int rotationOverride, const std::string& originalCameraId,
-        bool sharedMode)
+        bool sharedMode, bool isVendorClient)
     : Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper,
                         attributionAndPermissionUtils, clientAttribution, callingPid,
                         systemNativeClient, cameraId, /*API1 camera ID*/ -1, cameraFacing,
@@ -90,7 +96,8 @@
       mStreamingRequestId(REQUEST_ID_NONE),
       mRequestIdCounter(0),
       mOverrideForPerfClass(overrideForPerfClass),
-      mOriginalCameraId(originalCameraId) {
+      mOriginalCameraId(originalCameraId),
+      mIsVendorClient(isVendorClient) {
     ATRACE_CALL();
     ALOGI("CameraDeviceClient %s: Opened", cameraId.c_str());
 }
@@ -180,6 +187,14 @@
             mHighResolutionSensors.insert(physicalId);
         }
     }
+    int32_t resultMQSize =
+            property_get_int32("ro.vendor.camera.res.fmq.size", /*default*/METADATA_QUEUE_SIZE);
+    res = CreateMetadataQueue(&mResultMetadataQueue, resultMQSize);
+    if (res != OK) {
+        ALOGE("%s: Creating result metadata queue failed: %s(%d)", __FUNCTION__,
+            strerror(-res), res);
+        return res;
+    }
     return OK;
 }
 
@@ -1768,6 +1783,34 @@
     return binder::Status::ok();
 }
 
+status_t CameraDeviceClient::CreateMetadataQueue(
+        std::unique_ptr<MetadataQueue>* metadata_queue, uint32_t default_size_bytes) {
+        if (metadata_queue == nullptr) {
+            ALOGE("%s: metadata_queue is nullptr", __FUNCTION__);
+            return BAD_VALUE;
+        }
+
+        int32_t size = default_size_bytes;
+
+        *metadata_queue =
+                std::make_unique<MetadataQueue>(static_cast<size_t>(size),
+                        /*configureEventFlagWord*/ false);
+        if (!(*metadata_queue)->isValid()) {
+            ALOGE("%s: Creating metadata queue (size %d) failed.", __FUNCTION__, size);
+            return NO_INIT;
+        }
+
+        return OK;
+}
+
+binder::Status CameraDeviceClient::getCaptureResultMetadataQueue(
+          android::hardware::common::fmq::MQDescriptor<
+          int8_t, android::hardware::common::fmq::SynchronizedReadWrite>* aidl_return) {
+
+    *aidl_return = mResultMetadataQueue->dupeDesc();
+    return binder::Status::ok();
+}
+
 binder::Status CameraDeviceClient::getGlobalAudioRestriction(/*out*/ int32_t* outMode) {
     ATRACE_CALL();
     binder::Status res;
@@ -2190,16 +2233,76 @@
     mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs, hasDeviceError);
 }
 
+size_t CameraDeviceClient::writeResultMetadataIntoResultQueue(
+        const CameraMetadata &resultMetadata) {
+    ATRACE_CALL();
+
+    const camera_metadata_t *resultMetadataP = resultMetadata.getAndLock();
+    size_t resultSize = get_camera_metadata_size(resultMetadataP);
+    if (mResultMetadataQueue != nullptr &&
+        mResultMetadataQueue->write(reinterpret_cast<const int8_t*>(resultMetadataP),
+                resultSize)) {
+        resultMetadata.unlock(resultMetadataP);
+        return resultSize;
+    }
+    resultMetadata.unlock(resultMetadataP);
+    ALOGE(" %s couldn't write metadata into result queue ", __FUNCTION__);
+    return 0;
+}
+
 /** Device-related methods */
+std::vector<PhysicalCaptureResultInfo> CameraDeviceClient::convertToFMQ(
+        const std::vector<PhysicalCaptureResultInfo> &physicalResults) {
+    std::vector<PhysicalCaptureResultInfo> retVal;
+    ALOGVV("%s E", __FUNCTION__);
+    for (const auto &srcPhysicalResult : physicalResults) {
+        size_t fmqSize = 0;
+        if (!mIsVendorClient && flags::fmq_metadata()) {
+            fmqSize = writeResultMetadataIntoResultQueue(
+                    srcPhysicalResult.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
+        }
+        ALOGVV("%s physical metadata write size is %d", __FUNCTION__, (int)fmqSize);
+        if (fmqSize != 0) {
+            retVal.emplace_back(srcPhysicalResult.mPhysicalCameraId, fmqSize);
+        } else {
+            // The flag was off / we're serving VNDK shim call or FMQ write failed.
+            retVal.emplace_back(srcPhysicalResult.mPhysicalCameraId,
+                    srcPhysicalResult.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
+        }
+    }
+    ALOGVV("%s X", __FUNCTION__);
+    return retVal;
+}
+
 void CameraDeviceClient::onResultAvailable(const CaptureResult& result) {
     ATRACE_CALL();
-    ALOGV("%s", __FUNCTION__);
+    ALOGVV("%s E", __FUNCTION__);
 
     // Thread-safe. No lock necessary.
     sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
     if (remoteCb != NULL) {
-        remoteCb->onResultReceived(result.mMetadata, result.mResultExtras,
-                result.mPhysicalMetadatas);
+        // Write  result metadata into metadataQueue
+        size_t fmqMetadataSize = 0;
+        // Vendor clients need to modify metadata and also this call is in process
+        // before going through FMQ to vendor clients. So don't use FMQ here.
+        if (!mIsVendorClient && flags::fmq_metadata()) {
+            fmqMetadataSize = writeResultMetadataIntoResultQueue(result.mMetadata);
+        }
+        hardware::camera2::impl::CameraMetadataNative resultMetadata;
+        CameraMetadataInfo resultInfo;
+        if (fmqMetadataSize == 0) {
+            // The flag was off / we're serving VNDK shim call or FMQ write failed.
+            resultMetadata = result.mMetadata;
+            resultInfo.set<CameraMetadataInfo::metadata>(resultMetadata);
+        } else {
+            resultInfo.set<CameraMetadataInfo::fmqSize>(fmqMetadataSize);
+        }
+
+        std::vector<PhysicalCaptureResultInfo> physicalMetadatas =
+                convertToFMQ(result.mPhysicalMetadatas);
+
+        remoteCb->onResultReceived(resultInfo, result.mResultExtras,
+                physicalMetadatas);
     }
 
     // Access to the composite stream map must be synchronized
@@ -2207,6 +2310,7 @@
     for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
         mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
     }
+    ALOGVV("%s X", __FUNCTION__);
 }
 
 binder::Status CameraDeviceClient::checkPidStatus(const char* checkLocation) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index a8cf451..691fa8d 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -24,6 +24,8 @@
 #include <camera/camera2/SubmitInfo.h>
 #include <unordered_map>
 
+#include <fmq/AidlMessageQueueCpp.h>
+
 #include "CameraOfflineSessionClient.h"
 #include "CameraService.h"
 #include "common/FrameProcessorBase.h"
@@ -161,6 +163,11 @@
 
     virtual binder::Status setCameraAudioRestriction(int32_t mode) override;
 
+    virtual binder::Status getCaptureResultMetadataQueue(
+          android::hardware::common::fmq::MQDescriptor<
+          int8_t, android::hardware::common::fmq::SynchronizedReadWrite>*
+          aidl_return) override;
+
     virtual binder::Status getGlobalAudioRestriction(/*out*/int32_t* outMode) override;
 
     virtual binder::Status switchToOffline(
@@ -182,7 +189,8 @@
                        const AttributionSourceState& clientAttribution, int callingPid,
                        bool clientPackageOverride, const std::string& cameraId, int cameraFacing,
                        int sensorOrientation, int servicePid, bool overrideForPerfClass,
-                       int rotationOverride, const std::string& originalCameraId, bool sharedMode);
+                       int rotationOverride, const std::string& originalCameraId, bool sharedMode,
+                       bool isVendorClient);
     virtual ~CameraDeviceClient();
 
     virtual status_t      initialize(sp<CameraProviderManager> manager,
@@ -233,6 +241,10 @@
      */
 protected:
     /** FilteredListener implementation **/
+
+    size_t writeResultMetadataIntoResultQueue(const CameraMetadata &result);
+    std::vector<PhysicalCaptureResultInfo> convertToFMQ(
+            const std::vector<PhysicalCaptureResultInfo> &physicalResults);
     virtual void          onResultAvailable(const CaptureResult& result);
     virtual void          detachDevice();
 
@@ -244,6 +256,11 @@
     const CameraMetadata &getStaticInfo(const std::string &cameraId);
 
 private:
+    using MetadataQueue = AidlMessageQueueCpp<
+            int8_t, android::hardware::common::fmq::SynchronizedReadWrite>;
+    using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
+    status_t CreateMetadataQueue(
+            std::unique_ptr<MetadataQueue>* metadata_queue, uint32_t default_size);
     // StreamSurfaceId encapsulates streamId + surfaceId for a particular surface.
     // streamId specifies the index of the stream the surface belongs to, and the
     // surfaceId specifies the index of the surface within the stream. (one stream
@@ -322,6 +339,9 @@
 
     int32_t mRequestIdCounter;
 
+    // Metadata queue to write the result metadata to.
+    std::unique_ptr<MetadataQueue> mResultMetadataQueue;
+
     std::vector<std::string> mPhysicalCameraIds;
 
     // The list of output streams whose surfaces are deferred. We have to track them separately
@@ -361,6 +381,8 @@
 
     // This only exists in case of camera ID Remapping.
     const std::string mOriginalCameraId;
+
+    bool mIsVendorClient = false;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 71fd3ba..1e73d79 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -299,7 +299,10 @@
     ALOGV("%s", __FUNCTION__);
 
     if (mRemoteCallback.get() != NULL) {
-        mRemoteCallback->onResultReceived(result.mMetadata, result.mResultExtras,
+        using hardware::camera2::CameraMetadataInfo;
+        CameraMetadataInfo resultInfo;
+        resultInfo.set<CameraMetadataInfo::metadata>(result.mMetadata);
+        mRemoteCallback->onResultReceived(resultInfo, result.mResultExtras,
                 result.mPhysicalMetadatas);
     }
 
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 2322def..31dcce2 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -29,6 +29,8 @@
 namespace android {
 namespace camera2 {
 
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
+
 FrameProcessorBase::FrameProcessorBase(wp<FrameProducer> device) :
     Thread(/*canCallJava*/false),
     mDevice(device),
@@ -99,7 +101,7 @@
 
         for (const auto& physicalFrame : mLastPhysicalFrames) {
             lastPhysicalFrames.emplace(physicalFrame.mPhysicalCameraId,
-                    physicalFrame.mPhysicalCameraMetadata);
+                    physicalFrame.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
         }
     }
     lastFrame.dump(fd, /*verbosity*/2, /*indentation*/6);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index ed11a96..66dcbc3 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -56,6 +56,7 @@
 using namespace android::camera3;
 using namespace android::camera3::SessionConfigurationUtils;
 using namespace android::hardware::camera;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 namespace flags = com::android::internal::camera::flags;
 
 namespace android {
@@ -231,11 +232,12 @@
 
     // Update vendor tag id for physical metadata
     for (auto& physicalMetadata : result->mPhysicalMetadatas) {
-        camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(
-                physicalMetadata.mPhysicalCameraMetadata.getAndLock());
+        auto &metadata =
+                physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>();
+        camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(metadata.getAndLock());
         set_camera_metadata_vendor_id(pmeta, states.vendorTagId);
         correctMeteringRegions(pmeta);
-        physicalMetadata.mPhysicalCameraMetadata.unlock(pmeta);
+        metadata.unlock(pmeta);
     }
 
     // Valid result, insert into queue
@@ -362,7 +364,8 @@
 
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
         camera_metadata_entry timestamp =
-                physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
+                physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+                        find(ANDROID_SENSOR_TIMESTAMP);
         if (timestamp.count == 0) {
             SET_ERR("No timestamp provided by HAL for physical camera %s frame %d!",
                     physicalMetadata.mPhysicalCameraId.c_str(), frameNumber);
@@ -415,7 +418,8 @@
         return;
     }
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
-        res = fixupManualFlashStrengthControlTags(physicalMetadata.mPhysicalCameraMetadata);
+        res = fixupManualFlashStrengthControlTags(physicalMetadata.mCameraMetadataInfo.
+                get<CameraMetadataInfo::metadata>());
         if (res != OK) {
             SET_ERR("Failed to set flash strength level defaults in physical result"
                     " metadata: %s (%d)", strerror(-res), res);
@@ -431,7 +435,8 @@
         return;
     }
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
-        res = fixupAutoframingTags(physicalMetadata.mPhysicalCameraMetadata);
+        res = fixupAutoframingTags(physicalMetadata.mCameraMetadataInfo.
+                get<CameraMetadataInfo::metadata>());
         if (res != OK) {
             SET_ERR("Failed to set autoframing defaults in physical result metadata: %s (%d)",
                     strerror(-res), res);
@@ -444,7 +449,7 @@
         auto mapper = states.distortionMappers.find(cameraId);
         if (mapper != states.distortionMappers.end()) {
             res = mapper->second.correctCaptureResult(
-                    &physicalMetadata.mPhysicalCameraMetadata);
+                    &physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
             if (res != OK) {
                 SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
                         frameNumber, strerror(-res), res);
@@ -455,7 +460,8 @@
         // Note: Physical camera continues to use SCALER_CROP_REGION to reflect
         // zoom levels.
         res = states.zoomRatioMappers[cameraId].updateCaptureResult(
-                &physicalMetadata.mPhysicalCameraMetadata, /*zoomMethodIsRatio*/false,
+                &physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>(),
+                /*zoomMethodIsRatio*/false,
                 /*zoomRatioIs1*/false);
         if (res != OK) {
             SET_ERR("Failed to update camera %s's physical zoom ratio metadata for "
@@ -474,7 +480,7 @@
         const std::string &cameraId = physicalMetadata.mPhysicalCameraId;
         res = fixupMonochromeTags(states,
                 states.physicalDeviceInfoMap.at(cameraId),
-                physicalMetadata.mPhysicalCameraMetadata);
+                physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
         if (res != OK) {
             SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
             return;
@@ -484,7 +490,7 @@
     std::unordered_map<std::string, CameraMetadata> monitoredPhysicalMetadata;
     for (auto& m : physicalMetadatas) {
         monitoredPhysicalMetadata.emplace(m.mPhysicalCameraId,
-                CameraMetadata(m.mPhysicalCameraMetadata));
+                CameraMetadata(m.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>()));
     }
     states.tagMonitor.monitorMetadata(TagMonitor::RESULT,
             frameNumber, sensorTimestamp, captureResult.mMetadata,
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
index de51ffa..24d9a7e 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
@@ -167,11 +167,19 @@
 }
 
 binder::Status H2BCameraDeviceCallbacks::onResultReceived(
-    const CameraMetadataNative& result,
+    const CameraMetadataInfo &resultInfo,
     const CaptureResultExtras& resultExtras,
     const ::std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
     // Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
     // sp<RefBase>-able structure and post it.
+    // We modify metadata - since we want to filter out tags based on the vndk
+    // version, and also this communication is an in process function call.
+    // So we don't use FMQ for the shim layer. FMQ is still used for VNDK IPC.
+    if (resultInfo.getTag() != CameraMetadataInfo::metadata) {
+        ALOGE("Vendor callbacks got metadata in fmq ? ");
+        return binder::Status::ok();
+    }
+    const CameraMetadataNative &result = resultInfo.get<CameraMetadataInfo::metadata>();
     sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
                                                         resultExtras, physicalCaptureResultInfos);
     sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
index 98a0dbb..e36c2ea 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
@@ -54,6 +54,7 @@
 using hardware::kSynchronizedReadWrite;
 using hardware::MessageQueue;
 using CaptureResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 
 struct H2BCameraDeviceCallbacks :
     public H2BConverter<HCameraDeviceCallback, ICameraDeviceCallbacks, BnCameraDeviceCallbacks> {
@@ -72,7 +73,8 @@
                                             int64_t timestamp) override;
 
     virtual binder::Status onResultReceived(
-        const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+        const CameraMetadataInfo &,
+        const CaptureResultExtras& resultExtras,
         const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
 
     virtual binder::Status onPrepared(int32_t streamId) override;
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 9d140f2..9e66236 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -132,7 +132,7 @@
                     kDefaultDeviceId);
     clientAttribution.packageName = "";
     clientAttribution.attributionTag = std::nullopt;
-    binder::Status serviceRet = mAidlICameraService->connectDevice(
+    binder::Status serviceRet = mAidlICameraService->connectDeviceVendor(
             callbacks, cameraId, 0/*oomScoreOffset*/,
             /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE,
             clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, /*out*/&deviceRemote);
diff --git a/services/camera/libcameraservice/hidl/Utils.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
index d0302d0..d37287b 100644
--- a/services/camera/libcameraservice/hidl/Utils.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -28,6 +28,7 @@
 
 using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
 using aimg::AImageReader_getHGBPFromHandle;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
 
 // Note: existing data in dst will be gone. Caller still owns the memory of src
 void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst) {
@@ -274,7 +275,8 @@
     hPhysicalCaptureResultInfo.physicalCameraId =
         toString8(physicalCaptureResultInfo.mPhysicalCameraId);
     const camera_metadata_t *rawMetadata =
-        physicalCaptureResultInfo.mPhysicalCameraMetadata.getAndLock();
+        physicalCaptureResultInfo.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+                getAndLock();
     // Try using fmq at first.
     size_t metadata_size = get_camera_metadata_size(rawMetadata);
     if ((metadata_size > 0) && (captureResultMetadataQueue->availableToWrite() > 0)) {
@@ -287,7 +289,8 @@
             hPhysicalCaptureResultInfo.physicalCameraMetadata.metadata(std::move(metadata));
         }
     }
-    physicalCaptureResultInfo.mPhysicalCameraMetadata.unlock(rawMetadata);
+    physicalCaptureResultInfo.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+            unlock(rawMetadata);
     return hPhysicalCaptureResultInfo;
 }
 
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 6c98837..8c7d39e 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -54,6 +54,7 @@
 
 using ICameraService::ROTATION_OVERRIDE_NONE;
 using ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT;
+using android::hardware::camera2::CameraMetadataInfo;
 
 const int32_t kPreviewThreshold = 8;
 const int32_t kNumRequestsTested = 8;
@@ -778,7 +779,7 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+    virtual binder::Status onResultReceived(const CameraMetadataInfo& /*metadata*/,
             const CaptureResultExtras& /*resultExtras*/,
             const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
         return binder::Status::ok();
diff --git a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
index ff58c4a..2f035e7 100644
--- a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
@@ -34,6 +34,7 @@
 
 using namespace android;
 using namespace android::hardware::camera;
+using android::hardware::camera2::CameraMetadataInfo;
 
 // Empty service listener.
 class TestCameraServiceListener : public hardware::BnCameraServiceListener {
@@ -107,7 +108,7 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+    virtual binder::Status onResultReceived(const CameraMetadataInfo& /*metadata*/,
             const CaptureResultExtras& /*resultExtras*/,
             const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
         return binder::Status::ok();