Merge "audio policy: fix LE audio input device selection." into tm-dev
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 42b3c43..0acf7d7 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -1502,6 +1502,7 @@
         igbp = new B2HGraphicBufferProducer2(surface);
     }
 
+    std::scoped_lock lock(mOutputMutex);
     std::shared_ptr<SurfaceSyncObj> syncObj;
 
     if (!surface) {
@@ -1586,6 +1587,24 @@
     mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
 }
 
+void Codec2Client::Component::stopUsingOutputSurface(
+        C2BlockPool::local_id_t blockPoolId) {
+    std::scoped_lock lock(mOutputMutex);
+    mOutputBufferQueue->stop();
+    Return<Status> transStatus = mBase1_0->setOutputSurface(
+            static_cast<uint64_t>(blockPoolId), nullptr);
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
+    } else {
+        c2_status_t status =
+                static_cast<c2_status_t>(static_cast<Status>(transStatus));
+        if (status != C2_OK) {
+            LOG(DEBUG) << "setOutputSurface(stopUsingOutputSurface) -- call failed: "
+                       << status << ".";
+        }
+    }
+}
+
 c2_status_t Codec2Client::Component::connectToInputSurface(
         const std::shared_ptr<InputSurface>& inputSurface,
         std::shared_ptr<InputSurfaceConnection>* connection) {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 347e58a..49d9b28 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -411,6 +411,10 @@
     // Set max dequeue count for output surface.
     void setOutputSurfaceMaxDequeueCount(int maxDequeueCount);
 
+    // Stop using the current output surface.
+    void stopUsingOutputSurface(
+            C2BlockPool::local_id_t blockPoolId);
+
     // Connect to a given InputSurface.
     c2_status_t connectToInputSurface(
             const std::shared_ptr<InputSurface>& inputSurface,
@@ -441,6 +445,11 @@
     struct OutputBufferQueue;
     std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
 
+    // (b/202903117) Sometimes MediaCodec::setSurface races between normal
+    // setSurface and setSurface with ReleaseSurface due to timing issues.
+    // In order to prevent the race condition mutex is added.
+    std::mutex mOutputMutex;
+
     static c2_status_t setDeathListener(
             const std::shared_ptr<Component>& component,
             const std::shared_ptr<Listener>& listener);
diff --git a/media/codec2/hidl/client/include/codec2/hidl/output.h b/media/codec2/hidl/client/include/codec2/hidl/output.h
index 877148a..a13edf3 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/output.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/output.h
@@ -50,6 +50,10 @@
                    int maxDequeueBufferCount,
                    std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);
 
+    // Stop using the current output surface. Pending buffer opeations will not
+    // perform anymore.
+    void stop();
+
     // Render a graphic block to current surface.
     status_t outputBuffer(
             const C2ConstGraphicBlock& block,
@@ -81,6 +85,7 @@
     sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
     std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
     std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
+    bool mStopped;
 
     bool registerBuffer(const C2ConstGraphicBlock& block);
 };
diff --git a/media/codec2/hidl/client/output.cpp b/media/codec2/hidl/client/output.cpp
index de34c24..f789030 100644
--- a/media/codec2/hidl/client/output.cpp
+++ b/media/codec2/hidl/client/output.cpp
@@ -169,7 +169,7 @@
 } // unnamed namespace
 
 OutputBufferQueue::OutputBufferQueue()
-      : mGeneration{0}, mBqId{0} {
+      : mGeneration{0}, mBqId{0}, mStopped{false} {
 }
 
 OutputBufferQueue::~OutputBufferQueue() {
@@ -219,6 +219,8 @@
             poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
     {
         std::scoped_lock<std::mutex> l(mMutex);
+        bool stopped = mStopped;
+        mStopped = false;
         if (generation == mGeneration) {
             // case of old BlockPool destruction
             C2SyncVariables *var = mSyncMem ? mSyncMem->mem() : nullptr;
@@ -258,7 +260,7 @@
             return false;
         }
         for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
-            if (mBqId == 0 || !mBuffers[i]) {
+            if (mBqId == 0 || !mBuffers[i] || stopped) {
                 continue;
             }
             std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
@@ -317,6 +319,12 @@
     return true;
 }
 
+void OutputBufferQueue::stop() {
+    std::scoped_lock<std::mutex> l(mMutex);
+    mStopped = true;
+    mOwner.reset(); // destructor of the block will not triger IGBP::cancel()
+}
+
 bool OutputBufferQueue::registerBuffer(const C2ConstGraphicBlock& block) {
     std::shared_ptr<_C2BlockPoolData> data =
             _C2BlockFactory::GetGraphicBlockPoolData(block);
@@ -325,7 +333,7 @@
     }
     std::scoped_lock<std::mutex> l(mMutex);
 
-    if (!mIgbp) {
+    if (!mIgbp || mStopped) {
         return false;
     }
 
@@ -371,11 +379,17 @@
 
         std::shared_ptr<C2SurfaceSyncMemory> syncMem;
         mMutex.lock();
+        bool stopped = mStopped;
         sp<IGraphicBufferProducer> outputIgbp = mIgbp;
         uint32_t outputGeneration = mGeneration;
         syncMem = mSyncMem;
         mMutex.unlock();
 
+        if (stopped) {
+            LOG(INFO) << "outputBuffer -- already stopped.";
+            return DEAD_OBJECT;
+        }
+
         status_t status = attachToBufferQueue(
                 block, outputIgbp, outputGeneration, &bqSlot, syncMem);
 
@@ -408,12 +422,18 @@
 
     std::shared_ptr<C2SurfaceSyncMemory> syncMem;
     mMutex.lock();
+    bool stopped = mStopped;
     sp<IGraphicBufferProducer> outputIgbp = mIgbp;
     uint32_t outputGeneration = mGeneration;
     uint64_t outputBqId = mBqId;
     syncMem = mSyncMem;
     mMutex.unlock();
 
+    if (stopped) {
+        LOG(INFO) << "outputBuffer -- already stopped.";
+        return DEAD_OBJECT;
+    }
+
     if (!outputIgbp) {
         LOG(VERBOSE) << "outputBuffer -- output surface is null.";
         return NO_INIT;
@@ -467,7 +487,7 @@
     mMutex.lock();
     mMaxDequeueBufferCount = maxDequeueBufferCount;
     auto syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
-    if (syncVar) {
+    if (syncVar && !mStopped) {
         syncVar->lock();
         syncVar->updateMaxDequeueCountLocked(maxDequeueBufferCount);
         syncVar->unlock();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 62a1d02..159e885 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1570,6 +1570,14 @@
         Mutexed<Output>::Locked output(mOutput);
         output->buffers.reset();
     }
+    if (mOutputSurface.lock()->surface) {
+        C2BlockPool::local_id_t outputPoolId;
+        {
+            Mutexed<BlockPools>::Locked pools(mBlockPools);
+            outputPoolId = pools->outputPoolId;
+        }
+        mComponent->stopUsingOutputSurface(outputPoolId);
+    }
 }
 
 void CCodecBufferChannel::release() {
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index bec978a..29aad5e 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -129,8 +129,9 @@
     // Create a local BlockPoolData.
     C2BufferQueueBlockPoolData(
             uint32_t generation, uint64_t bqId, int32_t bqSlot,
+            const std::shared_ptr<int> &owner,
             const android::sp<HGraphicBufferProducer>& producer,
-            std::shared_ptr<C2SurfaceSyncMemory>, int noUse);
+            std::shared_ptr<C2SurfaceSyncMemory>);
 
     virtual ~C2BufferQueueBlockPoolData() override;
 
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 63b0f39..e67e42f 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -542,7 +542,7 @@
                         std::make_shared<C2BufferQueueBlockPoolData>(
                                 slotBuffer->getGenerationNumber(),
                                 mProducerId, slot,
-                                mProducer, mSyncMem, 0);
+                                mIgbpValidityToken, mProducer, mSyncMem);
                 mPoolDatas[slot] = poolData;
                 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
                 return C2_OK;
@@ -572,10 +572,11 @@
     Impl(const std::shared_ptr<C2Allocator> &allocator)
         : mInit(C2_OK), mProducerId(0), mGeneration(0),
           mConsumerUsage(0), mDqFailure(0), mLastDqTs(0),
-          mLastDqLogTs(0), mAllocator(allocator) {
+          mLastDqLogTs(0), mAllocator(allocator), mIgbpValidityToken(std::make_shared<int>(0)) {
     }
 
     ~Impl() {
+        mIgbpValidityToken.reset();
         for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
             mBuffers[i].clear();
         }
@@ -618,7 +619,7 @@
             }
             std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
                     std::make_shared<C2BufferQueueBlockPoolData>(
-                            0, (uint64_t)0, ~0, nullptr, nullptr, 0);
+                            0, (uint64_t)0, ~0, nullptr, nullptr, nullptr);
             *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
             ALOGV("allocated a buffer successfully");
 
@@ -694,8 +695,7 @@
                 mProducer = nullptr;
                 mProducerId = 0;
                 mGeneration = 0;
-                ALOGW("invalid producer producer(%d), generation(%d)",
-                      (bool)producer, bqInformation);
+                ALOGD("configuring null producer: igbp_information(%d)", bqInformation);
             }
             oldMem = mSyncMem; // preven destruction while locked.
             mSyncMem = c2SyncMem;
@@ -720,6 +720,10 @@
                         }
                     }
                 }
+            } else {
+                // old buffers should not be cancelled since the associated IGBP
+                // is no longer valid.
+                mIgbpValidityToken = std::make_shared<int>(0);
             }
             for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
                 mBuffers[i] = buffers[i];
@@ -761,6 +765,20 @@
     std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
 
     std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
+
+    // IGBP invalidation notification token.
+    // The buffers(C2BufferQueueBlockPoolData) has the reference to the IGBP where
+    // they belong in order to call IGBP::cancelBuffer() when they are of no use.
+    //
+    // In certain cases, IGBP is no longer used by this class(actually MediaCodec)
+    // any more and the situation needs to be addressed quickly. In order to
+    // achieve those, std::shared_ptr<> is used as a token for quick IGBP invalidation
+    // notification from the buffers.
+    //
+    // The buffer side will have the reference of the token as std::weak_ptr<>.
+    // if the token has been expired, the buffers will not call IGBP::cancelBuffer()
+    // when they are no longer used.
+    std::shared_ptr<int> mIgbpValidityToken;
 };
 
 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
@@ -776,14 +794,14 @@
 
 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
         uint32_t generation, uint64_t bqId, int32_t bqSlot,
+        const std::shared_ptr<int>& owner,
         const android::sp<HGraphicBufferProducer>& producer,
-        std::shared_ptr<C2SurfaceSyncMemory> syncMem, int noUse) :
+        std::shared_ptr<C2SurfaceSyncMemory> syncMem) :
         mLocal(true), mHeld(true),
         mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
         mCurrentGeneration(generation), mCurrentBqId(bqId),
         mTransfer(false), mAttach(false), mDisplay(false),
-        mIgbp(producer), mSyncMem(syncMem) {
-            (void)noUse;
+        mOwner(owner), mIgbp(producer), mSyncMem(syncMem) {
 }
 
 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
@@ -792,7 +810,7 @@
     }
 
     if (mLocal) {
-        if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId) {
+        if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId && !mOwner.expired()) {
             C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
             if (syncVar) {
                 syncVar->lock();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 36f8e10..6ab8339 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -728,11 +728,13 @@
     //  (b) we can support re-creation of offloaded tracks
     if (offloadInfo != NULL) {
         mOffloadInfoCopy = *offloadInfo;
-        mOffloadInfo = &mOffloadInfoCopy;
     } else {
-        mOffloadInfo = NULL;
         memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
         mOffloadInfoCopy = AUDIO_INFO_INITIALIZER;
+        mOffloadInfoCopy.format = format;
+        mOffloadInfoCopy.sample_rate = sampleRate;
+        mOffloadInfoCopy.channel_mask = channelMask;
+        mOffloadInfoCopy.stream_type = streamType;
     }
 
     mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
diff --git a/media/libaudioclient/include/media/AidlConversionUtil.h b/media/libaudioclient/include/media/AidlConversionUtil.h
index 820b7cb..9f294cb 100644
--- a/media/libaudioclient/include/media/AidlConversionUtil.h
+++ b/media/libaudioclient/include/media/AidlConversionUtil.h
@@ -20,6 +20,7 @@
 #include <type_traits>
 #include <utility>
 
+#include <binder/Enums.h>
 #include <binder/Status.h>
 #include <error/Result.h>
 
@@ -270,6 +271,15 @@
 namespace aidl_utils {
 
 /**
+ * Return true if the value is valid for the AIDL enumeration.
+ */
+template <typename T>
+bool isValidEnum(T value) {
+    constexpr android::enum_range<T> er{};
+    return std::find(er.begin(), er.end(), value) != er.end();
+}
+
+/**
  * Return the equivalent Android status_t from a binder exception code.
  *
  * Generally one should use statusTFromBinderStatus() instead.
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 1cf6ef9..9f540e6 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1344,7 +1344,6 @@
     sp<IMemory>             mSharedBuffer;
     transfer_type           mTransfer;
     audio_offload_info_t    mOffloadInfoCopy;
-    const audio_offload_info_t* mOffloadInfo;
     audio_attributes_t      mAttributes;
 
     size_t                  mFrameSize;             // frame size in bytes
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 40a1eaa..8eefe77 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -571,12 +571,6 @@
         lHalConfig.offload_info.channel_mask = lHalConfig.channel_mask;
         lHalConfig.offload_info.format = lHalConfig.format;
         lHalConfig.offload_info.stream_type = stream;
-        lHalConfig.offload_info.duration_us = -1;
-        lHalConfig.offload_info.has_video = true; // conservative
-        lHalConfig.offload_info.is_streaming = true; // likely
-        lHalConfig.offload_info.encapsulation_mode = lHalConfig.offload_info.encapsulation_mode;
-        lHalConfig.offload_info.content_id = lHalConfig.offload_info.content_id;
-        lHalConfig.offload_info.sync_id = lHalConfig.offload_info.sync_id;
     }
 
     audio_config_base_t lMixerConfig;
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index ef11072..9baaf93 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -214,21 +214,79 @@
     status_t status = getHalParameter<false>(effect, SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED,
                                          &supportsHeadTracking);
     if (status != NO_ERROR) {
+        ALOGW("%s: cannot get SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED", __func__);
         return status;
     }
     mSupportsHeadTracking = supportsHeadTracking[0];
 
-    status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_LEVELS, &mLevels);
+    std::vector<media::SpatializationLevel> spatializationLevels;
+    status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_LEVELS,
+            &spatializationLevels);
     if (status != NO_ERROR) {
+        ALOGW("%s: cannot get SPATIALIZER_PARAM_SUPPORTED_LEVELS", __func__);
         return status;
     }
+    bool noneLevelFound = false;
+    bool activeLevelFound = false;
+    for (const auto spatializationLevel : spatializationLevels) {
+        if (!aidl_utils::isValidEnum(spatializationLevel)) {
+            ALOGW("%s: ignoring spatializationLevel:%d", __func__, (int)spatializationLevel);
+            continue;
+        }
+        if (spatializationLevel == media::SpatializationLevel::NONE) {
+            noneLevelFound = true;
+        } else {
+            activeLevelFound = true;
+        }
+        // we don't detect duplicates.
+        mLevels.emplace_back(spatializationLevel);
+    }
+    if (!noneLevelFound || !activeLevelFound) {
+        ALOGW("%s: SPATIALIZER_PARAM_SUPPORTED_LEVELS must include NONE"
+                " and another valid level",  __func__);
+        return BAD_VALUE;
+    }
+
+    std::vector<media::SpatializationMode> spatializationModes;
     status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES,
-                                &mSpatializationModes);
+            &spatializationModes);
     if (status != NO_ERROR) {
+        ALOGW("%s: cannot get SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES", __func__);
         return status;
     }
-    return getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
-                                 &mChannelMasks);
+    for (const auto spatializationMode : spatializationModes) {
+        if (!aidl_utils::isValidEnum(spatializationMode)) {
+            ALOGW("%s: ignoring spatializationMode:%d", __func__, (int)spatializationMode);
+            continue;
+        }
+        // we don't detect duplicates.
+        mSpatializationModes.emplace_back(spatializationMode);
+    }
+    if (mSpatializationModes.empty()) {
+        ALOGW("%s: SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES reports empty", __func__);
+        return BAD_VALUE;
+    }
+
+    std::vector<audio_channel_mask_t> channelMasks;
+    status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
+                                 &channelMasks);
+    if (status != NO_ERROR) {
+        ALOGW("%s: cannot get SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS", __func__);
+        return status;
+    }
+    for (const auto channelMask : channelMasks) {
+        if (!audio_is_channel_mask_spatialized(channelMask)) {
+            ALOGW("%s: ignoring channelMask:%#x", __func__, channelMask);
+            continue;
+        }
+        // we don't detect duplicates.
+        mChannelMasks.emplace_back(channelMask);
+    }
+    if (mChannelMasks.empty()) {
+        ALOGW("%s: SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS reports empty", __func__);
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
 }
 
 /** Gets the channel mask, sampling rate and format set for the spatializer input. */
@@ -238,8 +296,10 @@
     // For now use highest supported channel count
     uint32_t maxCount = 0;
     for ( auto mask : mChannelMasks) {
-        if (audio_channel_count_from_out_mask(mask) > maxCount) {
+        const size_t count = audio_channel_count_from_out_mask(mask);
+        if (count > maxCount) {
             config.channel_mask = mask;
+            maxCount = count;
         }
     }
     return config;
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 493696b..e98975e 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -92,9 +92,9 @@
         "gui/RingBufferConsumer.cpp",
         "hidl/AidlCameraDeviceCallbacks.cpp",
         "hidl/AidlCameraServiceListener.cpp",
-        "hidl/Convert.cpp",
         "hidl/HidlCameraDeviceUser.cpp",
         "hidl/HidlCameraService.cpp",
+        "hidl/Utils.cpp",
         "utils/CameraServiceProxyWrapper.cpp",
         "utils/CameraThreadState.cpp",
         "utils/CameraTraces.cpp",
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index b5d0746..add1483 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -89,9 +89,10 @@
     if (strlen(camera_stream::physical_camera_id) > 0) {
         lines.appendFormat("      Physical camera id: %s\n", camera_stream::physical_camera_id);
     }
-    lines.appendFormat("      Dynamic Range Profile: 0x%" PRIx64,
+    lines.appendFormat("      Dynamic Range Profile: 0x%" PRIx64 "\n",
             camera_stream::dynamic_range_profile);
     lines.appendFormat("      Stream use case: %" PRId64 "\n", camera_stream::use_case);
+    lines.appendFormat("      Timestamp base: %d\n", getTimestampBase());
     lines.appendFormat("      Frames produced: %d, last timestamp: %" PRId64 " ns\n",
             mFrameCount, mLastTimestamp);
     lines.appendFormat("      Total buffers: %zu, currently dequeued: %zu\n",
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index b21322c..1ce7108 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -460,8 +460,8 @@
         }
 
         if (mPreviewFrameSpacer != nullptr) {
-            res = mPreviewFrameSpacer->queuePreviewBuffer(timestamp - mTimestampOffset, transform,
-                    anwBuffer, anwReleaseFence);
+            res = mPreviewFrameSpacer->queuePreviewBuffer(timestamp - mTimestampOffset,
+                    readoutTimestamp - mTimestampOffset, transform, anwBuffer, anwReleaseFence);
             if (res != OK) {
                 ALOGE("%s: Stream %d: Error queuing buffer to preview buffer spacer: %s (%d)",
                         __FUNCTION__, mId, strerror(-res), res);
@@ -680,12 +680,15 @@
         bool forceChoreographer = (timestampBase ==
                 OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
         bool defaultToChoreographer = (isDefaultTimeBase &&
-                isConsumedByHWComposer() &&
-                !property_get_bool("camera.disable_preview_scheduler", false));
+                isConsumedByHWComposer());
+        bool defaultToSpacer = (isDefaultTimeBase &&
+                isConsumedByHWTexture() &&
+                !isConsumedByCPU() &&
+                !isVideoStream());
         if (forceChoreographer || defaultToChoreographer) {
             mSyncToDisplay = true;
             mTotalBufferCount += kDisplaySyncExtraBuffer;
-        } else if (isConsumedByHWTexture() && !isVideoStream()) {
+        } else if (defaultToSpacer) {
             mPreviewFrameSpacer = new PreviewFrameSpacer(*this, mConsumer);
             mTotalBufferCount ++;
             res = mPreviewFrameSpacer->run(String8::format("PreviewSpacer-%d", mId).string());
@@ -1260,6 +1263,17 @@
     return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
 }
 
+bool Camera3OutputStream::isConsumedByCPU() const {
+    uint64_t usage = 0;
+    status_t res = getEndpointUsage(&usage);
+    if (res != OK) {
+        ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+        return false;
+    }
+
+    return (usage & GRALLOC_USAGE_SW_READ_MASK) != 0;
+}
+
 void Camera3OutputStream::dumpImageToDisk(nsecs_t timestamp,
         ANativeWindowBuffer* anwBuffer, int fence) {
     // Deriver output file name
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 45e995d..5f2831f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -160,6 +160,11 @@
     bool isConsumedByHWTexture() const;
 
     /**
+     * Return if this output stream is consumed by CPU.
+     */
+    bool isConsumedByCPU() const;
+
+    /**
      * Return if the consumer configuration of this stream is deferred.
      */
     virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
index 9112b93..496580f 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
@@ -36,12 +36,12 @@
     Thread::requestExitAndWait();
 }
 
-status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
-        ANativeWindowBuffer* anwBuffer, int releaseFence) {
+status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
+        int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence) {
     Mutex::Autolock l(mLock);
-    mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
-    ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64, __FUNCTION__,
-            mPendingBuffers.size(), timestamp);
+    mPendingBuffers.emplace(timestamp, readoutTimestamp, transform, anwBuffer, releaseFence);
+    ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64 ", readoutTime %" PRId64,
+            __FUNCTION__, mPendingBuffers.size(), timestamp, readoutTimestamp);
 
     mBufferCond.signal();
     return OK;
@@ -56,17 +56,17 @@
 
     nsecs_t currentTime = systemTime();
     auto buffer = mPendingBuffers.front();
-    nsecs_t captureInterval = buffer.timestamp - mLastCameraCaptureTime;
-    // If the capture interval exceeds threshold, directly queue
+    nsecs_t readoutInterval = buffer.readoutTimestamp - mLastCameraReadoutTime;
+    // If the readout interval exceeds threshold, directly queue
     // cached buffer.
-    if (captureInterval >= kFrameIntervalThreshold) {
+    if (readoutInterval >= kFrameIntervalThreshold) {
         mPendingBuffers.pop();
         queueBufferToClientLocked(buffer, currentTime);
         return true;
     }
 
-    // Cache the frame to match capture time interval, for up to 33ms
-    nsecs_t expectedQueueTime = mLastCameraPresentTime + captureInterval;
+    // Cache the frame to match readout time interval, for up to 33ms
+    nsecs_t expectedQueueTime = mLastCameraPresentTime + readoutInterval;
     nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
     if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
         mBufferCond.waitRelative(mLock, frameWaitTime);
@@ -75,8 +75,8 @@
         }
         currentTime = systemTime();
     }
-    ALOGV("%s: captureInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
-            ", timestamp %" PRId64, __FUNCTION__, captureInterval,
+    ALOGV("%s: readoutInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
+            ", timestamp %" PRId64, __FUNCTION__, readoutInterval,
             currentTime - mLastCameraPresentTime, frameWaitTime, buffer.timestamp);
     mPendingBuffers.pop();
     queueBufferToClientLocked(buffer, currentTime);
@@ -114,7 +114,7 @@
     }
 
     mLastCameraPresentTime = currentTime;
-    mLastCameraCaptureTime = bufferHolder.timestamp;
+    mLastCameraReadoutTime = bufferHolder.readoutTimestamp;
 }
 
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
index 5062553..fb0a563 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
@@ -42,8 +42,8 @@
  *
  * The PreviewFrameSpacer improves the viewfinder user experience by:
  * - Cache the frame buffers if the intervals between queueBuffer is shorter
- *   than the camera capture intervals.
- * - Queue frame buffers in the same cadence as the camera capture time.
+ *   than the camera readout intervals.
+ * - Queue frame buffers in the same cadence as the camera readout time.
  * - Maintain at most 1 queue-able buffer. If the 2nd preview buffer becomes
  *   available, queue the oldest cached buffer to the buffer queue.
  */
@@ -53,8 +53,8 @@
     virtual ~PreviewFrameSpacer();
 
     // Queue preview buffer locally
-    status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
-            ANativeWindowBuffer* anwBuffer, int releaseFence);
+    status_t queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
+            int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence);
 
     bool threadLoop() override;
     void requestExit() override;
@@ -63,12 +63,14 @@
     // structure holding cached preview buffer info
     struct BufferHolder {
         nsecs_t timestamp;
+        nsecs_t readoutTimestamp;
         int32_t transform;
         sp<ANativeWindowBuffer> anwBuffer;
         int releaseFence;
 
-        BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
-                timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
+        BufferHolder(nsecs_t t, nsecs_t readoutT, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
+                timestamp(t), readoutTimestamp(readoutT), transform(tr), anwBuffer(anwb),
+                releaseFence(rf) {}
     };
 
     void queueBufferToClientLocked(const BufferHolder& bufferHolder, nsecs_t currentTime);
@@ -80,7 +82,7 @@
     Condition mBufferCond;
 
     std::queue<BufferHolder> mPendingBuffers;
-    nsecs_t mLastCameraCaptureTime = 0;
+    nsecs_t mLastCameraReadoutTime = 0;
     nsecs_t mLastCameraPresentTime = 0;
     static constexpr nsecs_t kWaitDuration = 5000000LL; // 50ms
     static constexpr nsecs_t kFrameIntervalThreshold = 80000000LL; // 80ms
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
index f063506..3392db1 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
@@ -16,7 +16,7 @@
 #include <hardware/camera.h>
 
 #include <hidl/AidlCameraDeviceCallbacks.h>
-#include <hidl/Convert.h>
+#include <hidl/Utils.h>
 
 namespace android {
 namespace frameworks {
@@ -34,7 +34,7 @@
 
 H2BCameraDeviceCallbacks::H2BCameraDeviceCallbacks(const sp<HalInterface>& base) : CBase(base) { }
 
-bool H2BCameraDeviceCallbacks::initializeLooper() {
+bool H2BCameraDeviceCallbacks::initializeLooper(int vndkVersion) {
     mCbLooper = new ALooper;
     mCbLooper->setName("cs-looper");
     status_t err = mCbLooper->start(/*runOnCallingThread*/ false, /*canCallJava*/ false,
@@ -43,7 +43,7 @@
         ALOGE("Unable to start camera device callback looper");
         return false;
     }
-    mHandler = new CallbackHandler(this);
+    mHandler = new CallbackHandler(this, vndkVersion);
     mCbLooper->registerHandler(mHandler);
     return true;
 }
@@ -144,6 +144,12 @@
 
     // Convert Metadata into HCameraMetadata;
     FmqSizeOrMetadata hResult;
+    using hardware::cameraservice::utils::conversion::filterVndkKeys;
+    if (filterVndkKeys(mVndkVersion, result, /*isStatic*/false) != OK) {
+        ALOGE("%s: filtering vndk keys from result failed, not sending onResultReceived callback",
+                __FUNCTION__);
+        return;
+    }
     const camera_metadata_t *rawMetadata = result.getAndLock();
     converter->convertResultMetadataToHidl(rawMetadata, &hResult);
     result.unlock(rawMetadata);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
index dbf520a..152002b 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
@@ -61,7 +61,7 @@
 
     ~H2BCameraDeviceCallbacks();
 
-    bool initializeLooper();
+    bool initializeLooper(int vndkVersion);
 
     virtual binder::Status onDeviceError(int32_t errorCode,
                                          const CaptureResultExtras& resultExtras) override;
@@ -103,10 +103,12 @@
     struct CallbackHandler : public AHandler {
         public:
             void onMessageReceived(const sp<AMessage> &msg) override;
-            CallbackHandler(H2BCameraDeviceCallbacks *converter) : mConverter(converter) { }
+            CallbackHandler(H2BCameraDeviceCallbacks *converter, int vndkVersion) :
+                    mConverter(converter), mVndkVersion(vndkVersion) { }
         private:
             void processResultMessage(sp<ResultWrapper> &resultWrapper);
             wp<H2BCameraDeviceCallbacks> mConverter = nullptr;
+            int mVndkVersion = -1;
             Mutex mMetadataQueueLock;
     };
 
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
index cca3f2e..add9121 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <hidl/AidlCameraServiceListener.h>
-#include <hidl/Convert.h>
+#include <hidl/Utils.h>
 
 namespace android {
 namespace frameworks {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index 2509e6c..26e813a 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -20,8 +20,8 @@
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 
 #include <hidl/AidlCameraDeviceCallbacks.h>
-#include <hidl/Convert.h>
 #include <hidl/HidlCameraDeviceUser.h>
+#include <hidl/Utils.h>
 #include <android/hardware/camera/device/3.2/types.h>
 
 namespace android {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index a812587..65a0300 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include <hidl/Convert.h>
+#include <android-base/properties.h>
 
-#include <hidl/HidlCameraService.h>
-
-#include <hidl/HidlCameraDeviceUser.h>
 #include <hidl/AidlCameraDeviceCallbacks.h>
 #include <hidl/AidlCameraServiceListener.h>
+#include <hidl/HidlCameraService.h>
+#include <hidl/HidlCameraDeviceUser.h>
+#include <hidl/Utils.h>
 
 #include <hidl/HidlTransportSupport.h>
 
@@ -34,6 +34,7 @@
 using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
 using hardware::hidl_vec;
 using hardware::cameraservice::utils::conversion::convertToHidl;
+using hardware::cameraservice::utils::conversion::filterVndkKeys;
 using hardware::cameraservice::utils::conversion::B2HStatus;
 using hardware::Void;
 
@@ -53,6 +54,10 @@
     return gHidlCameraService;
 }
 
+HidlCameraService::HidlCameraService(android::CameraService *cs) : mAidlICameraService(cs) {
+    mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
+};
+
 Return<void>
 HidlCameraService::getCameraCharacteristics(const hidl_string& cameraId,
                                             getCameraCharacteristics_cb _hidl_cb) {
@@ -77,6 +82,11 @@
         _hidl_cb(status, hidlMetadata);
         return Void();
     }
+    if (filterVndkKeys(mVndkVersion, cameraMetadata) != OK) {
+        ALOGE("%s: Unable to filter vndk metadata keys for version %d", __FUNCTION__, mVndkVersion);
+        _hidl_cb(HStatus::UNKNOWN_ERROR, hidlMetadata);
+        return Void();
+    }
     const camera_metadata_t *rawMetadata = cameraMetadata.getAndLock();
     convertToHidl(rawMetadata, &hidlMetadata);
     _hidl_cb(status, hidlMetadata);
@@ -97,7 +107,7 @@
     // Create a hardware::camera2::ICameraDeviceCallback object which internally
     // calls callback functions passed through hCallback.
     sp<H2BCameraDeviceCallbacks> hybridCallbacks = new H2BCameraDeviceCallbacks(hCallback);
-    if (!hybridCallbacks->initializeLooper()) {
+    if (!hybridCallbacks->initializeLooper(mVndkVersion)) {
         ALOGE("Unable to handle callbacks on device, cannot connect");
         _hidl_cb(HStatus::UNKNOWN_ERROR, nullptr);
         return Void();
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.h b/services/camera/libcameraservice/hidl/HidlCameraService.h
index 86a7cec..1c8145c 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.h
@@ -75,7 +75,7 @@
     static sp<HidlCameraService> getInstance(android::CameraService *cs);
 
 private:
-    HidlCameraService(android::CameraService *cs) : mAidlICameraService(cs) { };
+    HidlCameraService(android::CameraService *cs);
 
     sp<hardware::ICameraServiceListener> searchListenerCacheLocked(
         sp<HCameraServiceListener> listener, /*removeIfFound*/ bool shouldRemove = false);
@@ -95,6 +95,7 @@
     using HIListeners =
         std::pair<sp<HCameraServiceListener>, sp<ICameraServiceListener>>;
     std::list<HIListeners> mListeners;
+    int mVndkVersion = -1;
 };
 
 }  // namespace implementation
diff --git a/services/camera/libcameraservice/hidl/Convert.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
similarity index 92%
rename from services/camera/libcameraservice/hidl/Convert.cpp
rename to services/camera/libcameraservice/hidl/Utils.cpp
index 597147b..057a6e9 100644
--- a/services/camera/libcameraservice/hidl/Convert.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#include <hidl/Convert.h>
+#include <hidl/Utils.h>
+#include <hidl/VndkVersionMetadataTags.h>
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <cutils/native_handle.h>
 #include <mediautils/AImageReaderUtils.h>
@@ -297,6 +298,31 @@
     return hPhysicalCaptureResultInfos;
 }
 
+status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic) {
+    if (vndkVersion == __ANDROID_API_FUTURE__) {
+        // VNDK version in ro.vndk.version is a version code-name that
+        // corresponds to the current version.
+        return OK;
+    }
+    const auto &apiLevelToKeys =
+            isStatic ? static_api_level_to_keys : dynamic_api_level_to_keys;
+    // Find the vndk versions above the given vndk version. All the vndk
+    // versions above the given one, need to have their keys filtered from the
+    // metadata in order to avoid metadata invalidation.
+    auto it = apiLevelToKeys.upper_bound(vndkVersion);
+    while (it != apiLevelToKeys.end()) {
+        for (const auto &key : it->second) {
+            status_t res = metadata.erase(key);
+            if (res != OK) {
+                ALOGE("%s metadata key %d could not be erased", __FUNCTION__, key);
+                return res;
+            }
+        }
+        it++;
+    }
+    return OK;
+}
+
 } //conversion
 } // utils
 } //cameraservice
diff --git a/services/camera/libcameraservice/hidl/Convert.h b/services/camera/libcameraservice/hidl/Utils.h
similarity index 96%
rename from services/camera/libcameraservice/hidl/Convert.h
rename to services/camera/libcameraservice/hidl/Utils.h
index 82ffc48..e6d4393 100644
--- a/services/camera/libcameraservice/hidl/Convert.h
+++ b/services/camera/libcameraservice/hidl/Utils.h
@@ -29,6 +29,7 @@
 #include <android/hardware/camera2/ICameraDeviceUser.h>
 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
 #include <android/hardware/ICameraService.h>
+#include <camera/CameraMetadata.h>
 #include <fmq/MessageQueue.h>
 #include <hardware/camera.h>
 #include <hidl/MQDescriptor.h>
@@ -96,6 +97,8 @@
 
 HStatus B2HStatus(const binder::Status &bStatus);
 
+status_t filterVndkKeys(int vndk_version, CameraMetadata &metadata, bool isStatic = true);
+
 } // conversion
 } // utils
 } // cameraservice
diff --git a/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h
new file mode 100644
index 0000000..d3377f4
--- /dev/null
+++ b/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <map>
+#include <vector>
+#pragma once
+/**
+ * ! Do not edit this file directly !
+ *
+ * Generated automatically from vndk_camera_metadata_tags.mako. To be included in libcameraservice
+ * only by hidl/Utils.cpp.
+ */
+
+/**
+ * API level to static keys mapping. To be used for filtering out keys depending on vndk version
+ * used by vendor clients.
+ */
+std::map<int, std::vector<camera_metadata_tag>> static_api_level_to_keys{
+      {30, {
+          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES,
+          ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+          ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
+          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+        } },
+      {31, {
+          ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION,
+          ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS,
+          ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED,
+          ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+          ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION,
+          ANDROID_SCALER_DEFAULT_SECURE_IMAGE_SIZE,
+          ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+          ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION,
+          ANDROID_SENSOR_INFO_BINNING_FACTOR,
+        } },
+      {32, {
+          ANDROID_INFO_DEVICE_STATE_ORIENTATIONS,
+        } },
+      {33, {
+          ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+          ANDROID_AUTOMOTIVE_LENS_FACING,
+          ANDROID_AUTOMOTIVE_LOCATION,
+          ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
+          ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES,
+          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP,
+          ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
+        } },
+};
+
+/**
+ * API level to dynamic keys mapping. To be used for filtering out keys depending on vndk version
+ * used by vendor clients.
+ */
+std::map<int, std::vector<camera_metadata_tag>> dynamic_api_level_to_keys{
+      {30, {
+          ANDROID_CONTROL_ZOOM_RATIO,
+          ANDROID_SCALER_ROTATE_AND_CROP,
+          ANDROID_CONTROL_EXTENDED_SCENE_MODE,
+        }  },
+      {31, {
+          ANDROID_SENSOR_PIXEL_MODE,
+          ANDROID_SENSOR_RAW_BINNING_FACTOR_USED,
+        }  },
+};