Merge "Enforce CREATE_VIRTUAL_DEVICE permission for virtual camera service" into main
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 409a930..8078cea 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -22,6 +22,7 @@
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraInjectionCallback;
 import android.hardware.camera2.ICameraInjectionSession;
+import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.params.VendorTagDescriptor;
 import android.hardware.camera2.params.VendorTagDescriptorCache;
 import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
@@ -261,4 +262,18 @@
     const int DEVICE_STATE_FOLDED = 4;
     const int DEVICE_STATE_LAST_FRAMEWORK_BIT = 0x80000000; // 1 << 31;
 
+    // Create a CaptureRequest metadata based on template id
+    CameraMetadataNative createDefaultRequest(@utf8InCpp String cameraId, int templateId);
+
+    /**
+      * Check whether a particular session configuration with optional session parameters
+      * has camera device support.
+      *
+      * @param cameraId The camera id to query session configuration on
+      * @param sessionConfiguration Specific session configuration to be verified.
+      * @return true  - in case the stream combination is supported.
+      *         false - in case there is no device support.
+      */
+    boolean isSessionConfigurationWithParametersSupported(@utf8InCpp String cameraId,
+            in SessionConfiguration sessionConfiguration);
 }
diff --git a/camera/camera2/SessionConfiguration.cpp b/camera/camera2/SessionConfiguration.cpp
index 7cf6087..2f1f22d 100644
--- a/camera/camera2/SessionConfiguration.cpp
+++ b/camera/camera2/SessionConfiguration.cpp
@@ -22,10 +22,13 @@
 
 #include <camera/camera2/SessionConfiguration.h>
 #include <camera/camera2/OutputConfiguration.h>
+#include <com_android_internal_camera_flags.h>
 #include <binder/Parcel.h>
 
 namespace android {
 
+namespace flags = com::android::internal::camera::flags;
+
 status_t SessionConfiguration::readFromParcel(const android::Parcel* parcel) {
     status_t err = OK;
     int operatingMode = 0;
@@ -67,6 +70,22 @@
         return err;
     }
 
+    bool hasSessionParameters = false;
+    CameraMetadata settings;
+    if (flags::feature_combination_query()) {
+        if ((err = parcel->readBool(&hasSessionParameters)) != OK) {
+            ALOGE("%s: Failed to read hasSessionParameters flag from parcel", __FUNCTION__);
+            return err;
+        }
+
+        if (hasSessionParameters) {
+            if ((err = settings.readFromParcel(parcel)) != OK) {
+                ALOGE("%s: Failed to read metadata flag from parcel", __FUNCTION__);
+                return err;
+            }
+        }
+    }
+
     mOperatingMode = operatingMode;
     mInputWidth = inputWidth;
     mInputHeight = inputHeight;
@@ -75,7 +94,10 @@
     for (auto& stream : outputStreams) {
         mOutputStreams.push_back(stream);
     }
-
+    if (flags::feature_combination_query()) {
+        mHasSessionParameters = hasSessionParameters;
+        mSessionParameters = std::move(settings);
+    }
 
     return err;
 }
@@ -103,6 +125,16 @@
     err = parcel->writeParcelableVector(mOutputStreams);
     if (err != OK) return err;
 
+    if (flags::feature_combination_query()) {
+        err = parcel->writeBool(mHasSessionParameters);
+        if (err != OK) return err;
+
+        if (mHasSessionParameters) {
+            err = mSessionParameters.writeToParcel(parcel);
+            if (err != OK) return err;
+        }
+    }
+
     return OK;
 }
 
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 501b48b..f7deda1 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -13,6 +13,14 @@
      description: "Introduces a new concert mode camera extension type"
      bug: "297083874"
 }
+
+flag {
+     namespace: "camera_platform"
+     name: "feature_combination_query"
+     description: "Query feature combination support and session specific characteristics"
+     bug: "309627704"
+}
+
 flag {
      namespace: "camera_platform"
      name: "log_ultrawide_usage"
@@ -54,11 +62,3 @@
     description: "Enable session parameter injection via reconfiguration"
     bug: "308984721"
 }
-
-flag {
-     namespace: "camera_platform"
-     name: "camera_ae_mode_low_light_boost"
-     description: "An AE mode that enables increased brightening in low light scenes"
-     bug: "312803148"
-}
-
diff --git a/camera/include/camera/camera2/SessionConfiguration.h b/camera/include/camera/camera2/SessionConfiguration.h
index 29913f6..120bf9e 100644
--- a/camera/include/camera/camera2/SessionConfiguration.h
+++ b/camera/include/camera/camera2/SessionConfiguration.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
 
 #include <binder/Parcelable.h>
+#include <camera/CameraMetadata.h>
 
 namespace android {
 
@@ -39,6 +40,8 @@
     int getInputFormat() const { return mInputFormat; }
     int getOperatingMode() const { return mOperatingMode; }
     bool inputIsMultiResolution() const { return mInputIsMultiResolution; }
+    bool hasSessionParameters() const { return mHasSessionParameters; }
+    const CameraMetadata& getSessionParameters() const { return mSessionParameters; }
 
     virtual status_t writeToParcel(android::Parcel* parcel) const override;
     virtual status_t readFromParcel(const android::Parcel* parcel) override;
@@ -111,6 +114,8 @@
     std::vector<OutputConfiguration> mOutputStreams;
     int                              mInputWidth, mInputHeight, mInputFormat, mOperatingMode;
     bool                             mInputIsMultiResolution = false;
+    bool                             mHasSessionParameters = false;
+    CameraMetadata                   mSessionParameters;
 };
 } // namespace params
 } // namespace camera2
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 86b9e99..3a483cc 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2244,39 +2244,6 @@
      */
     ACAMERA_CONTROL_AUTOFRAMING_STATE =                         // byte (acamera_metadata_enum_android_control_autoframing_state_t)
             ACAMERA_CONTROL_START + 54,
-    /**
-     * <p>The operating luminance range of low light boost measured in lux (lx).</p>
-     *
-     * <p>Type: float[2]</p>
-     *
-     * <p>This tag may appear in:
-     * <ul>
-     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
-     * </ul></p>
-     *
-     */
-    ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE =      // float[2]
-            ACAMERA_CONTROL_START + 55,
-    /**
-     * <p>Current state of the low light boost AE mode.</p>
-     *
-     * <p>Type: byte (acamera_metadata_enum_android_control_low_light_boost_state_t)</p>
-     *
-     * <p>This tag may appear in:
-     * <ul>
-     *   <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
-     * </ul></p>
-     *
-     * <p>When low light boost is enabled by setting the AE mode to
-     * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
-     * boost when the light level threshold is exceeded.</p>
-     * <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
-     * indicate when it is not being applied by returning 'INACTIVE'.</p>
-     * <p>This key will be absent from the CaptureResult if AE mode is not set to
-     * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
-     */
-    ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE =                     // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
-            ACAMERA_CONTROL_START + 56,
     ACAMERA_CONTROL_END,
 
     /**
@@ -8247,44 +8214,6 @@
      */
     ACAMERA_CONTROL_AE_MODE_ON_EXTERNAL_FLASH                        = 5,
 
-    /**
-     * <p>Like 'ON' but applies additional brightness boost in low light scenes.</p>
-     * <p>When the scene lighting conditions are within the range defined by
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE this mode will apply additional
-     * brightness boost.</p>
-     * <p>This mode will automatically adjust the intensity of low light boost applied
-     * according to the scene lighting conditions. A darker scene will receive more boost
-     * while a brighter scene will receive less boost.</p>
-     * <p>This mode can ignore the set target frame rate to allow more light to be captured
-     * which can result in choppier motion. The frame rate can extend to lower than the
-     * ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES but will not go below 10 FPS. This mode
-     * can also increase the sensor sensitivity gain which can result in increased luma
-     * and chroma noise. The sensor sensitivity gain can extend to higher values beyond
-     * ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE. This mode may also apply additional
-     * processing to recover details in dark and bright areas of the image,and noise
-     * reduction at high sensitivity gain settings to manage the trade-off between light
-     * sensitivity and capture noise.</p>
-     * <p>This mode is restricted to two output surfaces. One output surface type can either
-     * be SurfaceView or TextureView. Another output surface type can either be MediaCodec
-     * or MediaRecorder. This mode cannot be used with a target FPS range higher than 30
-     * FPS.</p>
-     * <p>If the session configuration is not supported, the AE mode reported in the
-     * CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
-     * <p>The application can observe the CapturerResult field
-     * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
-     * 'INACTIVE'.</p>
-     * <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
-     * upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
-     * This mode will be 'INACTIVE' once the scene lighting condition is greater than the
-     * upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.</p>
-     *
-     * @see ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
-     * @see ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE
-     * @see ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE
-     * @see ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE
-     */
-    ACAMERA_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY   = 6,
-
 } acamera_metadata_enum_android_control_ae_mode_t;
 
 // ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
@@ -9286,20 +9215,6 @@
 
 } acamera_metadata_enum_android_control_autoframing_state_t;
 
-// ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE
-typedef enum acamera_metadata_enum_acamera_control_low_light_boost_state {
-    /**
-     * <p>The AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' is enabled but not applied.</p>
-     */
-    ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE                   = 0,
-
-    /**
-     * <p>The AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' is enabled and applied.</p>
-     */
-    ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE                     = 1,
-
-} acamera_metadata_enum_android_control_low_light_boost_state_t;
-
 
 
 // ACAMERA_EDGE_MODE
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 30c385c..60b814e 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -562,7 +562,7 @@
                 GET_DEVICE_DESC_CONNECTION(IP_V4));
         append_AudioDeviceDescription(pairs,
                 AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_OUT_BUS,
-                AudioDeviceType::IN_DEVICE, AudioDeviceType::OUT_DEVICE);
+                AudioDeviceType::IN_BUS, AudioDeviceType::OUT_BUS);
         append_AudioDeviceDescription(pairs,
                 AUDIO_DEVICE_IN_PROXY, AUDIO_DEVICE_OUT_PROXY,
                 AudioDeviceType::IN_AFE_PROXY, AudioDeviceType::OUT_AFE_PROXY,
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 8faf6e8..66d3295 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -203,12 +203,12 @@
 
 private:
     android::Mutex                          mServiceLock;
-    std::shared_ptr<AAudioServiceInterface> mAdapter;
+    std::shared_ptr<AAudioServiceInterface> mAdapter PT_GUARDED_BY(mServiceLock);
     android::sp<AAudioClient>               mAAudioClient;
 
-    std::shared_ptr<AAudioServiceInterface> getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> getAAudioService() EXCLUDES(mServiceLock);
 
-    void dropAAudioService();
+    void dropAAudioService() EXCLUDES(mServiceLock);
 
 };
 
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index 01dd05a..2c23e1d 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -117,8 +117,6 @@
     bool                    mFreeRunning{false};
     android::fifo_counter_t mDataReadCounter{0}; // only used if free-running
     android::fifo_counter_t mDataWriteCounter{0}; // only used if free-running
-
-    std::mutex mDataQueueLock;
 };
 
 } // namespace aaudio
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index ca0db0d..f431da8 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -64,6 +64,9 @@
 
 #define LOG_TIMESTAMPS            0
 
+// Minimum number of bursts to use when sample rate conversion is used.
+#define MIN_SAMPLE_RATE_CONVERSION_NUM_BURSTS    3
+
 AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
         : AudioStream()
         , mClockModel()
@@ -910,6 +913,12 @@
         numBursts = 1;
     }
 
+    // Set a minimum number of bursts if sample rate conversion is used.
+    if ((getSampleRate() != getDeviceSampleRate()) &&
+            (numBursts < MIN_SAMPLE_RATE_CONVERSION_NUM_BURSTS)) {
+        numBursts = MIN_SAMPLE_RATE_CONVERSION_NUM_BURSTS;
+    }
+
     if (mAudioEndpoint) {
         // Clip against the actual size from the endpoint.
         int32_t actualFramesDevice = 0;
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index f2f5cac..49a63c4 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -172,7 +172,7 @@
         return createThread_l(periodNanoseconds, threadProc, threadArg);
     }
 
-    aaudio_result_t joinThread(void **returnArg);
+    aaudio_result_t joinThread(void **returnArg) EXCLUDES(mStreamLock);
 
     virtual aaudio_result_t registerThread() {
         return AAUDIO_OK;
@@ -424,7 +424,7 @@
     }
 
     // This is used by the AudioManager to duck and mute the stream when changing audio focus.
-    void setDuckAndMuteVolume(float duckAndMuteVolume);
+    void setDuckAndMuteVolume(float duckAndMuteVolume) EXCLUDES(mStreamLock);
 
     float getDuckAndMuteVolume() const {
         return mDuckAndMuteVolume;
@@ -459,11 +459,11 @@
         mPlayerBase->unregisterWithAudioManager();
     }
 
-    aaudio_result_t systemStart();
+    aaudio_result_t systemStart() EXCLUDES(mStreamLock);
 
-    aaudio_result_t systemPause();
+    aaudio_result_t systemPause() EXCLUDES(mStreamLock);
 
-    aaudio_result_t safeFlush();
+    aaudio_result_t safeFlush() EXCLUDES(mStreamLock);
 
     /**
      * This is called when an app calls AAudioStream_requestStop();
@@ -474,14 +474,14 @@
     /**
      * This is called internally when an app callback returns AAUDIO_CALLBACK_RESULT_STOP.
      */
-    aaudio_result_t systemStopInternal();
+    aaudio_result_t systemStopInternal() EXCLUDES(mStreamLock);
 
     /**
      * Safely RELEASE a stream after taking mStreamLock and checking
      * to make sure we are not being called from a callback.
      * @return AAUDIO_OK or a negative error
      */
-    aaudio_result_t safeRelease();
+    aaudio_result_t safeRelease() EXCLUDES(mStreamLock);
 
     /**
      * Safely RELEASE and CLOSE a stream after taking mStreamLock and checking
@@ -490,7 +490,7 @@
      */
     aaudio_result_t safeReleaseClose();
 
-    aaudio_result_t safeReleaseCloseInternal();
+    aaudio_result_t safeReleaseCloseInternal() EXCLUDES(mStreamLock);
 
 protected:
 
diff --git a/media/libaaudio/tests/test_various.cpp b/media/libaaudio/tests/test_various.cpp
index b68fc7b..eea8783 100644
--- a/media/libaaudio/tests/test_various.cpp
+++ b/media/libaaudio/tests/test_various.cpp
@@ -829,7 +829,7 @@
 
     void waitForFinished() {
         std::unique_lock <std::mutex> aLock(mutex);
-        conditionVariable.wait(aLock, [=] { return finished; });
+        conditionVariable.wait(aLock, [this] { return finished; });
     }
 
     // For signalling foreground test when callback finished
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
index 77e58ed..5786f7f 100644
--- a/media/libaudiofoundation/include/media/AudioPort.h
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -48,7 +48,10 @@
     audio_port_role_t getRole() const { return mRole; }
 
     virtual void setFlags(uint32_t flags);
-    uint32_t getFlags() const { return useInputChannelMask() ? mFlags.input : mFlags.output; }
+    uint32_t getFlags() const {
+        return useInputChannelMask() ? static_cast<uint32_t>(mFlags.input)
+                                     : static_cast<uint32_t>(mFlags.output);
+    }
 
     void setGains(const AudioGains &gains) { mGains = gains; }
     const AudioGains &getGains() const { return mGains; }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 2c8e50b..cb45f54 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -361,7 +361,7 @@
         DeviceVector moduleDevices = hwModule->getAllDevices();
         auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress, encodedFormat);
 
-        // Prevent overwritting moduleDevice address if connected device does not have the same
+        // Prevent overwriting moduleDevice address if connected device does not have the same
         // address (since getDevice with empty address ignores match on address), use dynamic device
         if (moduleDevice && allowToCreate &&
                 (!moduleDevice->address().empty() &&
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index f25bca3..4883a09 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -106,7 +106,7 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.6",
         "android.hardware.camera.provider@2.7",
-        "android.hardware.camera.provider-V2-ndk",
+        "android.hardware.camera.provider-V3-ndk",
         "libaidlcommonsupport",
         "libbinderthreadstateutils",
         "libcameraservice_device_independent",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 8add05e..feb9c75 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -84,6 +84,7 @@
 #include "utils/TagMonitor.h"
 #include "utils/CameraThreadState.h"
 #include "utils/CameraServiceProxyWrapper.h"
+#include "utils/SessionConfigurationUtils.h"
 
 namespace {
     const char* kPermissionServiceName = "permission";
@@ -95,8 +96,10 @@
 
 namespace android {
 
-using binder::Status;
 using namespace camera3;
+using namespace camera3::SessionConfigurationUtils;
+
+using binder::Status;
 using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
 using frameworks::cameraservice::service::implementation::AidlCameraService;
 using hardware::ICamera;
@@ -861,6 +864,136 @@
     return Status::ok();
 }
 
+Status CameraService::createDefaultRequest(const std::string& unresolvedCameraId, int templateId,
+        /* out */
+        hardware::camera2::impl::CameraMetadataNative* request) {
+    ATRACE_CALL();
+
+    if (!flags::feature_combination_query()) {
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                "Camera subsystem doesn't support this method!");
+    }
+    if (!mInitialized) {
+        ALOGE("%s: Camera subsystem is not available", __FUNCTION__);
+        logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
+        return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
+    }
+
+    const std::string cameraId = resolveCameraId(unresolvedCameraId,
+            CameraThreadState::getCallingUid());
+
+    binder::Status res;
+    if (request == nullptr) {
+        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+                "Camera %s: Error creating default request", cameraId.c_str());
+        return res;
+    }
+    camera_request_template_t tempId = camera_request_template_t::CAMERA_TEMPLATE_COUNT;
+    res = SessionConfigurationUtils::mapRequestTemplateFromClient(
+            cameraId, templateId, &tempId);
+    if (!res.isOk()) {
+        ALOGE("%s: Camera %s: failed to map request Template %d",
+                __FUNCTION__, cameraId.c_str(), templateId);
+        return res;
+    }
+
+    if (shouldRejectSystemCameraConnection(cameraId)) {
+        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to create default"
+                "request for system only device %s: ", cameraId.c_str());
+    }
+
+    // Check for camera permissions
+    if (!hasCameraPermissions()) {
+        return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+                "android.permission.CAMERA needed to call"
+                "createDefaultRequest");
+    }
+
+    CameraMetadata metadata;
+    status_t err = mCameraProviderManager->createDefaultRequest(cameraId, tempId, &metadata);
+    if (err == OK) {
+        request->swap(metadata);
+    } else if (err == BAD_VALUE) {
+        res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "Camera %s: Template ID %d is invalid or not supported: %s (%d)",
+                cameraId.c_str(), templateId, strerror(-err), err);
+    } else {
+        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+                "Camera %s: Error creating default request for template %d: %s (%d)",
+                cameraId.c_str(), templateId, strerror(-err), err);
+    }
+    return res;
+}
+
+Status CameraService::isSessionConfigurationWithParametersSupported(
+        const std::string& unresolvedCameraId,
+        const SessionConfiguration& sessionConfiguration,
+        /*out*/
+        bool* supported) {
+    ATRACE_CALL();
+
+    if (!flags::feature_combination_query()) {
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+                "Camera subsystem doesn't support this method!");
+    }
+    if (!mInitialized) {
+        ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
+        logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
+        return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
+    }
+
+    const std::string cameraId = resolveCameraId(unresolvedCameraId,
+            CameraThreadState::getCallingUid());
+    if (supported == nullptr) {
+        std::string msg = fmt::sprintf("Camera %s: Invalid 'support' input!",
+                unresolvedCameraId.c_str());
+        ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+    }
+
+    if (shouldRejectSystemCameraConnection(cameraId)) {
+        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to query "
+                "session configuration with parameters support for system only device %s: ",
+                cameraId.c_str());
+    }
+
+    // Check for camera permissions
+    if (!hasCameraPermissions()) {
+        return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+                "android.permission.CAMERA needed to call"
+                "isSessionConfigurationWithParametersSupported");
+    }
+
+    *supported = false;
+    status_t ret = mCameraProviderManager->isSessionConfigurationSupported(cameraId.c_str(),
+            sessionConfiguration, /*mOverrideForPerfClass*/false, /*checkSessionParams*/true,
+            supported);
+    binder::Status res;
+    switch (ret) {
+        case OK:
+            // Expected, do nothing.
+            break;
+        case INVALID_OPERATION: {
+                std::string msg = fmt::sprintf(
+                        "Camera %s: Session configuration query not supported!",
+                        cameraId.c_str());
+                ALOGD("%s: %s", __FUNCTION__, msg.c_str());
+                res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
+            }
+
+            break;
+        default: {
+                std::string msg = fmt::sprintf( "Camera %s: Error: %s (%d)", cameraId.c_str(),
+                        strerror(-ret), ret);
+                ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+                res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                        msg.c_str());
+            }
+    }
+
+    return res;
+}
+
 Status CameraService::parseCameraIdRemapping(
         const hardware::CameraIdRemapping& cameraIdRemapping,
         /* out */ TCameraIdRemapping* cameraIdRemappingMap) {
@@ -3042,6 +3175,22 @@
     return Status::ok();
 }
 
+bool CameraService::hasCameraPermissions() const {
+    int callingPid = CameraThreadState::getCallingPid();
+    int callingUid = CameraThreadState::getCallingUid();
+    AttributionSourceState attributionSource{};
+    attributionSource.pid = callingPid;
+    attributionSource.uid = callingUid;
+    bool res = checkPermission(std::string(), sCameraPermission,
+            attributionSource, std::string(), AppOpsManager::OP_NONE);
+
+    bool hasPermission = ((callingPid == getpid()) || res);
+    if (!hasPermission) {
+        ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid);
+    }
+    return hasPermission;
+}
+
 Status CameraService::isConcurrentSessionConfigurationSupported(
         const std::vector<CameraIdAndSessionConfiguration>& cameraIdsAndSessionConfigurations,
         int targetSdkVersion, /*out*/bool* isSupported) {
@@ -3057,15 +3206,7 @@
     }
 
     // Check for camera permissions
-    int callingPid = CameraThreadState::getCallingPid();
-    int callingUid = CameraThreadState::getCallingUid();
-    AttributionSourceState attributionSource{};
-    attributionSource.pid = callingPid;
-    attributionSource.uid = callingUid;
-    bool checkPermissionForCamera = checkPermission(std::string(),
-                sCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
-    if ((callingPid != getpid()) && !checkPermissionForCamera) {
-        ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid);
+    if (!hasCameraPermissions()) {
         return STATUS_ERROR(ERROR_PERMISSION_DENIED,
                 "android.permission.CAMERA needed to call"
                 "isConcurrentSessionConfigurationSupported");
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 6819136..cabac17 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -234,6 +234,16 @@
     virtual binder::Status remapCameraIds(const hardware::CameraIdRemapping&
         cameraIdRemapping);
 
+    virtual binder::Status createDefaultRequest(const std::string& cameraId, int templateId,
+            /*out*/
+            hardware::camera2::impl::CameraMetadataNative* request);
+
+    virtual binder::Status isSessionConfigurationWithParametersSupported(
+            const std::string& cameraId,
+            const SessionConfiguration& sessionConfiguration,
+            /*out*/
+            bool* supported);
+
     // Extra permissions checks
     virtual status_t    onTransact(uint32_t code, const Parcel& data,
                                    Parcel* reply, uint32_t flags);
@@ -662,6 +672,7 @@
     bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
             int callingUid) const;
 
+    bool hasCameraPermissions() const;
    /**
      * Typesafe version of device status, containing both the HAL-layer and the service interface-
      * layer values.
diff --git a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
index e403b97..b193be2 100644
--- a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -77,7 +77,6 @@
       {34, {
           ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
           ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
-          ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
           ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
           ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
           ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
@@ -109,7 +108,6 @@
       {34, {
           ANDROID_CONTROL_AUTOFRAMING,
           ANDROID_CONTROL_AUTOFRAMING_STATE,
-          ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
           ANDROID_CONTROL_SETTINGS_OVERRIDE,
           ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
           ANDROID_EXTENSION_CURRENT_TYPE,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 28f7054..095d425 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -742,13 +742,6 @@
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
 
-    auto operatingMode = sessionConfiguration.getOperatingMode();
-    res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
-            mCameraIdStr);
-    if (!res.isOk()) {
-        return res;
-    }
-
     if (status == nullptr) {
         std::string msg = fmt::sprintf( "Camera %s: Invalid status!", mCameraIdStr.c_str());
         ALOGE("%s: %s", __FUNCTION__, msg.c_str());
@@ -756,11 +749,9 @@
     }
 
     *status = false;
-    camera3::metadataGetter getMetadata = [this](const std::string &id,
-            bool /*overrideForPerfClass*/) {
-          return mDevice->infoPhysical(id);};
     ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.c_str(),
-            sessionConfiguration, mOverrideForPerfClass, getMetadata, status);
+            sessionConfiguration, mOverrideForPerfClass, /*checkSessionParams*/false,
+            status);
     switch (ret) {
         case OK:
             // Expected, do nothing.
@@ -1396,7 +1387,9 @@
 
     status_t err;
     camera_request_template_t tempId = camera_request_template_t::CAMERA_TEMPLATE_COUNT;
-    if (!(res = mapRequestTemplate(templateId, &tempId)).isOk()) return res;
+    res = SessionConfigurationUtils::mapRequestTemplateFromClient(
+            mCameraIdStr, templateId, &tempId);
+    if (!res.isOk()) return res;
 
     CameraMetadata metadata;
     if ( (err = mDevice->createDefaultRequest(tempId, &metadata) ) == OK &&
@@ -2245,44 +2238,6 @@
     return CameraUtils::getRotationTransform(staticInfo, mirrorMode, transform);
 }
 
-binder::Status CameraDeviceClient::mapRequestTemplate(int templateId,
-        camera_request_template_t* tempId /*out*/) {
-    binder::Status ret = binder::Status::ok();
-
-    if (tempId == nullptr) {
-        ret = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                "Camera %s: Invalid template argument", mCameraIdStr.c_str());
-        return ret;
-    }
-    switch(templateId) {
-        case ICameraDeviceUser::TEMPLATE_PREVIEW:
-            *tempId = camera_request_template_t::CAMERA_TEMPLATE_PREVIEW;
-            break;
-        case ICameraDeviceUser::TEMPLATE_RECORD:
-            *tempId = camera_request_template_t::CAMERA_TEMPLATE_VIDEO_RECORD;
-            break;
-        case ICameraDeviceUser::TEMPLATE_STILL_CAPTURE:
-            *tempId = camera_request_template_t::CAMERA_TEMPLATE_STILL_CAPTURE;
-            break;
-        case ICameraDeviceUser::TEMPLATE_VIDEO_SNAPSHOT:
-            *tempId = camera_request_template_t::CAMERA_TEMPLATE_VIDEO_SNAPSHOT;
-            break;
-        case ICameraDeviceUser::TEMPLATE_ZERO_SHUTTER_LAG:
-            *tempId = camera_request_template_t::CAMERA_TEMPLATE_ZERO_SHUTTER_LAG;
-            break;
-        case ICameraDeviceUser::TEMPLATE_MANUAL:
-            *tempId = camera_request_template_t::CAMERA_TEMPLATE_MANUAL;
-            break;
-        default:
-            ret = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                    "Camera %s: Template ID %d is invalid or not supported",
-                    mCameraIdStr.c_str(), templateId);
-            return ret;
-    }
-
-    return ret;
-}
-
 const CameraMetadata &CameraDeviceClient::getStaticInfo(const std::string &cameraId) {
     if (mDevice->getId() == cameraId) {
         return mDevice->info();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 5dea3aa..b2c9626 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -312,10 +312,6 @@
             /*out*/SurfaceMap* surfaceMap, /*out*/Vector<int32_t>* streamIds,
             /*out*/int32_t*  currentStreamId);
 
-    // Utility method that maps AIDL request templates.
-    binder::Status mapRequestTemplate(int templateId,
-            camera_request_template_t* tempId /*out*/);
-
     // IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams
     KeyedVector<sp<IBinder>, StreamSurfaceId> mStreamMap;
 
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 01199af..983b2c1 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -35,6 +35,7 @@
 #include "binder/Status.h"
 #include "FrameProducer.h"
 #include "utils/IPCTransport.h"
+#include "utils/SessionConfigurationUtils.h"
 
 #include "CameraOfflineSessionBase.h"
 
@@ -42,17 +43,6 @@
 
 namespace camera3 {
 
-typedef enum camera_request_template {
-    CAMERA_TEMPLATE_PREVIEW = 1,
-    CAMERA_TEMPLATE_STILL_CAPTURE = 2,
-    CAMERA_TEMPLATE_VIDEO_RECORD = 3,
-    CAMERA_TEMPLATE_VIDEO_SNAPSHOT = 4,
-    CAMERA_TEMPLATE_ZERO_SHUTTER_LAG = 5,
-    CAMERA_TEMPLATE_MANUAL = 6,
-    CAMERA_TEMPLATE_COUNT,
-    CAMERA_VENDOR_TEMPLATE_START = 0x40000000
-} camera_request_template_t;
-
 typedef enum camera_stream_configuration_mode {
     CAMERA_STREAM_CONFIGURATION_NORMAL_MODE = 0,
     CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE = 1,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index adcb523..fbb5e1b 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -397,7 +397,7 @@
 
 status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
         const SessionConfiguration &configuration, bool overrideForPerfClass,
-        metadataGetter getMetadata, bool *status /*out*/) const {
+        bool checkSessionParams, bool *status /*out*/) const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
     auto deviceInfo = findDeviceInfoLocked(id);
     if (deviceInfo == nullptr) {
@@ -405,7 +405,41 @@
     }
 
     return deviceInfo->isSessionConfigurationSupported(configuration,
-            overrideForPerfClass, getMetadata, status);
+            overrideForPerfClass, checkSessionParams, status);
+}
+
+status_t  CameraProviderManager::createDefaultRequest(const std::string& cameraId,
+        camera_request_template_t templateId,
+        CameraMetadata* metadata) const {
+    ATRACE_CALL();
+    if (templateId <= 0 || templateId >= CAMERA_TEMPLATE_COUNT) {
+        return BAD_VALUE;
+    }
+
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    auto deviceInfo = findDeviceInfoLocked(cameraId);
+    if (deviceInfo == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+
+    camera_metadata_t *rawRequest;
+    status_t res = deviceInfo->createDefaultRequest(templateId,
+            &rawRequest);
+
+    if (res == BAD_VALUE) {
+        ALOGI("%s: template %d is not supported on this camera device",
+              __FUNCTION__, templateId);
+        return res;
+    } else if (res != OK) {
+        ALOGE("Unable to construct request template %d: %s (%d)",
+                templateId, strerror(-res), res);
+        return res;
+    }
+
+    set_camera_metadata_vendor_id(rawRequest, deviceInfo->mProviderTagid);
+    metadata->acquire(rawRequest);
+
+    return OK;
 }
 
 status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
@@ -1011,6 +1045,20 @@
     }
 }
 
+CameraMetadata CameraProviderManager::ProviderInfo::DeviceInfo3::deviceInfo(
+        const std::string &id) {
+    if (id.empty()) {
+        return mCameraCharacteristics;
+    } else {
+        if (mPhysicalCameraCharacteristics.find(id) != mPhysicalCameraCharacteristics.end()) {
+            return mPhysicalCameraCharacteristics.at(id);
+        } else {
+            ALOGE("%s: Invalid physical camera id %s", __FUNCTION__, id.c_str());
+            return mCameraCharacteristics;
+        }
+    }
+}
+
 SystemCameraKind CameraProviderManager::ProviderInfo::DeviceInfo3::getSystemCameraKind() {
     camera_metadata_entry_t entryCap;
     entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
@@ -1757,6 +1805,26 @@
     return res;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addSessionConfigQueryVersionTag() {
+    sp<ProviderInfo> parentProvider = mParentProvider.promote();
+    if (parentProvider == nullptr) {
+        return DEAD_OBJECT;
+    }
+
+    int versionCode = ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_UPSIDE_DOWN_CAKE;
+    IPCTransport ipcTransport = parentProvider->getIPCTransport();
+    int deviceVersion = HARDWARE_DEVICE_API_VERSION(mVersion.get_major(), mVersion.get_minor());
+    if (ipcTransport == IPCTransport::AIDL
+            && deviceVersion >= CAMERA_DEVICE_API_VERSION_1_3) {
+        versionCode = ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_VANILLA_ICE_CREAM;
+    }
+
+    auto& c = mCameraCharacteristics;
+    status_t res = c.update(ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION, &versionCode, 1);
+
+    return res;
+}
+
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::removeAvailableKeys(
         CameraMetadata& c, const std::vector<uint32_t>& keys, uint32_t keyTag) {
     status_t res = OK;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index fd04854..6142a71 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -87,6 +87,7 @@
 
 #define CAMERA_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0)
 #define CAMERA_DEVICE_API_VERSION_1_2 HARDWARE_DEVICE_API_VERSION(1, 2)
+#define CAMERA_DEVICE_API_VERSION_1_3 HARDWARE_DEVICE_API_VERSION(1, 3)
 #define CAMERA_DEVICE_API_VERSION_3_0 HARDWARE_DEVICE_API_VERSION(3, 0)
 #define CAMERA_DEVICE_API_VERSION_3_1 HARDWARE_DEVICE_API_VERSION(3, 1)
 #define CAMERA_DEVICE_API_VERSION_3_2 HARDWARE_DEVICE_API_VERSION(3, 2)
@@ -299,12 +300,20 @@
             int targetSdkVersion, bool *isSupported);
 
     std::vector<std::unordered_set<std::string>> getConcurrentCameraIds() const;
+
+    /**
+     * Create a default capture request metadata for a camera and a specific
+     * template.
+     */
+    status_t createDefaultRequest(const std::string& id,
+            camera3::camera_request_template_t templateId,
+            hardware::camera2::impl::CameraMetadataNative* request) const;
     /**
      * Check for device support of specific stream combination.
      */
     status_t isSessionConfigurationSupported(const std::string& id,
             const SessionConfiguration &configuration,
-            bool overrideForPerfClass, camera3::metadataGetter getMetadata,
+            bool overrideForPerfClass, bool checkSessionParams,
             bool *status /*out*/) const;
 
     /**
@@ -619,12 +628,17 @@
             virtual status_t isSessionConfigurationSupported(
                     const SessionConfiguration &/*configuration*/,
                     bool /*overrideForPerfClass*/,
-                    camera3::metadataGetter /*getMetadata*/,
+                    bool /*checkSessionParams*/,
                     bool * /*status*/) {
                 return INVALID_OPERATION;
             }
             virtual status_t filterSmallJpegSizes() = 0;
             virtual void notifyDeviceStateChange(int64_t /*newState*/) {}
+            virtual status_t createDefaultRequest(
+                    camera3::camera_request_template_t /*templateId*/,
+                    camera_metadata_t** /*metadata*/) {
+                return INVALID_OPERATION;
+            }
 
             DeviceInfo(const std::string& name, const metadata_vendor_id_t tagId,
                     const std::string &id, const hardware::hidl_version& version,
@@ -675,10 +689,6 @@
                     bool overrideToPortrait) override;
             virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
                     CameraMetadata *characteristics) const override;
-            virtual status_t isSessionConfigurationSupported(
-                    const SessionConfiguration &configuration, bool /*overrideForPerfClass*/,
-                    camera3::metadataGetter /*getMetadata*/,
-                    bool *status /*out*/) = 0;
             virtual status_t filterSmallJpegSizes() override;
             virtual void notifyDeviceStateChange(
                         int64_t newState) override;
@@ -712,6 +722,7 @@
             status_t addAutoframingTags();
             status_t addPreCorrectionActiveArraySize();
             status_t addReadoutTimestampTag(bool readoutTimestampSupported = true);
+            status_t addSessionConfigQueryVersionTag();
 
             static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,
                     android_pixel_format_t format,
@@ -736,6 +747,8 @@
                     std::vector<int64_t>* stallDurations,
                     const camera_metadata_entry& halStreamConfigs,
                     const camera_metadata_entry& halStreamDurations);
+
+            CameraMetadata deviceInfo(const std::string &id);
         };
     protected:
         std::string mType;
@@ -887,8 +900,6 @@
             std::vector<std::string>& systemCameraDeviceIds) const;
 
     status_t usbDeviceDetached(const std::string &usbDeviceId);
-    ndk::ScopedAStatus onAidlRegistration(const std::string& in_name,
-            const ::ndk::SpAIBinder& in_binder);
 
     static bool isVirtualCameraHalEnabled();
 };
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index c2b8bf4..a64c9d7 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -386,7 +386,7 @@
 std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
     AidlProviderInfo::initializeDeviceInfo(
         const std::string &name, const metadata_vendor_id_t tagId,
-        const std::string &id, uint16_t minorVersion) {
+        const std::string &id, uint16_t /*minorVersion*/) {
     ::ndk::ScopedAStatus status;
 
     auto cameraInterface = startDeviceInterface(name);
@@ -411,9 +411,18 @@
         conflictName = id;
     }
 
+    int32_t interfaceVersion = 0;
+    status = cameraInterface->getInterfaceVersion(&interfaceVersion);
+    if (!status.isOk()) {
+        ALOGE("%s: Unable to obtain interface version for camera device %s: %s", __FUNCTION__,
+                id.c_str(), status.getMessage());
+        return nullptr;
+    }
+
     return std::unique_ptr<DeviceInfo3>(
-        new AidlDeviceInfo3(name, tagId, id, minorVersion, HalToFrameworkResourceCost(resourceCost),
-                this, mProviderPublicCameraIds, cameraInterface));
+        new AidlDeviceInfo3(name, tagId, id, static_cast<uint16_t>(interfaceVersion),
+                HalToFrameworkResourceCost(resourceCost), this,
+                mProviderPublicCameraIds, cameraInterface));
 }
 
 status_t AidlProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
@@ -604,6 +613,14 @@
         mHasFlashUnit = false;
     }
 
+    if (flags::feature_combination_query()) {
+        res = addSessionConfigQueryVersionTag();
+        if (OK != res) {
+            ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+        }
+    }
+
     camera_metadata_entry entry =
             mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
     if (entry.count == 1) {
@@ -766,13 +783,24 @@
 
 status_t AidlProviderInfo::AidlDeviceInfo3::isSessionConfigurationSupported(
         const SessionConfiguration &configuration, bool overrideForPerfClass,
-        camera3::metadataGetter getMetadata, bool *status) {
+        bool checkSessionParams, bool *status) {
+
+    auto operatingMode = configuration.getOperatingMode();
+
+    auto res = SessionConfigurationUtils::checkOperatingMode(operatingMode,
+            mCameraCharacteristics, mId);
+    if (!res.isOk()) {
+        return UNKNOWN_ERROR;
+    }
 
     camera::device::StreamConfiguration streamConfiguration;
     bool earlyExit = false;
+    camera3::metadataGetter getMetadata = [this](const std::string &id,
+            bool /*overrideForPerfClass*/) {return this->deviceInfo(id);};
     auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
             mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata,
-            mPhysicalIds, streamConfiguration, overrideForPerfClass, &earlyExit);
+            mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid,
+            checkSessionParams, &earlyExit);
 
     if (!bRes.isOk()) {
         return UNKNOWN_ERROR;
@@ -790,8 +818,25 @@
         return DEAD_OBJECT;
     }
 
-    ::ndk::ScopedAStatus ret =
-        interface->isStreamCombinationSupported(streamConfiguration, status);
+    ::ndk::ScopedAStatus ret;
+    if (checkSessionParams) {
+        // Only interface version 1_3 or greater supports
+        // isStreamCombinationWIthSettingsSupported.
+        int deviceVersion = HARDWARE_DEVICE_API_VERSION(mVersion.get_major(), mVersion.get_minor());
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_1_3) {
+            ALOGI("%s: Camera device version (major %d, minor %d) doesn't support querying of "
+                    "session configuration!", __FUNCTION__, mVersion.get_major(),
+                    mVersion.get_minor());
+            return INVALID_OPERATION;
+        }
+        if (flags::feature_combination_query()) {
+            ret = interface->isStreamCombinationWithSettingsSupported(streamConfiguration, status);
+        } else {
+            return INVALID_OPERATION;
+        }
+    } else {
+        ret = interface->isStreamCombinationSupported(streamConfiguration, status);
+    }
     if (!ret.isOk()) {
         *status = false;
         ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage());
@@ -801,6 +846,60 @@
 
 }
 
+status_t AidlProviderInfo::AidlDeviceInfo3::createDefaultRequest(
+        camera3::camera_request_template_t templateId, camera_metadata_t** metadata) {
+    const std::shared_ptr<camera::device::ICameraDevice> interface =
+            startDeviceInterface();
+
+    if (interface == nullptr) {
+        return DEAD_OBJECT;
+    }
+
+    int deviceVersion = HARDWARE_DEVICE_API_VERSION(mVersion.get_major(), mVersion.get_minor());
+    if (deviceVersion < CAMERA_DEVICE_API_VERSION_1_3) {
+        ALOGI("%s: Camera device minor version 0x%x doesn't support creating "
+                " default request!", __FUNCTION__, mVersion.get_minor());
+        return INVALID_OPERATION;
+    }
+
+    aidl::android::hardware::camera::device::CameraMetadata request;
+
+    using aidl::android::hardware::camera::device::RequestTemplate;
+    RequestTemplate id;
+    status_t res = SessionConfigurationUtils::mapRequestTemplateToAidl(
+            templateId, &id);
+    if (res != OK) {
+        return res;
+    }
+
+    if (!flags::feature_combination_query()) {
+        return INVALID_OPERATION;
+    }
+
+    auto err = interface->constructDefaultRequestSettings(id, &request);
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+        return AidlProviderInfo::mapToStatusT(err);
+    }
+    const camera_metadata *r =
+            reinterpret_cast<const camera_metadata_t*>(request.metadata.data());
+    size_t expectedSize = request.metadata.size();
+    int ret = validate_camera_metadata_structure(r, &expectedSize);
+    if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+        *metadata = clone_camera_metadata(r);
+        if (*metadata == nullptr) {
+            ALOGE("%s: Unable to clone camera metadata received from HAL",
+                    __FUNCTION__);
+            res = UNKNOWN_ERROR;
+        }
+    } else {
+        ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+        res = UNKNOWN_ERROR;
+    }
+
+    return res;
+}
+
 status_t AidlProviderInfo::convertToAidlHALStreamCombinationAndCameraIdsLocked(
         const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
         const std::set<std::string>& perfClassPrimaryCameraIds,
@@ -840,7 +939,8 @@
                     cameraId, deviceInfo,
                     mManager->isCompositeJpegRDisabledLocked(cameraId), getMetadata,
                     physicalCameraIds, streamConfiguration,
-                    overrideForPerfClass, &shouldExit);
+                    overrideForPerfClass, mProviderTagid,
+                    /*checkSessionParams*/false, &shouldExit);
         if (!bStatus.isOk()) {
             ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
             return INVALID_OPERATION;
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
index 90bc627..cc5101a 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -107,8 +107,6 @@
 
     struct AidlDeviceInfo3 : public CameraProviderManager::ProviderInfo::DeviceInfo3 {
 
-        //TODO: fix init
-        const hardware::hidl_version mVersion = hardware::hidl_version{3, 2};
         std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
                 mSavedInterface = nullptr;
 
@@ -129,9 +127,13 @@
 
         virtual status_t isSessionConfigurationSupported(
                 const SessionConfiguration &/*configuration*/,
-                bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
+                bool overrideForPerfClass, bool checkSessionParams,
                 bool *status/*status*/);
 
+        virtual status_t createDefaultRequest(
+                    camera3::camera_request_template_t templateId,
+                    camera_metadata_t** metadata) override;
+
         std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
                 startDeviceInterface();
     };
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index e4bd503..d2643c1 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -853,13 +853,21 @@
 
 status_t HidlProviderInfo::HidlDeviceInfo3::isSessionConfigurationSupported(
         const SessionConfiguration &configuration, bool overrideForPerfClass,
-        metadataGetter getMetadata, bool *status) {
+        bool checkSessionParams, bool *status) {
+
+    if (checkSessionParams) {
+        // HIDL device doesn't support checking session parameters
+        return INVALID_OPERATION;
+    }
 
     hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
     bool earlyExit = false;
+    camera3::metadataGetter getMetadata = [this](const std::string &id,
+            bool /*overrideForPerfClass*/) {return this->deviceInfo(id);};
     auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
             mId, mCameraCharacteristics, getMetadata, mPhysicalIds,
-            configuration_3_7, overrideForPerfClass, &earlyExit);
+            configuration_3_7, overrideForPerfClass, mProviderTagid,
+            &earlyExit);
 
     if (!bRes.isOk()) {
         return UNKNOWN_ERROR;
@@ -961,7 +969,7 @@
                     cameraIdAndSessionConfig.mSessionConfiguration,
                     cameraId, deviceInfo, getMetadata,
                     physicalCameraIds, streamConfiguration,
-                    overrideForPerfClass, &shouldExit);
+                    overrideForPerfClass, mProviderTagid, &shouldExit);
         if (!bStatus.isOk()) {
             ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
             return INVALID_OPERATION;
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
index fa6f4d4..f53db7f 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -105,7 +105,7 @@
 
         virtual status_t isSessionConfigurationSupported(
                 const SessionConfiguration &/*configuration*/,
-                bool overrideForPerfClass, camera3::metadataGetter getMetadata,
+                bool overrideForPerfClass, bool checkSessionParams,
                 bool *status/*status*/);
         sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
     };
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 8006ee1..0a5b0c4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -75,6 +75,7 @@
 #include <tuple>
 
 using namespace android::camera3;
+using namespace android::camera3::SessionConfigurationUtils;
 using namespace android::hardware::camera;
 
 namespace flags = com::android::internal::camera::flags;
@@ -1365,62 +1366,52 @@
     return filterParamsAndConfigureLocked(sessionParams, operatingMode);
 }
 
-status_t Camera3Device::filterParamsAndConfigureLocked(const CameraMetadata& sessionParams,
+status_t Camera3Device::filterParamsAndConfigureLocked(const CameraMetadata& params,
         int operatingMode) {
-    //Filter out any incoming session parameters
-    const CameraMetadata params(sessionParams);
+    CameraMetadata filteredParams;
+    SessionConfigurationUtils::filterParameters(params, mDeviceInfo, mVendorTagId, filteredParams);
+
     camera_metadata_entry_t availableSessionKeys = mDeviceInfo.find(
             ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
-    CameraMetadata filteredParams(availableSessionKeys.count);
-    camera_metadata_t *meta = const_cast<camera_metadata_t *>(
-            filteredParams.getAndLock());
-    set_camera_metadata_vendor_id(meta, mVendorTagId);
-    filteredParams.unlock(meta);
-    if (availableSessionKeys.count > 0) {
-        bool rotateAndCropSessionKey = false;
-        bool autoframingSessionKey = false;
-        for (size_t i = 0; i < availableSessionKeys.count; i++) {
-            camera_metadata_ro_entry entry = params.find(
-                    availableSessionKeys.data.i32[i]);
-            if (entry.count > 0) {
-                filteredParams.update(entry);
+
+    bool rotateAndCropSessionKey = false;
+    bool autoframingSessionKey = false;
+    for (size_t i = 0; i < availableSessionKeys.count; i++) {
+        if (ANDROID_SCALER_ROTATE_AND_CROP == availableSessionKeys.data.i32[i]) {
+            rotateAndCropSessionKey = true;
+        }
+        if (ANDROID_CONTROL_AUTOFRAMING == availableSessionKeys.data.i32[i]) {
+            autoframingSessionKey = true;
+        }
+    }
+
+    if (rotateAndCropSessionKey || autoframingSessionKey) {
+        sp<CaptureRequest> request = new CaptureRequest();
+        PhysicalCameraSettings settingsList;
+        settingsList.metadata = filteredParams;
+        request->mSettingsList.push_back(settingsList);
+
+        if (rotateAndCropSessionKey) {
+            auto rotateAndCropEntry = filteredParams.find(ANDROID_SCALER_ROTATE_AND_CROP);
+            if (rotateAndCropEntry.count > 0 &&
+                    rotateAndCropEntry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+                request->mRotateAndCropAuto = true;
+            } else {
+                request->mRotateAndCropAuto = false;
             }
-            if (ANDROID_SCALER_ROTATE_AND_CROP == availableSessionKeys.data.i32[i]) {
-                rotateAndCropSessionKey = true;
-            }
-            if (ANDROID_CONTROL_AUTOFRAMING == availableSessionKeys.data.i32[i]) {
-                autoframingSessionKey = true;
+
+            overrideAutoRotateAndCrop(request, mOverrideToPortrait, mRotateAndCropOverride);
+        }
+
+        if (autoframingSessionKey) {
+            auto autoframingEntry = filteredParams.find(ANDROID_CONTROL_AUTOFRAMING);
+            if (autoframingEntry.count > 0 &&
+                    autoframingEntry.data.u8[0] == ANDROID_CONTROL_AUTOFRAMING_AUTO) {
+                overrideAutoframing(request, mAutoframingOverride);
             }
         }
 
-        if (rotateAndCropSessionKey || autoframingSessionKey) {
-            sp<CaptureRequest> request = new CaptureRequest();
-            PhysicalCameraSettings settingsList;
-            settingsList.metadata = filteredParams;
-            request->mSettingsList.push_back(settingsList);
-
-            if (rotateAndCropSessionKey) {
-                auto rotateAndCropEntry = filteredParams.find(ANDROID_SCALER_ROTATE_AND_CROP);
-                if (rotateAndCropEntry.count > 0 &&
-                        rotateAndCropEntry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
-                    request->mRotateAndCropAuto = true;
-                } else {
-                    request->mRotateAndCropAuto = false;
-                }
-
-                overrideAutoRotateAndCrop(request, mOverrideToPortrait, mRotateAndCropOverride);
-            }
-
-            if (autoframingSessionKey) {
-                auto autoframingEntry = filteredParams.find(ANDROID_CONTROL_AUTOFRAMING);
-                if (autoframingEntry.count > 0 &&
-                        autoframingEntry.data.u8[0] == ANDROID_CONTROL_AUTOFRAMING_AUTO) {
-                    overrideAutoframing(request, mAutoframingOverride);
-                }
-            }
-
-            filteredParams = request->mSettingsList.begin()->metadata;
-        }
+        filteredParams = request->mSettingsList.begin()->metadata;
     }
 
     return configureStreamsLocked(operatingMode, filteredParams);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index c90fad2..97475f0 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -851,33 +851,15 @@
     ATRACE_NAME("CameraAidlHal::constructDefaultRequestSettings");
     using aidl::android::hardware::camera::device::RequestTemplate;
     if (!valid()) return INVALID_OPERATION;
-    status_t res = OK;
 
     RequestTemplate id;
-    aidl::android::hardware::camera::device::CameraMetadata request;
-    switch (templateId) {
-        case CAMERA_TEMPLATE_PREVIEW:
-            id = RequestTemplate::PREVIEW;
-            break;
-        case CAMERA_TEMPLATE_STILL_CAPTURE:
-            id = RequestTemplate::STILL_CAPTURE;
-            break;
-        case CAMERA_TEMPLATE_VIDEO_RECORD:
-            id = RequestTemplate::VIDEO_RECORD;
-            break;
-        case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
-            id = RequestTemplate::VIDEO_SNAPSHOT;
-            break;
-        case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
-            id = RequestTemplate::ZERO_SHUTTER_LAG;
-            break;
-        case CAMERA_TEMPLATE_MANUAL:
-            id = RequestTemplate::MANUAL;
-            break;
-        default:
-            // Unknown template ID, or this HAL is too old to support it
-            return BAD_VALUE;
+    status_t res = SessionConfigurationUtils::mapRequestTemplateToAidl(
+            templateId, &id);
+    if (res != OK) {
+        return res;
     }
+
+    aidl::android::hardware::camera::device::CameraMetadata request;
     auto err = mAidlSession->constructDefaultRequestSettings(id, &request);
 
     if (!err.isOk()) {
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index efc58b4..9dd657c 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -49,7 +49,7 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.6",
         "android.hardware.camera.provider@2.7",
-        "android.hardware.camera.provider-V2-ndk",
+        "android.hardware.camera.provider-V3-ndk",
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index e9ecc86..5072edd 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -62,7 +62,7 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.6",
         "android.hardware.camera.provider@2.7",
-        "android.hardware.camera.provider-V2-ndk",
+        "android.hardware.camera.provider-V3-ndk",
         "libcameraservice",
         "libgmock",
         "libflagtest",
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index afc8b94..467707e 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -299,6 +299,16 @@
     ::ndk::ScopedAStatus getTorchStrengthLevel(int32_t*) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus constructDefaultRequestSettings(
+            ::aidl::android::hardware::camera::device::RequestTemplate,
+            ::aidl::android::hardware::camera::device::CameraMetadata*) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus isStreamCombinationWithSettingsSupported(
+            const ::aidl::android::hardware::camera::device::StreamConfiguration&,
+            bool*) override {
+        return ndk::ScopedAStatus::ok();
+    }
 };
 
 /**
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index f7257e3..3be8e15 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -34,6 +34,7 @@
 using android::camera3::OutputStreamInfo;
 using android::camera3::OutputStreamInfo;
 using android::hardware::camera2::ICameraDeviceUser;
+using aidl::android::hardware::camera::device::RequestTemplate;
 
 namespace android {
 namespace camera3 {
@@ -682,7 +683,8 @@
         bool isCompositeJpegRDisabled,
         metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
         aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
-        bool overrideForPerfClass, bool *earlyExit) {
+        bool overrideForPerfClass, metadata_vendor_id_t vendorTagId,
+        bool checkSessionParams, bool *earlyExit) {
     using SensorPixelMode = aidl::android::hardware::camera::metadata::SensorPixelMode;
     auto operatingMode = sessionConfiguration.getOperatingMode();
     binder::Status res = checkOperatingMode(operatingMode, deviceInfo,
@@ -875,6 +877,21 @@
             }
         }
     }
+
+    if (checkSessionParams) {
+        const CameraMetadata &deviceInfo = getMetadata(logicalCameraId,
+                /*overrideForPerfClass*/false);
+        CameraMetadata filteredParams;
+
+        filterParameters(sessionConfiguration.getSessionParameters(), deviceInfo,
+                vendorTagId, filteredParams);
+
+        camera_metadata_t* metadata = const_cast<camera_metadata_t*>(filteredParams.getAndLock());
+        uint8_t *metadataP = reinterpret_cast<uint8_t*>(metadata);
+        streamConfiguration.sessionParams.metadata.assign(metadataP,
+                metadataP + get_camera_metadata_size(metadata));
+    }
+
     return binder::Status::ok();
 }
 
@@ -1049,6 +1066,92 @@
     return targetSdkVersion >= SDK_VERSION_S && isPerfClassPrimaryCamera;
 }
 
+binder::Status mapRequestTemplateFromClient(const std::string& cameraId, int templateId,
+        camera_request_template_t* tempId /*out*/) {
+    binder::Status ret = binder::Status::ok();
+
+    if (tempId == nullptr) {
+        ret = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "Camera %s: Invalid template argument", cameraId.c_str());
+        return ret;
+    }
+    switch(templateId) {
+        case ICameraDeviceUser::TEMPLATE_PREVIEW:
+            *tempId = camera_request_template_t::CAMERA_TEMPLATE_PREVIEW;
+            break;
+        case ICameraDeviceUser::TEMPLATE_RECORD:
+            *tempId = camera_request_template_t::CAMERA_TEMPLATE_VIDEO_RECORD;
+            break;
+        case ICameraDeviceUser::TEMPLATE_STILL_CAPTURE:
+            *tempId = camera_request_template_t::CAMERA_TEMPLATE_STILL_CAPTURE;
+            break;
+        case ICameraDeviceUser::TEMPLATE_VIDEO_SNAPSHOT:
+            *tempId = camera_request_template_t::CAMERA_TEMPLATE_VIDEO_SNAPSHOT;
+            break;
+        case ICameraDeviceUser::TEMPLATE_ZERO_SHUTTER_LAG:
+            *tempId = camera_request_template_t::CAMERA_TEMPLATE_ZERO_SHUTTER_LAG;
+            break;
+        case ICameraDeviceUser::TEMPLATE_MANUAL:
+            *tempId = camera_request_template_t::CAMERA_TEMPLATE_MANUAL;
+            break;
+        default:
+            ret = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                    "Camera %s: Template ID %d is invalid or not supported",
+                    cameraId.c_str(), templateId);
+            return ret;
+    }
+
+    return ret;
+}
+
+status_t mapRequestTemplateToAidl(camera_request_template_t templateId,
+        RequestTemplate* id /*out*/) {
+    switch (templateId) {
+        case CAMERA_TEMPLATE_PREVIEW:
+            *id = RequestTemplate::PREVIEW;
+            break;
+        case CAMERA_TEMPLATE_STILL_CAPTURE:
+            *id = RequestTemplate::STILL_CAPTURE;
+            break;
+        case CAMERA_TEMPLATE_VIDEO_RECORD:
+            *id = RequestTemplate::VIDEO_RECORD;
+            break;
+        case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
+            *id = RequestTemplate::VIDEO_SNAPSHOT;
+            break;
+        case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
+            *id = RequestTemplate::ZERO_SHUTTER_LAG;
+            break;
+        case CAMERA_TEMPLATE_MANUAL:
+            *id = RequestTemplate::MANUAL;
+            break;
+        default:
+            // Unknown template ID, or this HAL is too old to support it
+            return BAD_VALUE;
+    }
+    return OK;
+}
+
+void filterParameters(const CameraMetadata& src, const CameraMetadata& deviceInfo,
+        int vendorTagId, CameraMetadata& dst) {
+    const CameraMetadata params(src);
+    camera_metadata_ro_entry_t availableSessionKeys = deviceInfo.find(
+            ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
+    CameraMetadata filteredParams(availableSessionKeys.count);
+    camera_metadata_t *meta = const_cast<camera_metadata_t *>(
+            filteredParams.getAndLock());
+    set_camera_metadata_vendor_id(meta, vendorTagId);
+    filteredParams.unlock(meta);
+    for (size_t i = 0; i < availableSessionKeys.count; i++) {
+        camera_metadata_ro_entry entry = params.find(
+                availableSessionKeys.data.i32[i]);
+        if (entry.count > 0) {
+            filteredParams.update(entry);
+        }
+    }
+    dst = std::move(filteredParams);
+}
+
 } // namespace SessionConfigurationUtils
 } // namespace camera3
 } // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 79d80ea..29e3eca 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -48,6 +48,17 @@
 namespace android {
 namespace camera3 {
 
+typedef enum camera_request_template {
+    CAMERA_TEMPLATE_PREVIEW = 1,
+    CAMERA_TEMPLATE_STILL_CAPTURE = 2,
+    CAMERA_TEMPLATE_VIDEO_RECORD = 3,
+    CAMERA_TEMPLATE_VIDEO_SNAPSHOT = 4,
+    CAMERA_TEMPLATE_ZERO_SHUTTER_LAG = 5,
+    CAMERA_TEMPLATE_MANUAL = 6,
+    CAMERA_TEMPLATE_COUNT,
+    CAMERA_VENDOR_TEMPLATE_START = 0x40000000
+} camera_request_template_t;
+
 typedef std::function<CameraMetadata (const std::string &, bool overrideForPerfClass)>
         metadataGetter;
 
@@ -144,7 +155,8 @@
     bool isCompositeJpegRDisabled, metadataGetter getMetadata,
     const std::vector<std::string> &physicalCameraIds,
     aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
-    bool overrideForPerfClass, bool *earlyExit);
+    bool overrideForPerfClass, metadata_vendor_id_t vendorTagId,
+    bool checkSessionParams, bool *earlyExit);
 
 StreamConfigurationPair getStreamConfigurationPair(const CameraMetadata &metadata);
 
@@ -157,6 +169,16 @@
         const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
         int32_t targetSdkVersion);
 
+// Utility method that maps AIDL request templates.
+binder::Status mapRequestTemplateFromClient(const std::string& cameraId, int templateId,
+        camera_request_template_t* tempId /*out*/);
+
+status_t mapRequestTemplateToAidl(camera_request_template_t templateId,
+        aidl::android::hardware::camera::device::RequestTemplate* tempId /*out*/);
+
+void filterParameters(const CameraMetadata& src, const CameraMetadata& deviceInfo,
+        int vendorTagId, CameraMetadata& dst);
+
 constexpr int32_t MAX_SURFACES_PER_STREAM = 4;
 
 constexpr int32_t ROUNDING_WIDTH_CAP = 1920;
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
index cf93d3b..bf8ea84 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
@@ -108,11 +108,12 @@
         const std::string &logicalCameraId, const CameraMetadata &deviceInfo,
         metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
         hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
-        bool overrideForPerfClass, bool *earlyExit) {
+        bool overrideForPerfClass, metadata_vendor_id_t vendorTagId, bool *earlyExit) {
     aidl::android::hardware::camera::device::StreamConfiguration aidlStreamConfiguration;
     auto ret = convertToHALStreamCombination(sessionConfiguration, logicalCameraId, deviceInfo,
             false /*isCompositeJpegRDisabled*/, getMetadata, physicalCameraIds,
-            aidlStreamConfiguration, overrideForPerfClass, earlyExit);
+            aidlStreamConfiguration, overrideForPerfClass, vendorTagId,
+            /*checkSessionParams*/false, earlyExit);
     if (!ret.isOk()) {
         return ret;
     }
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h
index eae2e30..bc37470 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h
@@ -37,7 +37,8 @@
         const std::string &cameraId, const CameraMetadata &deviceInfo,
         metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
         hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
-        bool overrideForPerfClass, bool *earlyExit);
+        bool overrideForPerfClass, metadata_vendor_id_t vendorTagId,
+        bool *earlyExit);
 
 // Utility function to convert a V3_7::StreamConfiguration to
 // V3_4::StreamConfiguration. Return false if the original V3_7 configuration cannot
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index 8d4a476..cb4e10f 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -27,7 +27,7 @@
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
         "android.hardware.camera.common-V1-ndk",
-        "android.hardware.camera.device-V3-ndk",
+        "android.hardware.camera.device-V2-ndk",
         "android.hardware.camera.metadata-V2-ndk",
         "android.hardware.camera.provider-V2-ndk",
         "libaidlcommonsupport",
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index f5fa16e..ec72ee3 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -143,6 +143,7 @@
           .setControlAwbRegions({kDefaultEmptyControlRegion})
           .setControlAeCompensationRange(0, 1)
           .setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
+          .setControlZoomRatioRange(/*min=*/1.0, /*max=*/1.0)
           .setMaxJpegSize(kMaxJpegSize)
           .setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
           .setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 8a2db1c..8621160 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -24,6 +24,7 @@
 #include <mutex>
 #include <thread>
 
+#include "GLES/gl.h"
 #include "VirtualCameraSessionContext.h"
 #include "aidl/android/hardware/camera/common/Status.h"
 #include "aidl/android/hardware/camera/device/BufferStatus.h"
@@ -271,9 +272,9 @@
     }
 
     auto status = streamConfig->format == PixelFormat::BLOB
-                      ? renderIntoBlobStreamBuffer(
-                            reqBuffer.getStreamId(), reqBuffer.getBufferId(),
-                            streamConfig->bufferSize, reqBuffer.getFence())
+                      ? renderIntoBlobStreamBuffer(reqBuffer.getStreamId(),
+                                                   reqBuffer.getBufferId(),
+                                                   reqBuffer.getFence())
                       : renderIntoImageStreamBuffer(reqBuffer.getStreamId(),
                                                     reqBuffer.getBufferId(),
                                                     reqBuffer.getFence());
@@ -354,17 +355,21 @@
 }
 
 ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoBlobStreamBuffer(
-    const int streamId, const int bufferId, const size_t bufferSize,
-    sp<Fence> fence) {
+    const int streamId, const int bufferId, sp<Fence> fence) {
   ALOGV("%s", __func__);
-  sp<GraphicBuffer> gBuffer = mEglSurfaceTexture->getCurrentBuffer();
-  if (gBuffer == nullptr) {
-    // Most probably nothing was yet written to input surface if we reached this.
-    ALOGE("%s: Cannot fetch most recent buffer from SurfaceTexture", __func__);
-    return cameraStatus(Status::INTERNAL_ERROR);
-  }
   std::shared_ptr<AHardwareBuffer> hwBuffer =
       mSessionContext.fetchHardwareBuffer(streamId, bufferId);
+  if (hwBuffer == nullptr) {
+    ALOGE("%s: Failed to fetch hardware buffer %d for streamId %d", __func__,
+          bufferId, streamId);
+    return cameraStatus(Status::INTERNAL_ERROR);
+  }
+
+  std::optional<Stream> stream = mSessionContext.getStreamConfig(streamId);
+  if (!stream.has_value()) {
+    ALOGE("%s, failed to fetch information about stream %d", __func__, streamId);
+    return cameraStatus(Status::INTERNAL_ERROR);
+  }
 
   AHardwareBuffer_Planes planes_info;
 
@@ -377,27 +382,36 @@
     return cameraStatus(Status::INTERNAL_ERROR);
   }
 
-  android_ycbcr ycbcr;
-  status_t status =
-      gBuffer->lockYCbCr(AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, &ycbcr);
-  ALOGV("Locked buffers");
-  if (status != NO_ERROR) {
-    AHardwareBuffer_unlock(hwBuffer.get(), nullptr);
-    ALOGE("%s: Failed to lock graphic buffer: %d", __func__, status);
-    return cameraStatus(Status::INTERNAL_ERROR);
-  }
+  sp<GraphicBuffer> gBuffer = mEglSurfaceTexture->getCurrentBuffer();
+  bool compressionSuccess = true;
+  if (gBuffer != nullptr) {
+    android_ycbcr ycbcr;
+    status_t status =
+        gBuffer->lockYCbCr(AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, &ycbcr);
+    ALOGV("Locked buffers");
+    if (status != NO_ERROR) {
+      AHardwareBuffer_unlock(hwBuffer.get(), nullptr);
+      ALOGE("%s: Failed to lock graphic buffer: %d", __func__, status);
+      return cameraStatus(Status::INTERNAL_ERROR);
+    }
 
-  bool success = compressJpeg(gBuffer->getWidth(), gBuffer->getHeight(), ycbcr,
-                              bufferSize, planes_info.planes[0].data);
+    compressionSuccess =
+        compressJpeg(gBuffer->getWidth(), gBuffer->getHeight(), ycbcr,
+                     stream->bufferSize, planes_info.planes[0].data);
 
-  status_t res = gBuffer->unlock();
-  if (res != NO_ERROR) {
-    ALOGE("Failed to unlock graphic buffer: %d", res);
+    status_t res = gBuffer->unlock();
+    if (res != NO_ERROR) {
+      ALOGE("Failed to unlock graphic buffer: %d", res);
+    }
+  } else {
+    compressionSuccess =
+        compressBlackJpeg(stream->width, stream->height, stream->bufferSize,
+                          planes_info.planes[0].data);
   }
   AHardwareBuffer_unlock(hwBuffer.get(), nullptr);
   ALOGV("Unlocked buffers");
-  return success ? ndk::ScopedAStatus::ok()
-                 : cameraStatus(Status::INTERNAL_ERROR);
+  return compressionSuccess ? ndk::ScopedAStatus::ok()
+                            : cameraStatus(Status::INTERNAL_ERROR);
 }
 
 ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoImageStreamBuffer(
@@ -435,7 +449,15 @@
   mEglDisplayContext->makeCurrent();
   framebuffer->beforeDraw();
 
-  mEglTextureProgram->draw(mEglSurfaceTexture->updateTexture());
+  if (mEglSurfaceTexture->getCurrentBuffer() == nullptr) {
+    // If there's no current buffer, nothing was written to the surface and
+    // texture is not initialized yet. Let's render the framebuffer black
+    // instead of rendering the texture.
+    glClearColor(0.0f, 0.5f, 0.5f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+  } else {
+    mEglTextureProgram->draw(mEglSurfaceTexture->updateTexture());
+  }
   framebuffer->afterDraw();
 
   const std::chrono::nanoseconds after =
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index 30de7c2..a4374e6 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -126,7 +126,6 @@
   // Always called on render thread.
   ndk::ScopedAStatus renderIntoBlobStreamBuffer(const int streamId,
                                                 const int bufferId,
-                                                const size_t bufferSize,
                                                 sp<Fence> fence = nullptr);
 
   // Render current image to the YCbCr buffer.
diff --git a/services/camera/virtualcamera/VirtualCameraSession.h b/services/camera/virtualcamera/VirtualCameraSession.h
index 8bf66bc..50962e5 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.h
+++ b/services/camera/virtualcamera/VirtualCameraSession.h
@@ -64,12 +64,6 @@
       std::vector<::aidl::android::hardware::camera::device::HalStream>*
           _aidl_return) override EXCLUDES(mLock);
 
-  ndk::ScopedAStatus configureStreamsV2(
-      const ::aidl::android::hardware::camera::device::StreamConfiguration&,
-      ::aidl::android::hardware::camera::device::ConfigureStreamsRet*) override {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-  };
-
   ndk::ScopedAStatus constructDefaultRequestSettings(
       ::aidl::android::hardware::camera::device::RequestTemplate in_type,
       ::aidl::android::hardware::camera::device::CameraMetadata* _aidl_return)
diff --git a/services/camera/virtualcamera/tests/EglUtilTest.cc b/services/camera/virtualcamera/tests/EglUtilTest.cc
index d387ebf..d0b7218 100644
--- a/services/camera/virtualcamera/tests/EglUtilTest.cc
+++ b/services/camera/virtualcamera/tests/EglUtilTest.cc
@@ -31,28 +31,12 @@
 namespace virtualcamera {
 namespace {
 
-using ::testing::Eq;
-using ::testing::NotNull;
+using ::testing::IsNull;
 
 constexpr int kWidth = 64;
 constexpr int kHeight = 64;
 constexpr char kGlExtYuvTarget[] = "GL_EXT_YUV_target";
 
-uint8_t getY(const android_ycbcr& ycbcr, const int x, const int y) {
-    uint8_t* yPtr = reinterpret_cast<uint8_t*>(ycbcr.y);
-    return *(yPtr + ycbcr.ystride * y + x);
-}
-
-uint8_t getCb(const android_ycbcr& ycbcr, const int x, const int y) {
-    uint8_t* cbPtr = reinterpret_cast<uint8_t*>(ycbcr.cb);
-    return *(cbPtr + ycbcr.cstride * (y / 2) + (x / 2) * ycbcr.chroma_step);
-}
-
-uint8_t getCr(const android_ycbcr& ycbcr, const int x, const int y) {
-    uint8_t* crPtr = reinterpret_cast<uint8_t*>(ycbcr.cr);
-    return *(crPtr + ycbcr.cstride * (y / 2) + (x / 2) * ycbcr.chroma_step);
-}
-
 TEST(EglDisplayContextTest, SuccessfulInitialization) {
   EglDisplayContext displayContext;
 
@@ -88,7 +72,7 @@
   EXPECT_TRUE(eglTextureProgram.isInitialized());
 }
 
-TEST_F(EglTest, EglSurfaceTextureBlackAfterInit) {
+TEST_F(EglTest, EglSurfaceCurrentBufferNullAfterInit) {
   if (!isGlExtensionSupported(kGlExtYuvTarget)) {
       GTEST_SKIP() << "Skipping test because of missing required GL extension " << kGlExtYuvTarget;
   }
@@ -97,24 +81,7 @@
   surfaceTexture.updateTexture();
   sp<GraphicBuffer> buffer = surfaceTexture.getCurrentBuffer();
 
-  ASSERT_THAT(buffer, NotNull());
-  const int width = buffer->getWidth();
-  const int height = buffer->getHeight();
-  ASSERT_THAT(width, Eq(kWidth));
-  ASSERT_THAT(height, Eq(kHeight));
-
-  android_ycbcr ycbcr;
-  status_t ret = buffer->lockYCbCr(AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, &ycbcr);
-  ASSERT_THAT(ret, Eq(NO_ERROR));
-  for (int i = 0; i < width; ++i) {
-      for (int j = 0; j < height; ++j) {
-          EXPECT_THAT(getY(ycbcr, i, j), Eq(0x00));
-          EXPECT_THAT(getCb(ycbcr, i, j), Eq(0x7f));
-          EXPECT_THAT(getCr(ycbcr, i, j), Eq(0x7f));
-      }
-  }
-
-  buffer->unlock();
+  EXPECT_THAT(buffer, IsNull());
 }
 
 }  // namespace
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 266d65a..5b479c0 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -31,26 +31,6 @@
 namespace companion {
 namespace virtualcamera {
 
-namespace {
-
-void submitBlackBufferYCbCr420(Surface& surface) {
-    ANativeWindow_Buffer buffer;
-
-    int ret = surface.lock(&buffer, nullptr);
-    if (ret != NO_ERROR) {
-        ALOGE("%s: Cannot lock output surface: %d", __func__, ret);
-        return;
-    }
-    uint8_t* data = reinterpret_cast<uint8_t*>(buffer.bits);
-    const int yPixNr = buffer.width * buffer.height;
-    const int uvPixNr = (buffer.width / 2) * (buffer.height / 2);
-    memset(data, 0x00, yPixNr);
-    memset(data + yPixNr, 0x7f, 2 * uvPixNr);
-    surface.unlockAndPost();
-}
-
-}  // namespace
-
 EglSurfaceTexture::EglSurfaceTexture(const uint32_t width, const uint32_t height)
     : mWidth(width), mHeight(height) {
   glGenTextures(1, &mTextureId);
@@ -67,14 +47,6 @@
   mGlConsumer->setDefaultBufferFormat(AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420);
 
   mSurface = sp<Surface>::make(mBufferProducer);
-  // Submit black buffer to the surface to make sure there's input buffer
-  // to process in case capture request comes before client writes something
-  // to the surface.
-  //
-  // Note that if the client does write something before capture request is
-  // processed (& updateTexture is called), this black buffer will be
-  // skipped (and recycled).
-  submitBlackBufferYCbCr420(*mSurface);
 }
 
 EglSurfaceTexture::~EglSurfaceTexture() {
diff --git a/services/camera/virtualcamera/util/JpegUtil.cc b/services/camera/virtualcamera/util/JpegUtil.cc
index 6f10376..2b19c13 100644
--- a/services/camera/virtualcamera/util/JpegUtil.cc
+++ b/services/camera/virtualcamera/util/JpegUtil.cc
@@ -20,6 +20,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <vector>
 
 #include "android/hardware_buffer.h"
 #include "jpeglib.h"
@@ -37,10 +38,9 @@
 
 class LibJpegContext {
  public:
-  LibJpegContext(int width, int height, const android_ycbcr& ycbcr,
-                 const size_t outBufferSize, void* outBuffer)
-      : mYCbCr(ycbcr),
-        mWidth(width),
+  LibJpegContext(int width, int height, const size_t outBufferSize,
+                 void* outBuffer)
+      : mWidth(width),
         mHeight(height),
         mDstBufferSize(outBufferSize),
         mDstBuffer(outBuffer) {
@@ -94,15 +94,15 @@
     mCompressStruct.comp_info[2].v_samp_factor = 1;
   }
 
-  bool compress() {
+  bool compress(const android_ycbcr& ycbr) {
     // Prepare arrays of pointers to scanlines of each plane.
     std::vector<JSAMPROW> yLines(mHeight);
     std::vector<JSAMPROW> cbLines(mHeight / 2);
     std::vector<JSAMPROW> crLines(mHeight / 2);
 
-    uint8_t* y = static_cast<uint8_t*>(mYCbCr.y);
-    uint8_t* cb = static_cast<uint8_t*>(mYCbCr.cb);
-    uint8_t* cr = static_cast<uint8_t*>(mYCbCr.cr);
+    uint8_t* y = static_cast<uint8_t*>(ycbr.y);
+    uint8_t* cb = static_cast<uint8_t*>(ycbr.cb);
+    uint8_t* cr = static_cast<uint8_t*>(ycbr.cr);
 
     // Since UV samples might be interleaved (semiplanar) we need to copy
     // them to separate planes, since libjpeg doesn't directly
@@ -115,20 +115,59 @@
     for (int i = 0; i < c_samples; ++i) {
       cb_plane[i] = *cb;
       cr_plane[i] = *cr;
-      cb += mYCbCr.chroma_step;
-      cr += mYCbCr.chroma_step;
+      cb += ycbr.chroma_step;
+      cr += ycbr.chroma_step;
     }
 
     // Collect pointers to individual scanline of each plane.
     for (int i = 0; i < mHeight; ++i) {
-      yLines[i] = y + i * mYCbCr.ystride;
+      yLines[i] = y + i * ycbr.ystride;
     }
     for (int i = 0; i < (mHeight / 2); ++i) {
       cbLines[i] = cb_plane.data() + i * (mWidth / 2);
       crLines[i] = cr_plane.data() + i * (mWidth / 2);
     }
 
-    // Perform actual compression.
+    return compress(yLines, cbLines, crLines);
+  }
+
+  bool compressBlackImage() {
+    // We only really need to prepare one scanline for Y and one shared scanline
+    // for Cb & Cr.
+    std::vector<uint8_t> yLine(mWidth, 0);
+    std::vector<uint8_t> chromaLine(mWidth / 2, 0xff / 2);
+
+    std::vector<JSAMPROW> yLines(mHeight, yLine.data());
+    std::vector<JSAMPROW> cLines(mHeight / 2, chromaLine.data());
+
+    return compress(yLines, cLines, cLines);
+  }
+
+ private:
+  void setSuccess(const boolean success) {
+    mSuccess = success;
+  }
+
+  void initDestination() {
+    mDestinationMgr.next_output_byte = reinterpret_cast<JOCTET*>(mDstBuffer);
+    mDestinationMgr.free_in_buffer = mDstBufferSize;
+    ALOGV("%s:%d jpeg start: %p [%zu]", __FUNCTION__, __LINE__, mDstBuffer,
+          mDstBufferSize);
+  }
+
+  void termDestination() {
+    mEncodedSize = mDstBufferSize - mDestinationMgr.free_in_buffer;
+    ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, mEncodedSize);
+  }
+
+  // Perform actual compression.
+  //
+  // Takes vector of pointers to Y / Cb / Cr scanlines as an input. Length of
+  // each vector needs to correspond to height of corresponding plane.
+  //
+  // Returns true if compression is successful, false otherwise.
+  bool compress(std::vector<JSAMPROW>& yLines, std::vector<JSAMPROW>& cbLines,
+                std::vector<JSAMPROW>& crLines) {
     jpeg_start_compress(&mCompressStruct, TRUE);
 
     while (mCompressStruct.next_scanline < mCompressStruct.image_height) {
@@ -149,23 +188,6 @@
     return mSuccess;
   }
 
- private:
-  void setSuccess(const boolean success) {
-    mSuccess = success;
-  }
-
-  void initDestination() {
-    mDestinationMgr.next_output_byte = reinterpret_cast<JOCTET*>(mDstBuffer);
-    mDestinationMgr.free_in_buffer = mDstBufferSize;
-    ALOGV("%s:%d jpeg start: %p [%zu]", __FUNCTION__, __LINE__, mDstBuffer,
-          mDstBufferSize);
-  }
-
-  void termDestination() {
-    mEncodedSize = mDstBufferSize - mDestinationMgr.free_in_buffer;
-    ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, mEncodedSize);
-  }
-
   // === libjpeg callbacks below ===
 
   static void onOutputError(j_common_ptr cinfo) {
@@ -195,9 +217,6 @@
   jpeg_error_mgr mErrorMgr;
   jpeg_destination_mgr mDestinationMgr;
 
-  // Layout of the input image.
-  android_ycbcr mYCbCr;
-
   // Dimensions of the input image.
   int mWidth;
   int mHeight;
@@ -216,11 +235,15 @@
 
 }  // namespace
 
-// Returns true if the EGL is in an error state and logs the error.
 bool compressJpeg(int width, int height, const android_ycbcr& ycbcr,
                   size_t outBufferSize, void* outBuffer) {
-  return LibJpegContext(width, height, ycbcr, outBufferSize, outBuffer)
-      .compress();
+  return LibJpegContext(width, height, outBufferSize, outBuffer).compress(ycbcr);
+}
+
+bool compressBlackJpeg(int width, int height, size_t outBufferSize,
+                       void* outBuffer) {
+  return LibJpegContext(width, height, outBufferSize, outBuffer)
+      .compressBlackImage();
 }
 
 }  // namespace virtualcamera
diff --git a/services/camera/virtualcamera/util/JpegUtil.h b/services/camera/virtualcamera/util/JpegUtil.h
index 8bff008..c44d0a8 100644
--- a/services/camera/virtualcamera/util/JpegUtil.h
+++ b/services/camera/virtualcamera/util/JpegUtil.h
@@ -27,9 +27,15 @@
 namespace virtualcamera {
 
 // Jpeg-compress image into the output buffer.
+// Returns true if the compression was successful, false otherwise.
 bool compressJpeg(int width, int height, const android_ycbcr& ycbcr,
                   size_t outBufferSize, void* outBuffer);
 
+// Jpeg-compress all-black image into the output buffer.
+// Returns true if the compression was successful, false otherwise.
+bool compressBlackJpeg(int width, int height, size_t outBufferSize,
+                       void* outBuffer);
+
 }  // namespace virtualcamera
 }  // namespace companion
 }  // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataBuilder.cc b/services/camera/virtualcamera/util/MetadataBuilder.cc
index b3b1a26..92a48b9 100644
--- a/services/camera/virtualcamera/util/MetadataBuilder.cc
+++ b/services/camera/virtualcamera/util/MetadataBuilder.cc
@@ -233,6 +233,12 @@
   return *this;
 }
 
+MetadataBuilder& MetadataBuilder::setControlZoomRatioRange(const float min,
+                                                           const float max) {
+  mEntryMap[ANDROID_CONTROL_ZOOM_RATIO_RANGE] = std::vector<float>({min, max});
+  return *this;
+}
+
 MetadataBuilder& MetadataBuilder::setSensorActiveArraySize(int x0, int y0,
                                                            int x1, int y1) {
   mEntryMap[ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE] =
diff --git a/services/camera/virtualcamera/util/MetadataBuilder.h b/services/camera/virtualcamera/util/MetadataBuilder.h
index 2124398..d992d31 100644
--- a/services/camera/virtualcamera/util/MetadataBuilder.h
+++ b/services/camera/virtualcamera/util/MetadataBuilder.h
@@ -151,6 +151,9 @@
   // See ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM in CameraMetadataTag.aidl.
   MetadataBuilder& setAvailableMaxDigitalZoom(const float maxZoom);
 
+  // See ANDROID_CONTROL_ZOOM_RATIO_RANGE in CameraMetadataTag.aidl.
+  MetadataBuilder& setControlZoomRatioRange(float min, float max);
+
   // A list of all keys that the camera device has available to use with
   // CaptureRequest.
   //
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index cd3b75a..3d4ab34 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -110,7 +110,7 @@
     private:
         mutable std::mutex                              mLock;
         const pid_t                                     mProcessId;
-        std::set<android::sp<AAudioServiceStreamBase>>  mStreams;
+        std::set<android::sp<AAudioServiceStreamBase>>  mStreams GUARDED_BY(mLock);
         // hold onto binder to receive death notifications
         android::sp<IBinder>                            mBinder;
         bool                                            mExclusiveEnabled = true;
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 1d38d26..cddc261 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -58,18 +58,25 @@
      * @param sharingMode
      * @return endpoint or null
      */
-    android::sp<AAudioServiceEndpoint> openEndpoint(android::AAudioService &audioService,
-                                        const aaudio::AAudioStreamRequest &request);
+    android::sp<AAudioServiceEndpoint> openEndpoint(
+            android::AAudioService &audioService,
+            const aaudio::AAudioStreamRequest &request)
+            EXCLUDES(mExclusiveLock, mSharedLock);
 
-    void closeEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint);
+    void closeEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint)
+            EXCLUDES(mExclusiveLock, mSharedLock);;
 
 private:
-    android::sp<AAudioServiceEndpoint> openExclusiveEndpoint(android::AAudioService &aaudioService,
-                                                 const aaudio::AAudioStreamRequest &request,
-                                                 sp<AAudioServiceEndpoint> &endpointToSteal);
+    android::sp<AAudioServiceEndpoint> openExclusiveEndpoint(
+            android::AAudioService &aaudioService,
+            const aaudio::AAudioStreamRequest &request,
+            sp<AAudioServiceEndpoint> &endpointToSteal)
+            EXCLUDES(mExclusiveLock);
 
-    android::sp<AAudioServiceEndpoint> openSharedEndpoint(android::AAudioService &aaudioService,
-                                              const aaudio::AAudioStreamRequest &request);
+    android::sp<AAudioServiceEndpoint> openSharedEndpoint(
+            android::AAudioService &aaudioService,
+            const aaudio::AAudioStreamRequest &request)
+            EXCLUDES(mSharedLock);
 
     android::sp<AAudioServiceEndpoint> findExclusiveEndpoint_l(
             const AAudioStreamConfiguration& configuration)
@@ -77,7 +84,8 @@
 
     android::sp<AAudioServiceEndpointShared> findSharedEndpoint_l(
             const AAudioStreamConfiguration& configuration)
-            REQUIRES(mSharedLock);
+            REQUIRES(mSharedLock)
+            EXCLUDES(mExclusiveLock);
 
     void closeExclusiveEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint);
     void closeSharedEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint);
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index dff571b..6de95e0 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -55,9 +55,11 @@
      */
     virtual void close() = 0;
 
-    aaudio_result_t registerStream(const android::sp<AAudioServiceStreamBase>& stream);
+    aaudio_result_t registerStream(const android::sp<AAudioServiceStreamBase>& stream)
+            EXCLUDES(mLockStreams);
 
-    aaudio_result_t unregisterStream(const android::sp<AAudioServiceStreamBase>& stream);
+    aaudio_result_t unregisterStream(const android::sp<AAudioServiceStreamBase>& stream)
+            EXCLUDES(mLockStreams);
 
     virtual aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
                                         audio_port_handle_t *clientHandle) = 0;
@@ -148,9 +150,11 @@
      * @param portHandle
      * @return return true if a stream with the given portHandle is registered
      */
-    bool                     isStreamRegistered(audio_port_handle_t portHandle);
+    bool                     isStreamRegistered(audio_port_handle_t portHandle)
+                                    EXCLUDES(mLockStreams);
 
-    std::vector<android::sp<AAudioServiceStreamBase>> disconnectRegisteredStreams();
+    std::vector<android::sp<AAudioServiceStreamBase>> disconnectRegisteredStreams()
+            EXCLUDES(mLockStreams);
 
     mutable std::mutex       mLockStreams;
     std::vector<android::sp<AAudioServiceStreamBase>> mRegisteredStreams
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index f19005c..eaa578c 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -19,7 +19,6 @@
 
 #include <atomic>
 #include <functional>
-#include <mutex>
 #include <vector>
 
 #include "client/AudioStreamInternal.h"
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.h b/services/oboeservice/AAudioServiceEndpointPlay.h
index 160a1de..704502e 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.h
+++ b/services/oboeservice/AAudioServiceEndpointPlay.h
@@ -19,7 +19,6 @@
 
 #include <atomic>
 #include <functional>
-#include <mutex>
 #include <vector>
 
 #include "client/AudioStreamInternal.h"
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 0efb227..2c73953 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -18,7 +18,6 @@
 #define AAUDIO_SERVICE_ENDPOINT_SHARED_H
 
 #include <atomic>
-#include <mutex>
 
 #include <android-base/thread_annotations.h>
 
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 8f51ce4..d5061b3 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -76,7 +76,8 @@
     /**
      * Open the device.
      */
-    virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request) = 0;
+    virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request)
+            EXCLUDES(mUpMessageQueueLock);
 
     // We log the CLOSE from the close() method. We needed this separate method to log the OPEN
     // because we had to wait until we generated the handle.
@@ -269,7 +270,8 @@
 
         AudioEndpointParcelable* mParcelable;
     };
-    aaudio_result_t getDescription_l(AudioEndpointParcelable* parcelable) REQUIRES(mLock);
+    aaudio_result_t getDescription_l(AudioEndpointParcelable* parcelable)
+            REQUIRES(mLock) EXCLUDES(mUpMessageQueueLock);
 
     void setState(aaudio_stream_state_t state);
 
@@ -279,7 +281,8 @@
      */
     virtual aaudio_result_t startDevice();
 
-    aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
+    aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command)
+            EXCLUDES(mUpMessageQueueLock);
 
     aaudio_result_t sendCurrentTimestamp_l() REQUIRES(mLock);
 
@@ -342,7 +345,7 @@
     pid_t                   mRegisteredClientThread = ILLEGAL_THREAD_ID;
 
     std::mutex              mUpMessageQueueLock;
-    std::shared_ptr<SharedRingBuffer> mUpMessageQueue;
+    std::shared_ptr<SharedRingBuffer> mUpMessageQueue PT_GUARDED_BY(mUpMessageQueueLock);
 
     enum : int32_t {
         START,
@@ -402,7 +405,7 @@
     /**
      * @return true if the queue is getting full.
      */
-    bool isUpMessageQueueBusy();
+    bool isUpMessageQueueBusy() EXCLUDES(mUpMessageQueueLock);
 
     aaudio_handle_t         mHandle = -1;
     bool                    mFlowing = false;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index db3c8d0..42032d7 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -49,7 +49,8 @@
                             bool inService);
     ~AAudioServiceStreamMMAP() override = default;
 
-    aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
+    aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override
+            EXCLUDES(mUpMessageQueueLock);
 
     aaudio_result_t startClient(const android::AudioClient& client,
                                 const audio_attributes_t *attr,
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 0b2513a..c6b74e1 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -50,7 +50,8 @@
 
     std::string dump() const override;
 
-    aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
+    aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override
+            EXCLUDES(mUpMessageQueueLock);
 
     void writeDataIfRoom(int64_t mmapFramesRead, const void *buffer, int32_t numFrames);
 
@@ -107,7 +108,7 @@
 
 private:
 
-    std::shared_ptr<SharedRingBuffer> mAudioDataQueue GUARDED_BY(audioDataQueueLock);
+    std::shared_ptr<SharedRingBuffer> mAudioDataQueue PT_GUARDED_BY(audioDataQueueLock);
 
     std::atomic<int64_t>     mTimestampPositionOffset;
     std::atomic<int32_t>     mXRunCount;
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
index 99f4b6c..51a783d 100644
--- a/services/oboeservice/AAudioStreamTracker.h
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -37,7 +37,7 @@
      * @param streamHandle
      * @return number of streams removed
      */
-    int32_t removeStreamByHandle(aaudio_handle_t streamHandle);
+    int32_t removeStreamByHandle(aaudio_handle_t streamHandle) EXCLUDES(mHandleLock);
 
     /**
      * Look up a stream based on the handle.
@@ -46,7 +46,7 @@
      * @return strong pointer to the stream if found, or nullptr
      */
     android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(
-            aaudio_handle_t streamHandle);
+            aaudio_handle_t streamHandle) EXCLUDES(mHandleLock);
 
     /**
      * Look up a stream based on the AudioPolicy portHandle.
@@ -56,7 +56,7 @@
      * @return strong pointer to the stream if found, or nullptr
      */
     android::sp<aaudio::AAudioServiceStreamBase> findStreamByPortHandle(
-            audio_port_handle_t portHandle);
+            audio_port_handle_t portHandle) EXCLUDES(mHandleLock);
 
     /**
      * Store a strong pointer to the stream and return a unique handle for future reference.
@@ -64,7 +64,8 @@
      * @param serviceStream
      * @return handle for identifying the stream
      */
-    aaudio_handle_t addStreamForHandle(const android::sp<AAudioServiceStreamBase>& serviceStream);
+    aaudio_handle_t addStreamForHandle(const android::sp<AAudioServiceStreamBase>& serviceStream)
+            EXCLUDES(mHandleLock);
 
     /**
      * @return string that can be added to dumpsys