Merge "Update VmaCallbacks to return bool" into main
diff --git a/common/hal/aidl_service/Android.bp b/common/hal/aidl_service/Android.bp
index 722d3fd..4872360 100644
--- a/common/hal/aidl_service/Android.bp
+++ b/common/hal/aidl_service/Android.bp
@@ -90,12 +90,9 @@
     ],
     compile_multilib: "first",
     shared_libs: [
-        "android.hardware.camera.device-V2-ndk",
+        "android.hardware.camera.device-V3-ndk",
         "android.hardware.camera.common-V1-ndk",
-        "android.hardware.camera.provider-V2-ndk",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.camera.provider-V3-ndk",
         "android.hardware.thermal-V1-ndk",
         "libbinder_ndk",
         "libbase",
@@ -106,6 +103,7 @@
         "libgooglecamerahalutils",
         "libhidlbase",
         "liblog",
+        "libui",
         "libutils",
         "lib_profiler",
     ],
diff --git a/common/hal/aidl_service/aidl_camera_device.cc b/common/hal/aidl_service/aidl_camera_device.cc
index 9d6c869..a086897 100644
--- a/common/hal/aidl_service/aidl_camera_device.cc
+++ b/common/hal/aidl_service/aidl_camera_device.cc
@@ -162,6 +162,43 @@
   return ScopedAStatus::ok();
 }
 
+ScopedAStatus AidlCameraDevice::constructDefaultRequestSettings(
+    RequestTemplate /*requestTemplate*/, CameraMetadata* requestSettings) {
+  if (requestSettings == nullptr) {
+    return ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
+  }
+  return ScopedAStatus::fromServiceSpecificError(
+      static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED));
+}
+
+ScopedAStatus AidlCameraDevice::isStreamCombinationWithSettingsSupported(
+    const StreamConfiguration& /*streamConfiguration*/, bool* supported) {
+  if (supported == nullptr) {
+    return ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
+  }
+  return ScopedAStatus::fromServiceSpecificError(
+      static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED));
+}
+
+ScopedAStatus AidlCameraDevice::getSessionCharacteristics(
+    const StreamConfiguration& session_config,
+    CameraMetadata* characteristics_ret) {
+  // Temporary check to make sure session configuration is valid.
+  // As a mock implementation, we are just returning the camera characteristics
+  // for now.
+  google_camera_hal::StreamConfiguration stream_config;
+  status_t res =
+      aidl_utils::ConvertToHalStreamConfig(session_config, &stream_config);
+  if (res != OK) {
+    ALOGE("%s: ConvertToHalStreamConfig fail", __FUNCTION__);
+    return ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(Status::INTERNAL_ERROR));
+  }
+  return getCameraCharacteristics(characteristics_ret);
+}
+
 ScopedAStatus AidlCameraDevice::getPhysicalCameraCharacteristics(
     const std::string& physicalCameraId, CameraMetadata* characteristics_ret) {
   if (characteristics_ret == nullptr) {
@@ -255,7 +292,7 @@
   google_camera_hal::StreamConfiguration stream_config;
   status_t res = aidl_utils::ConvertToHalStreamConfig(streams, &stream_config);
   if (res != OK) {
-    ALOGE("%s: ConverToHalStreamConfig fail", __FUNCTION__);
+    ALOGE("%s: ConvertToHalStreamConfig fail", __FUNCTION__);
     return ScopedAStatus::fromServiceSpecificError(
         static_cast<int32_t>(Status::INTERNAL_ERROR));
   }
diff --git a/common/hal/aidl_service/aidl_camera_device.h b/common/hal/aidl_service/aidl_camera_device.h
index 86b7263..ccfaea2 100644
--- a/common/hal/aidl_service/aidl_camera_device.h
+++ b/common/hal/aidl_service/aidl_camera_device.h
@@ -36,6 +36,7 @@
 using aidl::android::hardware::camera::device::ICameraDeviceCallback;
 using aidl::android::hardware::camera::device::ICameraDeviceSession;
 using aidl::android::hardware::camera::device::ICameraInjectionSession;
+using aidl::android::hardware::camera::device::RequestTemplate;
 using aidl::android::hardware::camera::device::StreamConfiguration;
 using ::android::hardware::camera::implementation::AidlProfiler;
 using ndk::ScopedAStatus;
@@ -86,6 +87,16 @@
 
   ScopedAStatus getTorchStrengthLevel(int32_t* strength_level) override;
 
+  ScopedAStatus constructDefaultRequestSettings(
+      RequestTemplate requestTemplate, CameraMetadata* requestSettings) override;
+
+  ScopedAStatus isStreamCombinationWithSettingsSupported(
+      const StreamConfiguration& streamConfiguration, bool* supported) override;
+
+  ScopedAStatus getSessionCharacteristics(
+      const StreamConfiguration& session_config,
+      CameraMetadata* characteristics) override;
+
   // End of override functions in ICameraDevice
   AidlCameraDevice() = default;
 
diff --git a/common/hal/aidl_service/aidl_camera_device_session.cc b/common/hal/aidl_service/aidl_camera_device_session.cc
index ed4978e..13cd520 100644
--- a/common/hal/aidl_service/aidl_camera_device_session.cc
+++ b/common/hal/aidl_service/aidl_camera_device_session.cc
@@ -26,9 +26,11 @@
 #include <cutils/trace.h>
 #include <log/log.h>
 #include <malloc.h>
+#include <ui/GraphicBufferMapper.h>
 #include <utils/Trace.h>
 
 #include "aidl_profiler.h"
+#include "aidl_thermal_utils.h"
 #include "aidl_utils.h"
 namespace android {
 namespace hardware {
@@ -46,6 +48,7 @@
 using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
 using ::aidl::android::hardware::camera::device::CaptureRequest;
 using ::aidl::android::hardware::camera::device::CaptureResult;
+using ::aidl::android::hardware::camera::device::ConfigureStreamsRet;
 using ::aidl::android::hardware::camera::device::HalStream;
 using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
 using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
@@ -98,20 +101,8 @@
     return;
   }
 
-  {
-    std::lock_guard<std::mutex> pending_lock(pending_first_frame_buffers_mutex_);
-    if (!hal_result->output_buffers.empty() &&
-        num_pending_first_frame_buffers_ > 0 &&
-        first_request_frame_number_ == hal_result->frame_number) {
-      num_pending_first_frame_buffers_ -= hal_result->output_buffers.size();
-      if (num_pending_first_frame_buffers_ == 0) {
-        ALOGI("%s: First frame done", __FUNCTION__);
-        aidl_profiler_->FirstFrameEnd();
-        ATRACE_ASYNC_END("first_frame", 0);
-        ATRACE_ASYNC_END("switch_mode", 0);
-      }
-    }
-  }
+  TryLogFirstFrameDone(*hal_result, __FUNCTION__);
+
   for (auto& buffer : hal_result->output_buffers) {
     aidl_profiler_->ProfileFrameRate("Stream " +
                                      std::to_string(buffer.stream_id));
@@ -134,6 +125,44 @@
   }
 }
 
+void AidlCameraDeviceSession::ProcessBatchCaptureResult(
+    std::vector<std::unique_ptr<google_camera_hal::CaptureResult>> hal_results) {
+  std::shared_lock lock(aidl_device_callback_lock_);
+  if (aidl_device_callback_ == nullptr) {
+    ALOGE("%s: aidl_device_callback_ is nullptr", __FUNCTION__);
+    return;
+  }
+  int batch_size = hal_results.size();
+  std::vector<CaptureResult> aidl_results(batch_size);
+  for (size_t i = 0; i < hal_results.size(); ++i) {
+    std::unique_ptr<google_camera_hal::CaptureResult>& hal_result =
+        hal_results[i];
+    auto& aidl_result = aidl_results[i];
+
+    TryLogFirstFrameDone(*hal_result, __FUNCTION__);
+
+    for (auto& buffer : hal_result->output_buffers) {
+      aidl_profiler_->ProfileFrameRate("Stream " +
+                                       std::to_string(buffer.stream_id));
+    }
+
+    status_t res = aidl_utils::ConvertToAidlCaptureResult(
+        result_metadata_queue_.get(), std::move(hal_result), &aidl_result);
+    if (res != OK) {
+      ALOGE("%s: Converting to AIDL result failed: %s(%d)", __FUNCTION__,
+            strerror(-res), res);
+      return;
+    }
+  }
+
+  auto aidl_res = aidl_device_callback_->processCaptureResult(aidl_results);
+  if (!aidl_res.isOk()) {
+    ALOGE("%s: processCaptureResult transaction failed: %s.", __FUNCTION__,
+          aidl_res.getMessage());
+    return;
+  }
+}
+
 void AidlCameraDeviceSession::NotifyHalMessage(
     const google_camera_hal::NotifyMessage& hal_message) {
   std::shared_lock lock(aidl_device_callback_lock_);
@@ -250,21 +279,11 @@
         if (!aidl_utils::IsAidlNativeHandleNull(aidl_buffer.buffer)) {
           native_handle_t* aidl_buffer_native_handle =
               makeFromAidl(aidl_buffer.buffer);
-          if (buffer_mapper_v4_ != nullptr) {
-            hal_buffer.buffer = ImportBufferHandle<
-                android::hardware::graphics::mapper::V4_0::IMapper,
-                android::hardware::graphics::mapper::V4_0::Error>(
-                buffer_mapper_v4_, aidl_buffer_native_handle);
-          } else if (buffer_mapper_v3_ != nullptr) {
-            hal_buffer.buffer = ImportBufferHandle<
-                android::hardware::graphics::mapper::V3_0::IMapper,
-                android::hardware::graphics::mapper::V3_0::Error>(
-                buffer_mapper_v3_, aidl_buffer_native_handle);
-          } else {
-            hal_buffer.buffer = ImportBufferHandle<
-                android::hardware::graphics::mapper::V2_0::IMapper,
-                android::hardware::graphics::mapper::V2_0::Error>(
-                buffer_mapper_v2_, aidl_buffer_native_handle);
+          status_t status = GraphicBufferMapper::get().importBufferNoValidate(
+              aidl_buffer_native_handle, &hal_buffer.buffer);
+          if (status != OK) {
+            ALOGE("%s: Importing graphic buffer failed. Status: %s",
+                  __FUNCTION__, ::android::statusToString(status).c_str());
           }
           native_handle_delete(aidl_buffer_native_handle);
         }
@@ -281,26 +300,6 @@
   return hal_buffer_request_status;
 }
 
-template <class T, class U>
-buffer_handle_t AidlCameraDeviceSession::ImportBufferHandle(
-    const sp<T> buffer_mapper_, const hidl_handle& buffer_hidl_handle) {
-  U mapper_error;
-  buffer_handle_t imported_buffer_handle;
-
-  auto hidl_res = buffer_mapper_->importBuffer(
-      buffer_hidl_handle, [&](const auto& error, const auto& buffer_handle) {
-        mapper_error = error;
-        imported_buffer_handle = static_cast<buffer_handle_t>(buffer_handle);
-      });
-  if (!hidl_res.isOk() || mapper_error != U::NONE) {
-    ALOGE("%s: Importing buffer failed: %s, mapper error %u", __FUNCTION__,
-          hidl_res.description().c_str(), mapper_error);
-    return nullptr;
-  }
-
-  return imported_buffer_handle;
-}
-
 void AidlCameraDeviceSession::ReturnStreamBuffers(
     const std::vector<google_camera_hal::StreamBuffer>& return_hal_buffers) {
   std::shared_lock lock(aidl_device_callback_lock_);
@@ -331,29 +330,6 @@
   }
 }
 
-status_t AidlCameraDeviceSession::InitializeBufferMapper() {
-  buffer_mapper_v4_ =
-      android::hardware::graphics::mapper::V4_0::IMapper::getService();
-  if (buffer_mapper_v4_ != nullptr) {
-    return OK;
-  }
-
-  buffer_mapper_v3_ =
-      android::hardware::graphics::mapper::V3_0::IMapper::getService();
-  if (buffer_mapper_v3_ != nullptr) {
-    return OK;
-  }
-
-  buffer_mapper_v2_ =
-      android::hardware::graphics::mapper::V2_0::IMapper::getService();
-  if (buffer_mapper_v2_ != nullptr) {
-    return OK;
-  }
-
-  ALOGE("%s: Getting buffer mapper failed.", __FUNCTION__);
-  return UNKNOWN_ERROR;
-}
-
 status_t AidlCameraDeviceSession::Initialize(
     const std::shared_ptr<ICameraDeviceCallback>& callback,
     std::unique_ptr<google_camera_hal::CameraDeviceSession> device_session,
@@ -388,12 +364,7 @@
   }
 
   // Initialize buffer mapper
-  res = InitializeBufferMapper();
-  if (res != OK) {
-    ALOGE("%s: Initialize buffer mapper failed: %s(%d)", __FUNCTION__,
-          strerror(-res), res);
-    return res;
-  }
+  GraphicBufferMapper::preloadHal();
 
   const std::string thermal_instance_name =
       std::string(aidl::android::hardware::thermal::IThermal::descriptor) +
@@ -423,6 +394,13 @@
           [this](std::unique_ptr<google_camera_hal::CaptureResult> result) {
             ProcessCaptureResult(std::move(result));
           }),
+      .process_batch_capture_result =
+          google_camera_hal::ProcessBatchCaptureResultFunc(
+              [this](
+                  std::vector<std::unique_ptr<google_camera_hal::CaptureResult>>
+                      results) {
+                ProcessBatchCaptureResult(std::move(results));
+              }),
       .notify = google_camera_hal::NotifyFunc(
           [this](const google_camera_hal::NotifyMessage& message) {
             NotifyHalMessage(message);
@@ -583,15 +561,25 @@
   return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus AidlCameraDeviceSession::configureStreams(
+ndk::ScopedAStatus AidlCameraDeviceSession::configureStreamsV2(
     const StreamConfiguration& requestedConfiguration,
-    std::vector<HalStream>* aidl_return) {
-  ATRACE_NAME("AidlCameraDeviceSession::configureStreams");
+    ConfigureStreamsRet* aidl_return) {
   if (aidl_return == nullptr) {
     return ndk::ScopedAStatus::fromServiceSpecificError(
         static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
   }
-  aidl_return->clear();
+  return configureStreamsImpl(requestedConfiguration, /*v2=*/true, aidl_return);
+}
+
+ndk::ScopedAStatus AidlCameraDeviceSession::configureStreamsImpl(
+    const StreamConfiguration& requestedConfiguration, bool v2,
+    ConfigureStreamsRet* aidl_return) {
+  ATRACE_NAME("AidlCameraDeviceSession::configureStreamsV2");
+  if (aidl_return == nullptr) {
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
+  }
+  aidl_return->halStreams.clear();
   if (device_session_ == nullptr) {
     return ndk::ScopedAStatus::fromServiceSpecificError(
         static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
@@ -619,8 +607,8 @@
         static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
   }
 
-  std::vector<google_camera_hal::HalStream> hal_configured_streams;
-  res = device_session_->ConfigureStreams(hal_stream_config,
+  google_camera_hal::ConfigureStreamsReturn hal_configured_streams;
+  res = device_session_->ConfigureStreams(hal_stream_config, v2,
                                           &hal_configured_streams);
   if (res != OK) {
     ALOGE("%s: Configuring streams failed: %s(%d)", __FUNCTION__,
@@ -636,6 +624,24 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus AidlCameraDeviceSession::configureStreams(
+    const StreamConfiguration& requestedConfiguration,
+    std::vector<HalStream>* aidl_return) {
+  ATRACE_NAME("AidlCameraDeviceSession::configureStreams");
+  if (aidl_return == nullptr) {
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
+  }
+  ConfigureStreamsRet aidl_config;
+  auto err = configureStreamsImpl(requestedConfiguration,
+                                  /*v2=*/false, &aidl_config);
+  if (!err.isOk()) {
+    return err;
+  }
+  *aidl_return = std::move(aidl_config.halStreams);
+  return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus AidlCameraDeviceSession::getCaptureRequestMetadataQueue(
     aidl::android::hardware::common::fmq::MQDescriptor<
         int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>*
@@ -834,6 +840,22 @@
   return binder;
 }
 
+void AidlCameraDeviceSession::TryLogFirstFrameDone(
+    const google_camera_hal::CaptureResult& result,
+    const char* caller_func_name) {
+  std::lock_guard<std::mutex> pending_lock(pending_first_frame_buffers_mutex_);
+  if (!result.output_buffers.empty() && num_pending_first_frame_buffers_ > 0 &&
+      first_request_frame_number_ == result.frame_number) {
+    num_pending_first_frame_buffers_ -= result.output_buffers.size();
+    if (num_pending_first_frame_buffers_ == 0) {
+      ALOGI("%s: First frame done", caller_func_name);
+      aidl_profiler_->FirstFrameEnd();
+      ATRACE_ASYNC_END("first_frame", 0);
+      ATRACE_ASYNC_END("switch_mode", 0);
+    }
+  }
+}
+
 }  // namespace implementation
 }  // namespace device
 }  // namespace camera
diff --git a/common/hal/aidl_service/aidl_camera_device_session.h b/common/hal/aidl_service/aidl_camera_device_session.h
index 6480b05..1f6b609 100644
--- a/common/hal/aidl_service/aidl_camera_device_session.h
+++ b/common/hal/aidl_service/aidl_camera_device_session.h
@@ -26,10 +26,11 @@
 #include <utils/StrongPointer.h>
 
 #include <shared_mutex>
+#include <vector>
 
 #include "aidl_profiler.h"
-#include "aidl_thermal_utils.h"
 #include "camera_device_session.h"
+#include "hal_types.h"
 
 namespace android {
 namespace hardware {
@@ -113,6 +114,9 @@
     return ndk::ScopedAStatus::ok();
   };
 
+  ndk::ScopedAStatus configureStreamsV2(
+      const aidl::android::hardware::camera::device::StreamConfiguration&,
+      aidl::android::hardware::camera::device::ConfigureStreamsRet*) override;
   AidlCameraDeviceSession() = default;
 
  protected:
@@ -151,6 +155,19 @@
   void ProcessCaptureResult(
       std::unique_ptr<google_camera_hal::CaptureResult> hal_result);
 
+  // Invoked when receiving a batched result from HAL.
+  void ProcessBatchCaptureResult(
+      std::vector<std::unique_ptr<google_camera_hal::CaptureResult>> hal_results);
+
+  // TODO b/311263114: Remove this method once the feature flag is enabled.
+  // This is needed since the framework has the feature support flagged. The HAL
+  // should not switch HAL buffer on / off is the framework doesn't support them
+  // (flag is off). Since aconfig flags are not shared between the framework and
+  // the HAL - the HAL can know about framework support through knowing whether
+  // configureStreamsV2 was called or not.
+  ndk::ScopedAStatus configureStreamsImpl(
+      const aidl::android::hardware::camera::device::StreamConfiguration&,
+      bool v2, aidl::android::hardware::camera::device::ConfigureStreamsRet*);
   // Invoked when receiving a message from HAL.
   void NotifyHalMessage(const google_camera_hal::NotifyMessage& hal_message);
 
@@ -163,11 +180,6 @@
   void ReturnStreamBuffers(
       const std::vector<google_camera_hal::StreamBuffer>& return_hal_buffers);
 
-  // Import a buffer handle.
-  template <class T, class U>
-  buffer_handle_t ImportBufferHandle(const sp<T> buffer_mapper_,
-                                     const hidl_handle& buffer_hidl_handle);
-
   // Set camera device session callbacks.
   void SetSessionCallbacks();
 
@@ -183,6 +195,10 @@
   // Unregister thermal changed callback.
   void UnregisterThermalChangedCallback();
 
+  // Log when the first frame buffers are all received.
+  void TryLogFirstFrameDone(const google_camera_hal::CaptureResult& result,
+                            const char* caller_func_name);
+
   std::unique_ptr<google_camera_hal::CameraDeviceSession> device_session_;
 
   // Metadata queue to read the request metadata from.
@@ -198,10 +214,6 @@
   std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceCallback>
       aidl_device_callback_;
 
-  android::sp<android::hardware::graphics::mapper::V2_0::IMapper> buffer_mapper_v2_;
-  android::sp<android::hardware::graphics::mapper::V3_0::IMapper> buffer_mapper_v3_;
-  android::sp<android::hardware::graphics::mapper::V4_0::IMapper> buffer_mapper_v4_;
-
   std::mutex aidl_thermal_mutex_;
   std::shared_ptr<aidl::android::hardware::thermal::IThermal> thermal_;
 
diff --git a/common/hal/aidl_service/aidl_utils.cc b/common/hal/aidl_service/aidl_utils.cc
index ed84c50..b603aea 100644
--- a/common/hal/aidl_service/aidl_utils.cc
+++ b/common/hal/aidl_service/aidl_utils.cc
@@ -186,44 +186,44 @@
 }
 
 status_t ConvertToAidlHalStreamConfig(
-    const std::vector<google_camera_hal::HalStream>& hal_configured_streams,
-    std::vector<HalStream>* aidl_hal_streams) {
-  if (aidl_hal_streams == nullptr) {
-    ALOGE("%s: aidl_hal_streams is nullptr.", __FUNCTION__);
+    const google_camera_hal::ConfigureStreamsReturn& hal_config,
+    ConfigureStreamsRet* aidl_config) {
+  if (aidl_config == nullptr) {
+    ALOGE("%s: aidl_config is nullptr.", __FUNCTION__);
     return BAD_VALUE;
   }
 
-  aidl_hal_streams->resize(hal_configured_streams.size());
+  aidl_config->halStreams.resize(hal_config.hal_streams.size());
 
-  for (uint32_t i = 0; i < hal_configured_streams.size(); i++) {
-    auto& dst = (*aidl_hal_streams)[i];
+  for (uint32_t i = 0; i < hal_config.hal_streams.size(); i++) {
+    auto& dst = aidl_config->halStreams[i];
     dst.supportOffline = false;
-    if (hal_configured_streams[i].is_physical_camera_stream) {
+    if (hal_config.hal_streams[i].is_physical_camera_stream) {
       dst.physicalCameraId =
-          std::to_string(hal_configured_streams[i].physical_camera_id);
+          std::to_string(hal_config.hal_streams[i].physical_camera_id);
     }
 
     dst.overrideDataSpace =
         static_cast<aidl::android::hardware::graphics::common::Dataspace>(
-            hal_configured_streams[i].override_data_space);
+            hal_config.hal_streams[i].override_data_space);
 
-    dst.id = hal_configured_streams[i].id;
+    dst.id = hal_config.hal_streams[i].id;
 
     dst.overrideFormat =
         static_cast<aidl::android::hardware::graphics::common::PixelFormat>(
-            hal_configured_streams[i].override_format);
+            hal_config.hal_streams[i].override_format);
 
     dst.producerUsage =
         static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
-            hal_configured_streams[i].producer_usage);
+            hal_config.hal_streams[i].producer_usage);
 
     dst.consumerUsage =
         static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
-            hal_configured_streams[i].consumer_usage);
+            hal_config.hal_streams[i].consumer_usage);
 
-    dst.maxBuffers = hal_configured_streams[i].max_buffers;
+    dst.maxBuffers = hal_config.hal_streams[i].max_buffers;
   }
-
+  aidl_config->enableHalBufferManager = hal_config.use_hal_buf_manager;
   return OK;
 }
 
@@ -812,7 +812,8 @@
   }
 
   google_camera_hal::StreamBuffer hal_buffer = {};
-  if (!IsAidlNativeHandleNull(aidl_request.inputBuffer.buffer)) {
+
+  if (aidl_request.inputBuffer.streamId != -1) {
     res = ConvertToHalStreamBuffer(aidl_request.inputBuffer, &hal_buffer,
                                    handles_to_delete);
     if (res != OK) {
diff --git a/common/hal/aidl_service/aidl_utils.h b/common/hal/aidl_service/aidl_utils.h
index be7e6a5..f8b23a0 100644
--- a/common/hal/aidl_service/aidl_utils.h
+++ b/common/hal/aidl_service/aidl_utils.h
@@ -51,6 +51,7 @@
 using aidl::android::hardware::camera::device::BufferStatus;
 using aidl::android::hardware::camera::device::CaptureRequest;
 using aidl::android::hardware::camera::device::CaptureResult;
+using aidl::android::hardware::camera::device::ConfigureStreamsRet;
 using aidl::android::hardware::camera::device::ErrorCode;
 using aidl::android::hardware::camera::device::ErrorMsg;
 using aidl::android::hardware::camera::device::HalStream;
@@ -91,8 +92,8 @@
     CameraResourceCost* aidl_cost);
 
 status_t ConvertToAidlHalStreamConfig(
-    const std::vector<google_camera_hal::HalStream>& hal_configured_streams,
-    std::vector<HalStream>* aidl_hal_stream_config);
+    const google_camera_hal::ConfigureStreamsReturn& hal_config,
+    ConfigureStreamsRet* aidl_config);
 
 status_t ConverToAidlNotifyMessage(
     const google_camera_hal::NotifyMessage& hal_message,
diff --git a/common/hal/aidl_service/android.hardware.camera.provider@2.7-service-google.xml b/common/hal/aidl_service/android.hardware.camera.provider@2.7-service-google.xml
index a772f31..048c9c9 100644
--- a/common/hal/aidl_service/android.hardware.camera.provider@2.7-service-google.xml
+++ b/common/hal/aidl_service/android.hardware.camera.provider@2.7-service-google.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.camera.provider</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>ICameraProvider</name>
             <instance>internal/0</instance>
diff --git a/common/hal/common/hal_types.h b/common/hal/common/hal_types.h
index 8695418..380d2fb 100644
--- a/common/hal/common/hal_types.h
+++ b/common/hal/common/hal_types.h
@@ -19,6 +19,7 @@
 
 #include <cutils/native_handle.h>
 #include <system/graphics-base-v1.0.h>
+
 #include <string>
 #include <unordered_map>
 #include <vector>
@@ -172,6 +173,14 @@
   uint32_t physical_camera_id = 0;
 };
 
+// Corresponds to the definition of ConfigureStreamsRet
+// parcelable in ConfigureStreamsRet.aidl. That is used as the
+// return type for ICameraDeviceSession.configureStreamsV2
+struct ConfigureStreamsReturn {
+  std::vector<HalStream> hal_streams;
+  bool use_hal_buf_manager = false;
+};
+
 // See the definition of
 // ::android::hardware::camera::device::V3_2::BufferCache
 struct BufferCache {
@@ -396,6 +405,10 @@
 using ProcessCaptureResultFunc =
     std::function<void(std::unique_ptr<CaptureResult> /*result*/)>;
 
+// Callback function invoked to process a batched capture result.
+using ProcessBatchCaptureResultFunc =
+    std::function<void(std::vector<std::unique_ptr<CaptureResult>> /*results*/)>;
+
 // Callback function invoked to notify messages.
 using NotifyFunc = std::function<void(const NotifyMessage& /*message*/)>;
 
diff --git a/common/hal/google_camera_hal/Android.bp b/common/hal/google_camera_hal/Android.bp
index 0b35366..7910d90 100644
--- a/common/hal/google_camera_hal/Android.bp
+++ b/common/hal/google_camera_hal/Android.bp
@@ -80,9 +80,6 @@
         "zsl_snapshot_capture_session.cc",
     ],
     shared_libs: [
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
         "lib_profiler",
         "libbase",
         "libcamera_metadata",
@@ -91,6 +88,7 @@
         "libhidlbase",
         "liblog",
         "libmeminfo",
+        "libui",
         "libutils",
         "libsync",
     ],
diff --git a/common/hal/google_camera_hal/basic_capture_session.cc b/common/hal/google_camera_hal/basic_capture_session.cc
index 667d8df..18e8c34 100644
--- a/common/hal/google_camera_hal/basic_capture_session.cc
+++ b/common/hal/google_camera_hal/basic_capture_session.cc
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_BasicCaptureSession"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "basic_capture_session.h"
+
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include "basic_capture_session.h"
 #include "basic_request_processor.h"
 #include "basic_result_processor.h"
 #include "realtime_process_block.h"
@@ -44,8 +45,9 @@
 std::unique_ptr<CaptureSession> BasicCaptureSession::Create(
     CameraDeviceSessionHwl* device_session_hwl,
     const StreamConfiguration& stream_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-    HwlSessionCallback /*session_callback*/,
+    ProcessCaptureResultFunc process_capture_result,
+    ProcessBatchCaptureResultFunc process_batch_capture_result,
+    NotifyFunc notify, HwlSessionCallback /*session_callback*/,
     std::vector<HalStream>* hal_configured_streams,
     CameraBufferAllocatorHwl* /*camera_allocator_hwl*/) {
   ATRACE_CALL();
@@ -55,9 +57,9 @@
     return nullptr;
   }
 
-  status_t res = session->Initialize(device_session_hwl, stream_config,
-                                     process_capture_result, notify,
-                                     hal_configured_streams);
+  status_t res = session->Initialize(
+      device_session_hwl, stream_config, process_capture_result,
+      process_batch_capture_result, notify, hal_configured_streams);
   if (res != OK) {
     ALOGE("%s: Initializing BasicCaptureSession failed: %s (%d).", __FUNCTION__,
           strerror(-res), res);
@@ -185,8 +187,9 @@
 status_t BasicCaptureSession::Initialize(
     CameraDeviceSessionHwl* device_session_hwl,
     const StreamConfiguration& stream_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-    std::vector<HalStream>* hal_configured_streams) {
+    ProcessCaptureResultFunc process_capture_result,
+    ProcessBatchCaptureResultFunc process_batch_capture_result,
+    NotifyFunc notify, std::vector<HalStream>* hal_configured_streams) {
   ATRACE_CALL();
   if (!IsStreamConfigurationSupported(device_session_hwl, stream_config)) {
     ALOGE("%s: stream configuration is not supported.", __FUNCTION__);
@@ -207,7 +210,8 @@
     return UNKNOWN_ERROR;
   }
 
-  result_processor->SetResultCallback(process_capture_result, notify);
+  result_processor->SetResultCallback(process_capture_result, notify,
+                                      process_batch_capture_result);
 
   // Create process block.
   auto process_block = RealtimeProcessBlock::Create(device_session_hwl_);
diff --git a/common/hal/google_camera_hal/basic_capture_session.h b/common/hal/google_camera_hal/basic_capture_session.h
index c777e91..d2267d0 100644
--- a/common/hal/google_camera_hal/basic_capture_session.h
+++ b/common/hal/google_camera_hal/basic_capture_session.h
@@ -46,6 +46,8 @@
   // lifetime of BasicCaptureSession.
   // stream_config is the stream configuration.
   // process_capture_result is the callback function to notify results.
+  // process_batch_capture_result is the callback function to notify batched
+  // results.
   // notify is the callback function to notify messages.
   // hal_configured_streams will be filled with HAL configured streams.
   // camera_allocator_hwl is owned by the caller and must be valid during the
@@ -53,8 +55,9 @@
   static std::unique_ptr<CaptureSession> Create(
       CameraDeviceSessionHwl* device_session_hwl,
       const StreamConfiguration& stream_config,
-      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-      HwlSessionCallback session_callback,
+      ProcessCaptureResultFunc process_capture_result,
+      ProcessBatchCaptureResultFunc process_batch_capture_result,
+      NotifyFunc notify, HwlSessionCallback session_callback,
       std::vector<HalStream>* hal_configured_streams,
       CameraBufferAllocatorHwl* camera_allocator_hwl = nullptr);
 
@@ -73,6 +76,7 @@
   status_t Initialize(CameraDeviceSessionHwl* device_session_hwl,
                       const StreamConfiguration& stream_config,
                       ProcessCaptureResultFunc process_capture_result,
+                      ProcessBatchCaptureResultFunc process_batch_capture_result,
                       NotifyFunc notify,
                       std::vector<HalStream>* hal_configured_streams);
 
diff --git a/common/hal/google_camera_hal/basic_result_processor.cc b/common/hal/google_camera_hal/basic_result_processor.cc
index 41a112b..bfd1493 100644
--- a/common/hal/google_camera_hal/basic_result_processor.cc
+++ b/common/hal/google_camera_hal/basic_result_processor.cc
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_BasicResultProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "basic_result_processor.h"
+
+#include <inttypes.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include <inttypes.h>
-
-#include "basic_result_processor.h"
 #include "hal_utils.h"
 
 namespace android {
@@ -54,11 +54,13 @@
 }
 
 void BasicResultProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc process_batch_capture_result) {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
   notify_ = notify;
+  process_batch_capture_result_ = process_batch_capture_result;
 }
 
 status_t BasicResultProcessor::AddPendingRequests(
@@ -93,6 +95,29 @@
   process_capture_result_(std::move(block_result.result));
 }
 
+void BasicResultProcessor::ProcessBatchResult(
+    std::vector<ProcessBlockResult> block_results) {
+  ATRACE_CALL();
+  std::lock_guard<std::mutex> lock(callback_lock_);
+  if (process_capture_result_ == nullptr) {
+    ALOGE("%s: process_capture_result_ is nullptr. Dropping a result.",
+          __FUNCTION__);
+    return;
+  }
+
+  std::vector<std::unique_ptr<CaptureResult>> capture_results;
+  capture_results.reserve(block_results.size());
+  for (auto& block_result : block_results) {
+    if (block_result.result == nullptr) {
+      ALOGW("%s: Received a nullptr result.", __FUNCTION__);
+      continue;
+    }
+    capture_results.push_back(std::move(block_result.result));
+  }
+
+  process_batch_capture_result_(std::move(capture_results));
+}
+
 void BasicResultProcessor::Notify(const ProcessBlockNotifyMessage& block_message) {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(callback_lock_);
diff --git a/common/hal/google_camera_hal/basic_result_processor.h b/common/hal/google_camera_hal/basic_result_processor.h
index f263807..2fa1e3b 100644
--- a/common/hal/google_camera_hal/basic_result_processor.h
+++ b/common/hal/google_camera_hal/basic_result_processor.h
@@ -17,6 +17,8 @@
 #ifndef HARDWARE_GOOGLE_CAMERA_HAL_GOOGLE_CAMERA_HAL_BASIC_RESULT_PROCESSOR_H_
 #define HARDWARE_GOOGLE_CAMERA_HAL_GOOGLE_CAMERA_HAL_BASIC_RESULT_PROCESSOR_H_
 
+#include <vector>
+
 #include "result_processor.h"
 
 namespace android {
@@ -31,8 +33,9 @@
   virtual ~BasicResultProcessor();
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
@@ -40,6 +43,8 @@
 
   void ProcessResult(ProcessBlockResult block_result) override;
 
+  void ProcessBatchResult(std::vector<ProcessBlockResult> block_results) override;
+
   void Notify(const ProcessBlockNotifyMessage& block_message) override;
 
   status_t FlushPendingRequests() override;
@@ -53,6 +58,7 @@
 
   // The following callbacks must be protected by callback_lock_.
   ProcessCaptureResultFunc process_capture_result_;
+  ProcessBatchCaptureResultFunc process_batch_capture_result_;
   NotifyFunc notify_;
 };
 
diff --git a/common/hal/google_camera_hal/camera_device_session.cc b/common/hal/google_camera_hal/camera_device_session.cc
index 621fd6f..8d545ed 100644
--- a/common/hal/google_camera_hal/camera_device_session.cc
+++ b/common/hal/google_camera_hal/camera_device_session.cc
@@ -31,6 +31,7 @@
 #include "hdrplus_capture_session.h"
 #include "rgbird_capture_session.h"
 #include "system/camera_metadata.h"
+#include "ui/GraphicBufferMapper.h"
 #include "vendor_tag_defs.h"
 #include "vendor_tag_types.h"
 #include "vendor_tags.h"
@@ -186,48 +187,7 @@
 
 void CameraDeviceSession::ProcessCaptureResult(
     std::unique_ptr<CaptureResult> result) {
-  if (result == nullptr) {
-    ALOGE("%s: result is nullptr", __FUNCTION__);
-    return;
-  }
-  zoom_ratio_mapper_.UpdateCaptureResult(result.get());
-
-  // If buffer management is not supported, simply send the result to the client.
-  if (!buffer_management_supported_) {
-    std::shared_lock lock(session_callback_lock_);
-    session_callback_.process_capture_result(std::move(result));
-    return;
-  }
-
-  status_t res = UpdatePendingRequest(result.get());
-  if (res != OK) {
-    ALOGE("%s: Updating inflight requests/streams failed.", __FUNCTION__);
-  }
-
-  for (auto& stream_buffer : result->output_buffers) {
-    ALOGV("%s: [sbc] <= Return result output buf[%p], bid[%" PRIu64
-          "], strm[%d], frm[%u]",
-          __FUNCTION__, stream_buffer.buffer, stream_buffer.buffer_id,
-          stream_buffer.stream_id, result->frame_number);
-  }
-  for (auto& stream_buffer : result->input_buffers) {
-    ALOGV("%s: [sbc] <= Return result input buf[%p], bid[%" PRIu64
-          "], strm[%d], frm[%u]",
-          __FUNCTION__, stream_buffer.buffer, stream_buffer.buffer_id,
-          stream_buffer.stream_id, result->frame_number);
-  }
-
-  // If there is dummy buffer or a dummy buffer has been observed of this frame,
-  // handle the capture result specifically.
-  bool result_handled = false;
-  res = TryHandleDummyResult(result.get(), &result_handled);
-  if (res != OK) {
-    ALOGE("%s: Failed to handle dummy result.", __FUNCTION__);
-    return;
-  }
-  if (result_handled == true) {
-    return;
-  }
+  if (TryHandleCaptureResult(result)) return;
 
   // Update pending request tracker with returned buffers.
   std::vector<StreamBuffer> buffers;
@@ -244,18 +204,40 @@
     session_callback_.process_capture_result(std::move(result));
   }
 
-  if (!buffers.empty()) {
-    if (pending_requests_tracker_->TrackReturnedAcquiredBuffers(buffers) != OK) {
-      ALOGE("%s: Tracking requested acquired buffers failed", __FUNCTION__);
+  TrackReturnedBuffers(buffers);
+}
+
+void CameraDeviceSession::ProcessBatchCaptureResult(
+    std::vector<std::unique_ptr<CaptureResult>> results) {
+  std::vector<std::unique_ptr<CaptureResult>> results_to_callback;
+  results_to_callback.reserve(results.size());
+  std::vector<StreamBuffer> buffers;
+  for (auto& result : results) {
+    if (TryHandleCaptureResult(result)) continue;
+
+    // Update pending request tracker with returned buffers.
+    buffers.insert(buffers.end(), result->output_buffers.begin(),
+                   result->output_buffers.end());
+
+    if (result->result_metadata) {
+      std::lock_guard<std::mutex> lock(request_record_lock_);
+      pending_results_.erase(result->frame_number);
     }
-    if (pending_requests_tracker_->TrackReturnedResultBuffers(buffers) != OK) {
-      ALOGE("%s: Tracking requested quota buffers failed", __FUNCTION__);
-    }
+
+    results_to_callback.push_back(std::move(result));
   }
+
+  {
+    std::shared_lock lock(session_callback_lock_);
+    session_callback_.process_batch_capture_result(
+        std::move(results_to_callback));
+  }
+
+  TrackReturnedBuffers(buffers);
 }
 
 void CameraDeviceSession::Notify(const NotifyMessage& result) {
-  if (buffer_management_supported_) {
+  if (buffer_management_used_) {
     uint32_t frame_number = 0;
     if (result.type == MessageType::kError) {
       frame_number = result.message.error.frame_number;
@@ -305,29 +287,6 @@
   session_callback_.notify(result);
 }
 
-status_t CameraDeviceSession::InitializeBufferMapper() {
-  buffer_mapper_v4_ =
-      android::hardware::graphics::mapper::V4_0::IMapper::getService();
-  if (buffer_mapper_v4_ != nullptr) {
-    return OK;
-  }
-
-  buffer_mapper_v3_ =
-      android::hardware::graphics::mapper::V3_0::IMapper::getService();
-  if (buffer_mapper_v3_ != nullptr) {
-    return OK;
-  }
-
-  buffer_mapper_v2_ =
-      android::hardware::graphics::mapper::V2_0::IMapper::getService();
-  if (buffer_mapper_v2_ != nullptr) {
-    return OK;
-  }
-
-  ALOGE("%s: Getting buffer mapper failed.", __FUNCTION__);
-  return UNKNOWN_ERROR;
-}
-
 void CameraDeviceSession::InitializeCallbacks() {
   std::lock_guard lock(session_callback_lock_);
 
@@ -359,6 +318,12 @@
         ProcessCaptureResult(std::move(result));
       });
 
+  camera_device_session_callback_.process_batch_capture_result =
+      ProcessBatchCaptureResultFunc(
+          [this](std::vector<std::unique_ptr<CaptureResult>> results) {
+            ProcessBatchCaptureResult(std::move(results));
+          });
+
   camera_device_session_callback_.notify =
       NotifyFunc([this](const NotifyMessage& result) { Notify(result); });
 
@@ -390,9 +355,12 @@
   status_t res = characteristics->Get(
       ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
   if (res == OK && entry.count > 0) {
-    buffer_management_supported_ =
-        (entry.data.u8[0] >=
+    buffer_management_used_ =
+        (entry.data.u8[0] ==
          ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    session_buffer_management_supported_ =
+        (entry.data.u8[0] ==
+         ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE);
   }
 
   return OK;
@@ -416,17 +384,11 @@
   device_session_hwl_ = std::move(device_session_hwl);
   camera_allocator_hwl_ = camera_allocator_hwl;
 
-  status_t res = InitializeBufferMapper();
-  if (res != OK) {
-    ALOGE("%s: Initialize buffer mapper failed: %s(%d)", __FUNCTION__,
-          strerror(-res), res);
-    return res;
-  }
-
+  GraphicBufferMapper::preloadHal();
   InitializeCallbacks();
 
   std::unique_ptr<google_camera_hal::HalCameraMetadata> characteristics;
-  res = device_session_hwl_->GetCameraCharacteristics(&characteristics);
+  status_t res = device_session_hwl_->GetCameraCharacteristics(&characteristics);
   if (res != OK) {
     ALOGE("%s: Get camera characteristics failed: %s(%d)", __FUNCTION__,
           strerror(-res), res);
@@ -600,16 +562,7 @@
   }
   external_capture_session_entries_.clear();
 
-  if (buffer_mapper_v4_ != nullptr) {
-    FreeImportedBufferHandles<android::hardware::graphics::mapper::V4_0::IMapper>(
-        buffer_mapper_v4_);
-  } else if (buffer_mapper_v3_ != nullptr) {
-    FreeImportedBufferHandles<android::hardware::graphics::mapper::V3_0::IMapper>(
-        buffer_mapper_v3_);
-  } else if (buffer_mapper_v2_ != nullptr) {
-    FreeImportedBufferHandles<android::hardware::graphics::mapper::V2_0::IMapper>(
-        buffer_mapper_v2_);
-  }
+  FreeImportedBufferHandles();
 }
 
 void CameraDeviceSession::UnregisterThermalCallback() {
@@ -681,12 +634,17 @@
 }
 
 status_t CameraDeviceSession::ConfigureStreams(
-    const StreamConfiguration& stream_config,
-    std::vector<HalStream>* hal_config) {
+    const StreamConfiguration& stream_config, bool v2,
+    ConfigureStreamsReturn* configured_streams) {
   ATRACE_CALL();
   bool set_realtime_thread = false;
   int32_t schedule_policy;
   struct sched_param schedule_param = {0};
+  if (configured_streams == nullptr) {
+    ALOGE("%s: configured_streams output is nullptr", __FUNCTION__);
+    return BAD_VALUE;
+  }
+  std::vector<HalStream>& hal_config = configured_streams->hal_streams;
   if (utils::SupportRealtimeThread()) {
     bool get_thread_schedule = false;
     if (pthread_getschedparam(pthread_self(), &schedule_policy,
@@ -733,13 +691,14 @@
   if (!utils::IsStreamUseCaseSupported(stream_config, stream_use_cases_)) {
     return BAD_VALUE;
   }
-
+  device_session_hwl_->setConfigureStreamsV2(v2);
   capture_session_ = CreateCaptureSession(
       stream_config, kWrapperCaptureSessionEntries,
       external_capture_session_entries_, kCaptureSessionEntries,
       hwl_session_callback_, camera_allocator_hwl_, device_session_hwl_.get(),
-      hal_config, camera_device_session_callback_.process_capture_result,
-      camera_device_session_callback_.notify);
+      &hal_config, camera_device_session_callback_.process_capture_result,
+      camera_device_session_callback_.notify,
+      camera_device_session_callback_.process_batch_capture_result);
 
   if (capture_session_ == nullptr) {
     ALOGE("%s: Cannot find a capture session compatible with stream config",
@@ -749,8 +708,19 @@
     }
     return BAD_VALUE;
   }
-
-  if (buffer_management_supported_) {
+  if (session_buffer_management_supported_ && v2) {
+    bool use_buffer_management = false;
+    auto ret =
+        device_session_hwl_->ShouldUseHalBufferManager(&use_buffer_management);
+    if (ret != OK) {
+      ALOGE("%s: shouldUseHalBufManager() failed", __FUNCTION__);
+      return ret;
+    } else {
+      buffer_management_used_ = use_buffer_management;
+    }
+    configured_streams->use_hal_buf_manager = buffer_management_used_;
+  }
+  if (buffer_management_used_) {
     stream_buffer_cache_manager_ = StreamBufferCacheManager::Create();
     if (stream_buffer_cache_manager_ == nullptr) {
       ALOGE("%s: Failed to create stream buffer cache manager.", __FUNCTION__);
@@ -762,7 +732,7 @@
     }
 
     status_t res =
-        RegisterStreamsIntoCacheManagerLocked(stream_config, *hal_config);
+        RegisterStreamsIntoCacheManagerLocked(stream_config, hal_config);
     if (res != OK) {
       ALOGE("%s: Failed to register streams into stream buffer cache manager.",
             __FUNCTION__);
@@ -775,7 +745,7 @@
   }
 
   // (b/129561652): Framework assumes HalStream is sorted.
-  std::sort(hal_config->begin(), hal_config->end(),
+  std::sort(hal_config.begin(), hal_config.end(),
             [](const HalStream& a, const HalStream& b) { return a.id < b.id; });
 
   // Backup the streams received from frameworks into configured_streams_map_,
@@ -789,9 +759,9 @@
 
   // If buffer management is support, create a pending request tracker for
   // capture request throttling.
-  if (buffer_management_supported_) {
+  if (buffer_management_used_) {
     pending_requests_tracker_ =
-        PendingRequestsTracker::Create(*hal_config, grouped_stream_id_map_);
+        PendingRequestsTracker::Create(hal_config, grouped_stream_id_map_);
     if (pending_requests_tracker_ == nullptr) {
       ALOGE("%s: Cannot create a pending request tracker.", __FUNCTION__);
       if (set_realtime_thread) {
@@ -820,7 +790,6 @@
   if (set_realtime_thread) {
     utils::UpdateThreadSched(pthread_self(), schedule_policy, &schedule_param);
   }
-
   return OK;
 }
 
@@ -914,7 +883,7 @@
     }
     // If buffer management API is supported, buffers will be requested via
     // RequestStreamBuffersFunc.
-    if (!buffer_management_supported_) {
+    if (!buffer_management_used_) {
       res = UpdateBufferHandlesLocked(&updated_request->output_buffers);
       if (res != OK) {
         ALOGE("%s: Updating output buffer handles failed: %s(%d)", __FUNCTION__,
@@ -929,22 +898,16 @@
   return OK;
 }
 
-template <class T, class U>
 status_t CameraDeviceSession::ImportBufferHandleLocked(
-    const sp<T> buffer_mapper, const StreamBuffer& buffer) {
+    const StreamBuffer& buffer) {
   ATRACE_CALL();
-  U mapper_error;
   buffer_handle_t imported_buffer_handle;
 
-  auto hidl_res = buffer_mapper->importBuffer(
-      android::hardware::hidl_handle(buffer.buffer),
-      [&](const auto& error, const auto& buffer_handle) {
-        mapper_error = error;
-        imported_buffer_handle = static_cast<buffer_handle_t>(buffer_handle);
-      });
-  if (!hidl_res.isOk() || mapper_error != U::NONE) {
-    ALOGE("%s: Importing buffer failed: %s, mapper error %u", __FUNCTION__,
-          hidl_res.description().c_str(), mapper_error);
+  status_t status = GraphicBufferMapper::get().importBufferNoValidate(
+      buffer.buffer, &imported_buffer_handle);
+  if (status != OK) {
+    ALOGE("%s: Importing buffer failed: %s", __FUNCTION__,
+          ::android::statusToString(status).c_str());
     return UNKNOWN_ERROR;
   }
 
@@ -960,23 +923,7 @@
   // Import buffers that are new to HAL.
   for (auto& buffer : buffers) {
     if (!IsBufferImportedLocked(buffer.stream_id, buffer.buffer_id)) {
-      status_t res = OK;
-      if (buffer_mapper_v4_ != nullptr) {
-        res = ImportBufferHandleLocked<
-            android::hardware::graphics::mapper::V4_0::IMapper,
-            android::hardware::graphics::mapper::V4_0::Error>(buffer_mapper_v4_,
-                                                              buffer);
-      } else if (buffer_mapper_v3_ != nullptr) {
-        res = ImportBufferHandleLocked<
-            android::hardware::graphics::mapper::V3_0::IMapper,
-            android::hardware::graphics::mapper::V3_0::Error>(buffer_mapper_v3_,
-                                                              buffer);
-      } else {
-        res = ImportBufferHandleLocked<
-            android::hardware::graphics::mapper::V2_0::IMapper,
-            android::hardware::graphics::mapper::V2_0::Error>(buffer_mapper_v2_,
-                                                              buffer);
-      }
+      status_t res = ImportBufferHandleLocked(buffer);
 
       if (res != OK) {
         ALOGE("%s: Importing buffer %" PRIu64 " from stream %d failed: %s(%d)",
@@ -1001,7 +948,7 @@
     return res;
   }
 
-  if (buffer_management_supported_) {
+  if (buffer_management_used_) {
     ALOGV(
         "%s: Buffer management is enabled. Skip importing buffers in "
         "requests.",
@@ -1215,7 +1162,7 @@
     return;
   }
 
-  // Note: This function should only be called if buffer_management_supported_
+  // Note: This function should only be called if buffer_management_used_
   // is true.
   if (pending_request_streams_.empty()) {
     pending_requests_tracker_->OnBufferCacheFlushed();
@@ -1346,14 +1293,14 @@
                          ErrorCode::kErrorRequest);
       NotifyBufferError(request);
       need_to_process = false;
-    } else if (buffer_management_supported_) {
+    } else if (buffer_management_used_) {
       CheckRequestForStreamBufferCacheManager(updated_request, &need_to_process);
     }
 
     if (need_to_process) {
       // If buffer management is supported, framework does not throttle requests
       // with stream's max buffers. We need to throttle on our own.
-      if (buffer_management_supported_) {
+      if (buffer_management_used_) {
         std::vector<int32_t> first_requested_stream_ids;
 
         res = pending_requests_tracker_->WaitAndTrackRequestBuffers(
@@ -1378,7 +1325,7 @@
 
       // Check the flush status again to prevent flush being called while we are
       // waiting for the request buffers(request throttling).
-      if (buffer_management_supported_ && is_flushing_) {
+      if (buffer_management_used_ && is_flushing_) {
         std::vector<StreamBuffer> buffers = updated_request.output_buffers;
         {
           std::lock_guard<std::mutex> lock(request_record_lock_);
@@ -1453,41 +1400,28 @@
       continue;
     }
 
-    auto free_buffer_mapper = [&buffer_handle_it](auto buffer_mapper) {
-      auto hidl_res = buffer_mapper->freeBuffer(
-          const_cast<native_handle_t*>(buffer_handle_it->second));
-      if (!hidl_res.isOk()) {
-        ALOGE("%s: Freeing imported buffer failed: %s", __FUNCTION__,
-              hidl_res.description().c_str());
-      }
-    };
-
     device_session_hwl_->RemoveCachedBuffers(buffer_handle_it->second);
 
-    if (buffer_mapper_v4_ != nullptr) {
-      free_buffer_mapper(buffer_mapper_v4_);
-    } else if (buffer_mapper_v3_ != nullptr) {
-      free_buffer_mapper(buffer_mapper_v3_);
-    } else {
-      free_buffer_mapper(buffer_mapper_v2_);
-      ;
+    status_t res =
+        GraphicBufferMapper::get().freeBuffer(buffer_handle_it->second);
+    if (res != OK) {
+      ALOGE("%s: Freeing imported buffer failed: %s", __FUNCTION__,
+            ::android::statusToString(res).c_str());
     }
 
     imported_buffer_handle_map_.erase(buffer_handle_it);
   }
 }
 
-template <class T>
-void CameraDeviceSession::FreeBufferHandlesLocked(const sp<T> buffer_mapper,
-                                                  int32_t stream_id) {
+void CameraDeviceSession::FreeBufferHandlesLocked(int32_t stream_id) {
   for (auto buffer_handle_it = imported_buffer_handle_map_.begin();
        buffer_handle_it != imported_buffer_handle_map_.end();) {
     if (buffer_handle_it->first.stream_id == stream_id) {
-      auto hidl_res = buffer_mapper->freeBuffer(
-          const_cast<native_handle_t*>(buffer_handle_it->second));
-      if (!hidl_res.isOk()) {
+      status_t res =
+          GraphicBufferMapper::get().freeBuffer(buffer_handle_it->second);
+      if (res != OK) {
         ALOGE("%s: Freeing imported buffer failed: %s", __FUNCTION__,
-              hidl_res.description().c_str());
+              ::android::statusToString(res).c_str());
       }
       buffer_handle_it = imported_buffer_handle_map_.erase(buffer_handle_it);
     } else {
@@ -1496,21 +1430,16 @@
   }
 }
 
-template <class T>
-void CameraDeviceSession::FreeImportedBufferHandles(const sp<T> buffer_mapper) {
+void CameraDeviceSession::FreeImportedBufferHandles() {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(imported_buffer_handle_map_lock_);
 
-  if (buffer_mapper == nullptr) {
-    return;
-  }
-
+  auto& mapper = GraphicBufferMapper::get();
   for (auto buffer_handle_it : imported_buffer_handle_map_) {
-    auto hidl_res = buffer_mapper->freeBuffer(
-        const_cast<native_handle_t*>(buffer_handle_it.second));
-    if (!hidl_res.isOk()) {
+    status_t status = mapper.freeBuffer(buffer_handle_it.second);
+    if (status != OK) {
       ALOGE("%s: Freeing imported buffer failed: %s", __FUNCTION__,
-            hidl_res.description().c_str());
+            ::android::statusToString(status).c_str());
     }
   }
 
@@ -1532,16 +1461,7 @@
     if (!found) {
       std::lock_guard<std::mutex> lock(imported_buffer_handle_map_lock_);
       stream_it = configured_streams_map_.erase(stream_it);
-      if (buffer_mapper_v4_ != nullptr) {
-        FreeBufferHandlesLocked<android::hardware::graphics::mapper::V4_0::IMapper>(
-            buffer_mapper_v4_, stream_id);
-      } else if (buffer_mapper_v3_ != nullptr) {
-        FreeBufferHandlesLocked<android::hardware::graphics::mapper::V3_0::IMapper>(
-            buffer_mapper_v3_, stream_id);
-      } else {
-        FreeBufferHandlesLocked<android::hardware::graphics::mapper::V2_0::IMapper>(
-            buffer_mapper_v2_, stream_id);
-      }
+      FreeBufferHandlesLocked(stream_id);
     } else {
       stream_it++;
     }
@@ -1940,5 +1860,63 @@
   return device_session_hwl_->GetProfiler(camera_id, option);
 }
 
+bool CameraDeviceSession::TryHandleCaptureResult(
+    std::unique_ptr<CaptureResult>& result) {
+  if (result == nullptr) {
+    ALOGE("%s: result is nullptr", __FUNCTION__);
+    return true;
+  }
+  zoom_ratio_mapper_.UpdateCaptureResult(result.get());
+
+  // If buffer management is not used, simply send the result to the client.
+  if (!buffer_management_used_) {
+    std::shared_lock lock(session_callback_lock_);
+    session_callback_.process_capture_result(std::move(result));
+    return true;
+  }
+
+  status_t res = UpdatePendingRequest(result.get());
+  if (res != OK) {
+    ALOGE("%s: Updating inflight requests/streams failed: %s(%d)", __FUNCTION__,
+          strerror(-res), res);
+    return true;
+  }
+
+  for (auto& stream_buffer : result->output_buffers) {
+    ALOGV("%s: [sbc] <= Return result output buf[%p], bid[%" PRIu64
+          "], strm[%d], frm[%u]",
+          __FUNCTION__, stream_buffer.buffer, stream_buffer.buffer_id,
+          stream_buffer.stream_id, result->frame_number);
+  }
+  for (auto& stream_buffer : result->input_buffers) {
+    ALOGV("%s: [sbc] <= Return result input buf[%p], bid[%" PRIu64
+          "], strm[%d], frm[%u]",
+          __FUNCTION__, stream_buffer.buffer, stream_buffer.buffer_id,
+          stream_buffer.stream_id, result->frame_number);
+  }
+
+  // If there is placeholder buffer or a placeholder buffer has been observed of
+  // this frame, handle the capture result specifically.
+  bool result_handled = false;
+  res = TryHandleDummyResult(result.get(), &result_handled);
+  if (res != OK) {
+    ALOGE("%s: Failed to handle placeholder result.", __FUNCTION__);
+    return true;
+  }
+  return result_handled;
+}
+
+void CameraDeviceSession::TrackReturnedBuffers(
+    const std::vector<StreamBuffer>& buffers) {
+  if (!buffers.empty()) {
+    if (pending_requests_tracker_->TrackReturnedAcquiredBuffers(buffers) != OK) {
+      ALOGE("%s: Tracking requested acquired buffers failed", __FUNCTION__);
+    }
+    if (pending_requests_tracker_->TrackReturnedResultBuffers(buffers) != OK) {
+      ALOGE("%s: Tracking requested quota buffers failed", __FUNCTION__);
+    }
+  }
+}
+
 }  // namespace google_camera_hal
 }  // namespace android
diff --git a/common/hal/google_camera_hal/camera_device_session.h b/common/hal/google_camera_hal/camera_device_session.h
index 768cf26..644a91c 100644
--- a/common/hal/google_camera_hal/camera_device_session.h
+++ b/common/hal/google_camera_hal/camera_device_session.h
@@ -17,10 +17,6 @@
 #ifndef HARDWARE_GOOGLE_CAMERA_HAL_GOOGLE_CAMERA_HAL_CAMERA_DEVICE__SESSION_H_
 #define HARDWARE_GOOGLE_CAMERA_HAL_GOOGLE_CAMERA_HAL_CAMERA_DEVICE__SESSION_H_
 
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
-
 #include <memory>
 #include <set>
 #include <shared_mutex>
@@ -46,6 +42,9 @@
   // Callback to notify when a camera device produces a capture result.
   ProcessCaptureResultFunc process_capture_result;
 
+  // Callback to notify when a camera device produces a batched capture result.
+  ProcessBatchCaptureResultFunc process_batch_capture_result;
+
   // Callback to notify shutters or errors.
   NotifyFunc notify;
 
@@ -100,9 +99,11 @@
 
   // Configure streams.
   // stream_config is the requested stream configuration.
+  // v2 is whether the ConfigureStreams call is made by the configureStreamsV2
+  //    AIDL call or not.
   // hal_configured_streams is filled by this method with configured stream.
-  status_t ConfigureStreams(const StreamConfiguration& stream_config,
-                            std::vector<HalStream>* hal_configured_streams);
+  status_t ConfigureStreams(const StreamConfiguration& stream_config, bool v2,
+                            ConfigureStreamsReturn* configured_streams);
 
   // Process a capture request.
   // num_processed_requests is filled by this method with the number of
@@ -147,9 +148,6 @@
       CameraBufferAllocatorHwl* camera_allocator_hwl,
       std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries);
 
-  // Initialize the latest available gralloc buffer mapper.
-  status_t InitializeBufferMapper();
-
   // Initialize callbacks from HWL and callbacks to the client.
   void InitializeCallbacks();
 
@@ -168,9 +166,7 @@
 
   // Import the buffer handle of a buffer.
   // Must be protected by imported_buffer_handle_map_lock_.
-  template <class T, class U>
-  status_t ImportBufferHandleLocked(const sp<T> buffer_mapper,
-                                    const StreamBuffer& buffer);
+  status_t ImportBufferHandleLocked(const StreamBuffer& buffer);
 
   // Create a request with updated buffer handles and modified settings.
   // Must be protected by session_lock_.
@@ -190,11 +186,9 @@
 
   // Free all imported buffer handles belonging to the stream id.
   // Must be protected by imported_buffer_handle_map_lock_.
-  template <class T>
-  void FreeBufferHandlesLocked(const sp<T> buffer_mapper, int32_t stream_id);
+  void FreeBufferHandlesLocked(int32_t stream_id);
 
-  template <class T>
-  void FreeImportedBufferHandles(const sp<T> buffer_mapper);
+  void FreeImportedBufferHandles();
 
   // Clean up stale streams with new stream configuration.
   // Must be protected by session_lock_.
@@ -239,6 +233,10 @@
   // Process the capture result returned from the HWL
   void ProcessCaptureResult(std::unique_ptr<CaptureResult> result);
 
+  // Process the batched capture result returned from the HWL
+  void ProcessBatchCaptureResult(
+      std::vector<std::unique_ptr<CaptureResult>> results);
+
   // Notify error message with error code for stream of frame[frame_number].
   // Caller is responsible to make sure this function is called only once for any frame.
   void NotifyErrorMessage(uint32_t frame_number, int32_t stream_id,
@@ -287,14 +285,18 @@
   // within that group to one single stream ID for easier tracking.
   void DeriveGroupedStreamIdMap();
 
+  // Try handling a single capture result. Returns true when the result callback
+  // was sent in the function, or failed to handle it by running into an
+  // error. So the caller could skip sending the result callback when the
+  // function returned true.
+  bool TryHandleCaptureResult(std::unique_ptr<CaptureResult>& result);
+
+  // Tracks the returned buffers in capture results.
+  void TrackReturnedBuffers(const std::vector<StreamBuffer>& buffers);
+
   uint32_t camera_id_ = 0;
   std::unique_ptr<CameraDeviceSessionHwl> device_session_hwl_;
 
-  // Graphics buffer mapper used to import and free buffers.
-  sp<android::hardware::graphics::mapper::V2_0::IMapper> buffer_mapper_v2_;
-  sp<android::hardware::graphics::mapper::V3_0::IMapper> buffer_mapper_v3_;
-  sp<android::hardware::graphics::mapper::V4_0::IMapper> buffer_mapper_v4_;
-
   // Assuming callbacks to framework is thread-safe, the shared mutex is only
   // used to protect member variable writing and reading.
   std::shared_mutex session_callback_lock_;
@@ -365,8 +367,11 @@
   // hwl allocator
   CameraBufferAllocatorHwl* camera_allocator_hwl_ = nullptr;
 
-  // If buffer management API support.
-  bool buffer_management_supported_ = false;
+  // If buffer management API support is used for the session configured
+  bool buffer_management_used_ = false;
+
+  // If session specific hal buffer manager is supported by the HAL
+  bool session_buffer_management_supported_ = false;
 
   // Pending requests tracker used when buffer management API is enabled.
   // Protected by session_lock_.
diff --git a/common/hal/google_camera_hal/capture_session_utils.cc b/common/hal/google_camera_hal/capture_session_utils.cc
index 3d5f34c..bdc26d4 100644
--- a/common/hal/google_camera_hal/capture_session_utils.cc
+++ b/common/hal/google_camera_hal/capture_session_utils.cc
@@ -32,7 +32,8 @@
     CameraBufferAllocatorHwl* camera_buffer_allocator_hwl,
     CameraDeviceSessionHwl* camera_device_session_hwl,
     std::vector<HalStream>* hal_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc process_batch_capture_result) {
   // first pass: check predefined wrapper capture session
   for (auto sessionEntry : wrapper_capture_session_entries) {
     if (sessionEntry.IsStreamConfigurationSupported(camera_device_session_hwl,
@@ -61,7 +62,8 @@
                                                     stream_config)) {
       return sessionEntry.CreateSession(
           camera_device_session_hwl, stream_config, process_capture_result,
-          notify, hwl_session_callback, hal_config, camera_buffer_allocator_hwl);
+          process_batch_capture_result, notify, hwl_session_callback,
+          hal_config, camera_buffer_allocator_hwl);
     }
   }
   return nullptr;
diff --git a/common/hal/google_camera_hal/capture_session_utils.h b/common/hal/google_camera_hal/capture_session_utils.h
index f77c553..e544276 100644
--- a/common/hal/google_camera_hal/capture_session_utils.h
+++ b/common/hal/google_camera_hal/capture_session_utils.h
@@ -37,8 +37,9 @@
 using CaptureSessionCreateFunc = std::function<std::unique_ptr<CaptureSession>(
     CameraDeviceSessionHwl* device_session_hwl,
     const StreamConfiguration& stream_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-    HwlSessionCallback session_callback,
+    ProcessCaptureResultFunc process_capture_result,
+    ProcessBatchCaptureResultFunc process_capture_batch_result,
+    NotifyFunc notify, HwlSessionCallback session_callback,
     std::vector<HalStream>* hal_configured_streams,
     CameraBufferAllocatorHwl* camera_allocator_hwl)>;
 
@@ -82,7 +83,8 @@
     CameraBufferAllocatorHwl* camera_buffer_allocator_hwl,
     CameraDeviceSessionHwl* camera_device_session_hwl,
     std::vector<HalStream>* hal_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify);
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc process_batch_capture_result = nullptr);
 
 }  // namespace google_camera_hal
 }  // namespace android
diff --git a/common/hal/google_camera_hal/depth_process_block.cc b/common/hal/google_camera_hal/depth_process_block.cc
index b4f8121..afd5474 100644
--- a/common/hal/google_camera_hal/depth_process_block.cc
+++ b/common/hal/google_camera_hal/depth_process_block.cc
@@ -87,7 +87,7 @@
   // rt_request_processor and result_request_processor.
   block->rgb_ir_auto_cal_enabled_ =
       property_get_bool("vendor.camera.frontdepth.enableautocal", true);
-
+  block->device_session_hwl_ = device_session_hwl;
   return block;
 }
 
@@ -106,9 +106,12 @@
   res = characteristics->Get(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION,
                              &entry);
   if (res == OK && entry.count > 0) {
-    buffer_management_supported_ =
-        (entry.data.u8[0] >=
+    buffer_management_used_ =
+        (entry.data.u8[0] ==
          ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    session_buffer_management_supported_ =
+        (entry.data.u8[0] ==
+         ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE);
   }
 
   return OK;
@@ -250,7 +253,17 @@
       depth_generator_->SetResultCallback(nullptr);
     }
   }
-
+  if (session_buffer_management_supported_ &&
+      device_session_hwl_->configure_streams_v2()) {
+    bool use_buf_manager = false;
+    auto ret = device_session_hwl_->ShouldUseHalBufferManager(&use_buf_manager);
+    if (ret != OK) {
+      ALOGE("%s: shouldUseHalBufManager() failed", __FUNCTION__);
+      return ret;
+    } else {
+      buffer_management_used_ = use_buf_manager;
+    }
+  }
   is_configured_ = true;
   return OK;
 }
@@ -549,7 +562,7 @@
 
 status_t DepthProcessBlock::RequestDepthStreamBuffer(
     StreamBuffer* incomplete_buffer, uint32_t frame_number) {
-  if (!buffer_management_supported_) {
+  if (!buffer_management_used_) {
     return OK;
   }
 
@@ -693,7 +706,7 @@
     return BAD_VALUE;
   }
 
-  if (buffer_management_supported_) {
+  if (buffer_management_used_) {
     res = RequestDepthStreamBuffer(
         &(const_cast<CaptureRequest&>(request).output_buffers[0]),
         request.frame_number);
diff --git a/common/hal/google_camera_hal/depth_process_block.h b/common/hal/google_camera_hal/depth_process_block.h
index 15c4341..52514f8 100644
--- a/common/hal/google_camera_hal/depth_process_block.h
+++ b/common/hal/google_camera_hal/depth_process_block.h
@@ -177,8 +177,13 @@
   int32_t ir_active_array_width_ = 640;
   int32_t ir_active_array_height_ = 480;
 
-  // Whether the HAL Buffer Management is supported
-  bool buffer_management_supported_ = false;
+  // Whether the HAL Buffer Management is supported for the session
+  // configured
+  bool buffer_management_used_ = false;
+  bool session_buffer_management_supported_ = false;
+
+  // Owned by the client calling Create()
+  CameraDeviceSessionHwl* device_session_hwl_ = nullptr;
 
   // Whether the pipelined depth engine is enabled
   bool pipelined_depth_engine_enabled_ = false;
diff --git a/common/hal/google_camera_hal/dual_ir_capture_session.cc b/common/hal/google_camera_hal/dual_ir_capture_session.cc
index b1dfd00..4b52476 100644
--- a/common/hal/google_camera_hal/dual_ir_capture_session.cc
+++ b/common/hal/google_camera_hal/dual_ir_capture_session.cc
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_DualIrCaptureSession"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "dual_ir_capture_session.h"
+
 #include <log/log.h>
 #include <utils/Trace.h>
 
 #include <set>
 #include <vector>
 
-#include "dual_ir_capture_session.h"
 #include "dual_ir_request_processor.h"
 #include "dual_ir_result_request_processor.h"
 #include "hal_utils.h"
@@ -90,8 +91,9 @@
 std::unique_ptr<CaptureSession> DualIrCaptureSession::Create(
     CameraDeviceSessionHwl* device_session_hwl,
     const StreamConfiguration& stream_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-    HwlSessionCallback /*session_callback*/,
+    ProcessCaptureResultFunc process_capture_result,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/,
+    NotifyFunc notify, HwlSessionCallback /*session_callback*/,
     std::vector<HalStream>* hal_configured_streams,
     CameraBufferAllocatorHwl* /*camera_allocator_hwl*/) {
   ATRACE_CALL();
@@ -480,7 +482,9 @@
   // Only connect the depth segment of the realtime process chain when depth
   // stream is configured
   if (has_depth_stream_) {
-    depth_result_processor->SetResultCallback(process_capture_result, notify);
+    depth_result_processor->SetResultCallback(
+        process_capture_result, notify,
+        /*process_batch_capture_result=*/nullptr);
     res = ConnectProcessChain(rt_result_request_processor.get(),
                               std::move(depth_process_block),
                               std::move(depth_result_processor));
@@ -491,7 +495,8 @@
     }
   }
 
-  rt_result_request_processor->SetResultCallback(process_capture_result, notify);
+  rt_result_request_processor->SetResultCallback(
+      process_capture_result, notify, /*process_batch_capture_result=*/nullptr);
   res =
       ConnectProcessChain(request_processor_.get(), std::move(rt_process_block),
                           std::move(rt_result_request_processor));
diff --git a/common/hal/google_camera_hal/dual_ir_capture_session.h b/common/hal/google_camera_hal/dual_ir_capture_session.h
index 66236c9..b28820b 100644
--- a/common/hal/google_camera_hal/dual_ir_capture_session.h
+++ b/common/hal/google_camera_hal/dual_ir_capture_session.h
@@ -51,6 +51,8 @@
   // lifetime of DualIrCaptureSession.
   // stream_config is the stream configuration.
   // process_capture_result is the callback function to notify results.
+  // process_batch_capture_result is the callback function to notify batched
+  // results.
   // notify is the callback function to notify messages.
   // hal_configured_streams will be filled with HAL configured streams.
   // camera_allocator_hwl is owned by the caller and must be valid during the
@@ -58,8 +60,9 @@
   static std::unique_ptr<CaptureSession> Create(
       CameraDeviceSessionHwl* device_session_hwl,
       const StreamConfiguration& stream_config,
-      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-      HwlSessionCallback session_callback,
+      ProcessCaptureResultFunc process_capture_result,
+      ProcessBatchCaptureResultFunc process_batch_capture_result,
+      NotifyFunc notify, HwlSessionCallback session_callback,
       std::vector<HalStream>* hal_configured_streams,
       CameraBufferAllocatorHwl* camera_allocator_hwl);
 
diff --git a/common/hal/google_camera_hal/dual_ir_depth_result_processor.cc b/common/hal/google_camera_hal/dual_ir_depth_result_processor.cc
index ee30451..a81a448 100644
--- a/common/hal/google_camera_hal/dual_ir_depth_result_processor.cc
+++ b/common/hal/google_camera_hal/dual_ir_depth_result_processor.cc
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "DualIrDepthResultProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "dual_ir_depth_result_processor.h"
+
+#include <inttypes.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include <inttypes.h>
-
-#include "dual_ir_depth_result_processor.h"
 #include "hal_utils.h"
 
 namespace android {
@@ -50,7 +50,8 @@
 }
 
 void DualIrDepthResultProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
   notify_ = notify;
diff --git a/common/hal/google_camera_hal/dual_ir_depth_result_processor.h b/common/hal/google_camera_hal/dual_ir_depth_result_processor.h
index 4e9af84..6641e11 100644
--- a/common/hal/google_camera_hal/dual_ir_depth_result_processor.h
+++ b/common/hal/google_camera_hal/dual_ir_depth_result_processor.h
@@ -31,8 +31,9 @@
   virtual ~DualIrDepthResultProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/google_camera_hal/dual_ir_result_request_processor.cc b/common/hal/google_camera_hal/dual_ir_result_request_processor.cc
index 3511886..0e3819d 100644
--- a/common/hal/google_camera_hal/dual_ir_result_request_processor.cc
+++ b/common/hal/google_camera_hal/dual_ir_result_request_processor.cc
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_DualIrResultRequestProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "dual_ir_result_request_processor.h"
+
+#include <inttypes.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include <inttypes.h>
-
-#include "dual_ir_result_request_processor.h"
 #include "hal_utils.h"
 
 namespace android {
@@ -67,7 +67,8 @@
 }
 
 void DualIrResultRequestProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
diff --git a/common/hal/google_camera_hal/dual_ir_result_request_processor.h b/common/hal/google_camera_hal/dual_ir_result_request_processor.h
index 39bde53..534fa71 100644
--- a/common/hal/google_camera_hal/dual_ir_result_request_processor.h
+++ b/common/hal/google_camera_hal/dual_ir_result_request_processor.h
@@ -44,8 +44,9 @@
   virtual ~DualIrResultRequestProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/google_camera_hal/hdrplus_capture_session.cc b/common/hal/google_camera_hal/hdrplus_capture_session.cc
index 28abcce..64ba4d4 100644
--- a/common/hal/google_camera_hal/hdrplus_capture_session.cc
+++ b/common/hal/google_camera_hal/hdrplus_capture_session.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_HdrplusCaptureSession"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 #include "hdrplus_capture_session.h"
@@ -80,8 +80,9 @@
 std::unique_ptr<HdrplusCaptureSession> HdrplusCaptureSession::Create(
     CameraDeviceSessionHwl* device_session_hwl,
     const StreamConfiguration& stream_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-    HwlSessionCallback /*session_callback*/,
+    ProcessCaptureResultFunc process_capture_result,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/,
+    NotifyFunc notify, HwlSessionCallback /*session_callback*/,
     std::vector<HalStream>* hal_configured_streams,
     CameraBufferAllocatorHwl* /*camera_allocator_hwl*/) {
   ATRACE_CALL();
@@ -380,7 +381,8 @@
     ALOGE("%s: Creating RealtimeZslResultProcessor failed.", __FUNCTION__);
     return UNKNOWN_ERROR;
   }
-  result_processor->SetResultCallback(process_capture_result, notify);
+  result_processor->SetResultCallback(process_capture_result, notify,
+                                      /*process_batch_capture_result=*/nullptr);
 
   *realtime_process_block = std::move(process_block);
   *realtime_result_processor = std::move(result_processor);
@@ -426,7 +428,8 @@
     ALOGE("%s: Creating HdrplusResultProcessor failed.", __FUNCTION__);
     return UNKNOWN_ERROR;
   }
-  result_processor->SetResultCallback(process_capture_result, notify);
+  result_processor->SetResultCallback(process_capture_result, notify,
+                                      /*process_batch_capture_result=*/nullptr);
 
   status_t res = ConfigureHdrplusStreams(
       stream_config, hdrplus_request_processor_.get(), process_block.get());
diff --git a/common/hal/google_camera_hal/hdrplus_capture_session.h b/common/hal/google_camera_hal/hdrplus_capture_session.h
index 8369196..29d8993 100644
--- a/common/hal/google_camera_hal/hdrplus_capture_session.h
+++ b/common/hal/google_camera_hal/hdrplus_capture_session.h
@@ -50,6 +50,8 @@
   // lifetime of HdrplusCaptureSession.
   // stream_config is the stream configuration.
   // process_capture_result is the callback function to notify results.
+  // process_batch_capture_result is the callback function to notify batched
+  // results.
   // notify is the callback function to notify messages.
   // hal_configured_streams will be filled with HAL configured streams.
   // camera_allocator_hwl is owned by the caller and must be valid during the
@@ -57,8 +59,9 @@
   static std::unique_ptr<HdrplusCaptureSession> Create(
       CameraDeviceSessionHwl* device_session_hwl,
       const StreamConfiguration& stream_config,
-      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-      HwlSessionCallback session_callback,
+      ProcessCaptureResultFunc process_capture_result,
+      ProcessBatchCaptureResultFunc process_batch_capture_result,
+      NotifyFunc notify, HwlSessionCallback session_callback,
       std::vector<HalStream>* hal_configured_streams,
       CameraBufferAllocatorHwl* camera_allocator_hwl = nullptr);
 
diff --git a/common/hal/google_camera_hal/realtime_zsl_result_processor.cc b/common/hal/google_camera_hal/realtime_zsl_result_processor.cc
index 6580167..2735920 100644
--- a/common/hal/google_camera_hal/realtime_zsl_result_processor.cc
+++ b/common/hal/google_camera_hal/realtime_zsl_result_processor.cc
@@ -59,7 +59,8 @@
 }
 
 void RealtimeZslResultProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
   notify_ = notify;
diff --git a/common/hal/google_camera_hal/realtime_zsl_result_processor.h b/common/hal/google_camera_hal/realtime_zsl_result_processor.h
index 61106e3..7ab5490 100644
--- a/common/hal/google_camera_hal/realtime_zsl_result_processor.h
+++ b/common/hal/google_camera_hal/realtime_zsl_result_processor.h
@@ -36,8 +36,9 @@
   virtual ~RealtimeZslResultProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/google_camera_hal/rgbird_capture_session.cc b/common/hal/google_camera_hal/rgbird_capture_session.cc
index e41872b..5cd79a0 100644
--- a/common/hal/google_camera_hal/rgbird_capture_session.cc
+++ b/common/hal/google_camera_hal/rgbird_capture_session.cc
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_RgbirdCaptureSession"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "rgbird_capture_session.h"
+
 #include <cutils/properties.h>
+#include <inttypes.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include <inttypes.h>
 #include <set>
 
 #include "basic_result_processor.h"
@@ -31,7 +33,6 @@
 #include "hdrplus_request_processor.h"
 #include "hdrplus_result_processor.h"
 #include "multicam_realtime_process_block.h"
-#include "rgbird_capture_session.h"
 #include "rgbird_depth_result_processor.h"
 #include "rgbird_result_request_processor.h"
 #include "rgbird_rt_request_processor.h"
@@ -89,8 +90,9 @@
 std::unique_ptr<CaptureSession> RgbirdCaptureSession::Create(
     CameraDeviceSessionHwl* device_session_hwl,
     const StreamConfiguration& stream_config,
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-    HwlSessionCallback session_callback,
+    ProcessCaptureResultFunc process_capture_result,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/,
+    NotifyFunc notify, HwlSessionCallback session_callback,
     std::vector<HalStream>* hal_configured_streams,
     CameraBufferAllocatorHwl* /*camera_allocator_hwl*/) {
   ATRACE_CALL();
@@ -573,7 +575,8 @@
     ALOGE("%s: Creating RgbirdResultRequestProcessor failed.", __FUNCTION__);
     return UNKNOWN_ERROR;
   }
-  rt_result_processor->SetResultCallback(process_capture_result, notify);
+  rt_result_processor->SetResultCallback(
+      process_capture_result, notify, /*process_batch_capture_result=*/nullptr);
 
   if (is_hdrplus_supported_) {
     res = rt_result_processor->ConfigureStreams(internal_stream_manager_.get(),
@@ -652,7 +655,8 @@
     ALOGE("%s: Creating HdrplusResultProcessor failed.", __FUNCTION__);
     return UNKNOWN_ERROR;
   }
-  result_processor->SetResultCallback(process_capture_result, notify);
+  result_processor->SetResultCallback(process_capture_result, notify,
+                                      /*process_batch_capture_result=*/nullptr);
 
   StreamConfiguration process_block_stream_config;
   status_t res =
@@ -716,7 +720,9 @@
 
   // Connecting the depth segment of the realtime process chain.
   if (NeedDepthProcessBlock()) {
-    depth_result_processor->SetResultCallback(process_capture_result, notify);
+    depth_result_processor->SetResultCallback(
+        process_capture_result, notify,
+        /*process_batch_capture_result=*/nullptr);
 
     res = ConnectProcessChain(realtime_result_processor.get(),
                               std::move(depth_process_block),
diff --git a/common/hal/google_camera_hal/rgbird_capture_session.h b/common/hal/google_camera_hal/rgbird_capture_session.h
index 0ba6675..a9da992 100644
--- a/common/hal/google_camera_hal/rgbird_capture_session.h
+++ b/common/hal/google_camera_hal/rgbird_capture_session.h
@@ -54,14 +54,18 @@
   // stream_config is the stream configuration.
   // process_capture_result is the callback function to notify results.
   // notify is the callback function to notify messages.
+  // process_batch_capture_result is the callback function to notify batched
+  // results.
+  // notify is the callback function to notify messages.
   // hal_configured_streams will be filled with HAL configured streams.
   // camera_allocator_hwl is owned by the caller and must be valid during the
   // lifetime of RgbirdCaptureSession
   static std::unique_ptr<CaptureSession> Create(
       CameraDeviceSessionHwl* device_session_hwl,
       const StreamConfiguration& stream_config,
-      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
-      HwlSessionCallback session_callback,
+      ProcessCaptureResultFunc process_capture_result,
+      ProcessBatchCaptureResultFunc process_batch_capture_result,
+      NotifyFunc notify, HwlSessionCallback session_callback,
       std::vector<HalStream>* hal_configured_streams,
       CameraBufferAllocatorHwl* camera_allocator_hwl = nullptr);
 
diff --git a/common/hal/google_camera_hal/rgbird_depth_result_processor.cc b/common/hal/google_camera_hal/rgbird_depth_result_processor.cc
index 83d92e2..591a6a6 100644
--- a/common/hal/google_camera_hal/rgbird_depth_result_processor.cc
+++ b/common/hal/google_camera_hal/rgbird_depth_result_processor.cc
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_RgbirdDepthResultProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "rgbird_depth_result_processor.h"
+
+#include <inttypes.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include <inttypes.h>
-
 #include "hal_utils.h"
-#include "rgbird_depth_result_processor.h"
 
 namespace android {
 namespace google_camera_hal {
@@ -50,7 +50,8 @@
 }
 
 void RgbirdDepthResultProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
   notify_ = notify;
diff --git a/common/hal/google_camera_hal/rgbird_depth_result_processor.h b/common/hal/google_camera_hal/rgbird_depth_result_processor.h
index 88f9fd2..e4f201c 100644
--- a/common/hal/google_camera_hal/rgbird_depth_result_processor.h
+++ b/common/hal/google_camera_hal/rgbird_depth_result_processor.h
@@ -39,8 +39,9 @@
   virtual ~RgbirdDepthResultProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/google_camera_hal/rgbird_result_request_processor.cc b/common/hal/google_camera_hal/rgbird_result_request_processor.cc
index e48e3d1..a05384c 100644
--- a/common/hal/google_camera_hal/rgbird_result_request_processor.cc
+++ b/common/hal/google_camera_hal/rgbird_result_request_processor.cc
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_RgbirdResultRequestProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "rgbird_result_request_processor.h"
+
+#include <cutils/native_handle.h>
 #include <cutils/properties.h>
+#include <inttypes.h>
 #include <log/log.h>
 #include <sync/sync.h>
 #include <utils/Trace.h>
 
-#include <cutils/native_handle.h>
-#include <inttypes.h>
-
 #include "hal_utils.h"
-#include "rgbird_result_request_processor.h"
 
 namespace android {
 namespace google_camera_hal {
@@ -70,7 +70,8 @@
 }
 
 void RgbirdResultRequestProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
   notify_ = notify;
diff --git a/common/hal/google_camera_hal/rgbird_result_request_processor.h b/common/hal/google_camera_hal/rgbird_result_request_processor.h
index 0c35d28..84ee2c1 100644
--- a/common/hal/google_camera_hal/rgbird_result_request_processor.h
+++ b/common/hal/google_camera_hal/rgbird_result_request_processor.h
@@ -53,8 +53,9 @@
   virtual ~RgbirdResultRequestProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/google_camera_hal/snapshot_result_processor.cc b/common/hal/google_camera_hal/snapshot_result_processor.cc
index dd79daf..19dcd8e 100644
--- a/common/hal/google_camera_hal/snapshot_result_processor.cc
+++ b/common/hal/google_camera_hal/snapshot_result_processor.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_SnapshotResultProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 #include "snapshot_result_processor.h"
@@ -52,7 +52,8 @@
   yuv_stream_id_ = yuv_stream_id;
 }
 void SnapshotResultProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
diff --git a/common/hal/google_camera_hal/snapshot_result_processor.h b/common/hal/google_camera_hal/snapshot_result_processor.h
index 08ac23e..fbd976b 100644
--- a/common/hal/google_camera_hal/snapshot_result_processor.h
+++ b/common/hal/google_camera_hal/snapshot_result_processor.h
@@ -34,8 +34,9 @@
   virtual ~SnapshotResultProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc b/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc
index f6e658a..d42a9e2 100644
--- a/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc
+++ b/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc
@@ -442,7 +442,8 @@
         __FUNCTION__);
     return UNKNOWN_ERROR;
   }
-  realtime_result_processor->SetResultCallback(process_capture_result, notify);
+  realtime_result_processor->SetResultCallback(
+      process_capture_result, notify, /*process_batch_capture_result=*/nullptr);
 
   res = process_block->SetResultProcessor(std::move(realtime_result_processor));
   if (res != OK) {
@@ -490,7 +491,9 @@
       return UNKNOWN_ERROR;
     }
     basic_result_processor_ = basic_result_processor.get();
-    basic_result_processor->SetResultCallback(process_capture_result, notify);
+    basic_result_processor->SetResultCallback(
+        process_capture_result, notify,
+        /*process_batch_capture_result=*/nullptr);
 
     res =
         denoise_processor->SetResultProcessor(std::move(basic_result_processor));
@@ -603,7 +606,8 @@
   res = snapshot_process_block_->SetResultProcessor(
       std::move(snapshot_result_processor));
 
-  snapshot_result_processor_->SetResultCallback(process_capture_result, notify);
+  snapshot_result_processor_->SetResultCallback(
+      process_capture_result, notify, /*process_batch_capture_result=*/nullptr);
   res = ConfigureSnapshotStreams(stream_config);
   if (res != OK) {
     ALOGE("%s: Configuring snapshot stream failed: %s(%d)", __FUNCTION__,
diff --git a/common/hal/hwl_interface/camera_device_session_hwl.h b/common/hal/hwl_interface/camera_device_session_hwl.h
index c8094a5..ceeae59 100644
--- a/common/hal/hwl_interface/camera_device_session_hwl.h
+++ b/common/hal/hwl_interface/camera_device_session_hwl.h
@@ -73,6 +73,21 @@
   // NO_INIT.
   virtual status_t BuildPipelines() = 0;
 
+  // If the HAL buffer manager should be used for this session configuration.
+  // This should only be called after the pipelines have been configured.
+  // Otherwise this method will return NO_INIT. If the operation is not
+  // supported INVALID_OPERATION is returned.
+  // This is an hwl level method since the hwl layer can make the best decision
+  // about whether to use hal buffer manager for the session  configured - since
+  // it has device specific context.
+  virtual status_t ShouldUseHalBufferManager(bool* result) {
+    if (result == nullptr) {
+      return BAD_VALUE;
+    }
+    *result = false;
+    return INVALID_OPERATION;
+  }
+
   // Warm up pipeline to ready for taking request, this can be a NoOp for
   // implementation which doesn't support to put pipeline in standby mode
   // This call is optional for capture session before sending request. only
@@ -189,6 +204,17 @@
   // caching of file descriptors done by the HWL.
   virtual void RemoveCachedBuffers(const native_handle_t* /*handle*/) {
   }
+
+  void setConfigureStreamsV2(bool set) {
+    configure_streams_v2_ = set;
+  }
+
+  bool configure_streams_v2() const {
+    return configure_streams_v2_;
+  }
+
+ private:
+  bool configure_streams_v2_ = false;
 };
 
 }  // namespace google_camera_hal
diff --git a/common/hal/hwl_interface/hwl_types.h b/common/hal/hwl_interface/hwl_types.h
index 8168a7d..8017fef 100644
--- a/common/hal/hwl_interface/hwl_types.h
+++ b/common/hal/hwl_interface/hwl_types.h
@@ -17,6 +17,8 @@
 #ifndef HARDWARE_GOOGLE_CAMERA_HAL_HWL_INTERFACE_HWL_TYPES_H_
 #define HARDWARE_GOOGLE_CAMERA_HAL_HWL_INTERFACE_HWL_TYPES_H_
 
+#include <vector>
+
 #include "hal_types.h"
 
 namespace android {
@@ -81,6 +83,10 @@
 using HwlProcessPipelineResultFunc =
     std::function<void(std::unique_ptr<HwlPipelineResult> /*result*/)>;
 
+// Callback to invoke to send a batched result from HWL.
+using HwlProcessPipelineBatchResultFunc = std::function<void(
+    std::vector<std::unique_ptr<HwlPipelineResult>> /*results*/)>;
+
 // Callback to invoke to notify a message from HWL.
 using NotifyHwlPipelineMessageFunc = std::function<void(
     uint32_t /*pipeline_id*/, const NotifyMessage& /*message*/)>;
@@ -90,6 +96,9 @@
   // Callback to notify when a HWL pipeline produces a capture result.
   HwlProcessPipelineResultFunc process_pipeline_result;
 
+  // Callback to notify when a HWL pipeline produces a batched capture result.
+  HwlProcessPipelineBatchResultFunc process_pipeline_batch_result;
+
   // Callback to notify shutters or errors.
   NotifyHwlPipelineMessageFunc notify;
 };
diff --git a/common/hal/hwl_interface/result_processor.h b/common/hal/hwl_interface/result_processor.h
index 28eef51..165f54d 100644
--- a/common/hal/hwl_interface/result_processor.h
+++ b/common/hal/hwl_interface/result_processor.h
@@ -36,8 +36,9 @@
 
   // Set the callbacks to send the finished results. Must be called before
   // calling ProcessResult.
-  virtual void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                                 NotifyFunc notify) = 0;
+  virtual void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) = 0;
 
   // Add pending requests to the result processor.
   //
@@ -57,6 +58,13 @@
   // Called by a ProcessBlock to send the capture results.
   virtual void ProcessResult(ProcessBlockResult block_result) = 0;
 
+  // Called by a ProcessBlock to send the batched capture results.
+  virtual void ProcessBatchResult(std::vector<ProcessBlockResult> block_results) {
+    for (auto& result : block_results) {
+      ProcessResult(std::move(result));
+    }
+  }
+
   // Called by a ProcessBlock to notify a message.
   virtual void Notify(const ProcessBlockNotifyMessage& block_message) = 0;
 
diff --git a/common/hal/tests/Android.bp b/common/hal/tests/Android.bp
index 16c943d..79d5a36 100644
--- a/common/hal/tests/Android.bp
+++ b/common/hal/tests/Android.bp
@@ -55,9 +55,6 @@
     ],
     shared_libs: [
         "android.hardware.camera.provider@2.4",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
         "lib_profiler",
         "libcamera_metadata",
         "libcutils",
@@ -95,9 +92,6 @@
         "libgooglecamerahal",
         "libgooglecamerahalutils",
         "android.hardware.camera.provider@2.4",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
         "libcamera_metadata",
         "libcutils",
         "libhardware",
diff --git a/common/hal/tests/camera_device_session_tests.cc b/common/hal/tests/camera_device_session_tests.cc
index 75682a2..fba6116 100644
--- a/common/hal/tests/camera_device_session_tests.cc
+++ b/common/hal/tests/camera_device_session_tests.cc
@@ -359,7 +359,10 @@
   for (auto& resolution : preview_resolutions) {
     test_utils::GetPreviewOnlyStreamConfiguration(
         &preview_config, resolution.first, resolution.second);
-    res = session->ConfigureStreams(preview_config, &hal_configured_streams);
+    ConfigureStreamsReturn hal_config;
+    res = session->ConfigureStreams(preview_config, /*interfaceV3*/ false,
+                                    &hal_config);
+    hal_configured_streams = std::move(hal_config.hal_streams);
     EXPECT_EQ(res, OK);
   }
 }
@@ -408,8 +411,11 @@
 
   test_utils::GetPreviewOnlyStreamConfiguration(&preview_config, kPreviewWidth,
                                                 kPreviewHeight);
-  ASSERT_EQ(session->ConfigureStreams(preview_config, &hal_configured_streams),
+  ConfigureStreamsReturn hal_config;
+  ASSERT_EQ(session->ConfigureStreams(preview_config, /*interfaceV3*/ false,
+                                      &hal_config),
             OK);
+  hal_configured_streams = std::move(hal_config.hal_streams);
   ASSERT_EQ(hal_configured_streams.size(), static_cast<uint32_t>(1));
 
   // Allocate buffers.
diff --git a/common/hal/tests/mock_result_processor.h b/common/hal/tests/mock_result_processor.h
index fdf36cf..e3ed279 100644
--- a/common/hal/tests/mock_result_processor.h
+++ b/common/hal/tests/mock_result_processor.h
@@ -26,9 +26,10 @@
 // Defines a ResultProcessor mock using gmock.
 class MockResultProcessor : public ResultProcessor {
  public:
-  MOCK_METHOD2(SetResultCallback,
+  MOCK_METHOD3(SetResultCallback,
                void(ProcessCaptureResultFunc process_capture_result,
-                    NotifyFunc notify));
+                    NotifyFunc notify,
+                    ProcessBatchCaptureResultFunc process_batch_capture_result));
 
   MOCK_METHOD2(
       AddPendingRequests,
diff --git a/common/hal/tests/result_processor_tests.cc b/common/hal/tests/result_processor_tests.cc
index 51b2bd7..341b41b 100644
--- a/common/hal/tests/result_processor_tests.cc
+++ b/common/hal/tests/result_processor_tests.cc
@@ -15,9 +15,9 @@
  */
 
 #define LOG_TAG "ResultProcessorTest"
+#include <gtest/gtest.h>
 #include <log/log.h>
 
-#include <gtest/gtest.h>
 #include <memory>
 
 #include "basic_result_processor.h"
@@ -59,7 +59,9 @@
     ASSERT_NE(result_processor, nullptr)
         << "Creating a result processor failed";
 
-    result_processor->SetResultCallback(process_capture_result, notify);
+    result_processor->SetResultCallback(
+        process_capture_result, notify,
+        /*process_batch_capture_result=*/nullptr);
   }
 }
 
@@ -116,7 +118,9 @@
     SendResultsAndMessages(result_processor.get());
 
     // Test again after setting result callback.
-    result_processor->SetResultCallback(process_capture_result, notify);
+    result_processor->SetResultCallback(
+        process_capture_result, notify,
+        /*process_batch_capture_result=*/nullptr);
     SendResultsAndMessages(result_processor.get());
   }
 }
@@ -135,7 +139,8 @@
   NotifyFunc notify = NotifyFunc(
       [&](const NotifyMessage& /*message*/) { message_received = true; });
 
-  result_processor->SetResultCallback(process_capture_result, notify);
+  result_processor->SetResultCallback(process_capture_result, notify,
+                                      /*process_batch_capture_result=*/nullptr);
 
   ProcessBlockResult null_result;
   result_processor->ProcessResult(std::move(null_result));
@@ -165,7 +170,8 @@
 
   NotifyFunc notify = NotifyFunc([&](const NotifyMessage& /*message*/) {});
 
-  result_processor->SetResultCallback(process_capture_result, notify);
+  result_processor->SetResultCallback(process_capture_result, notify,
+                                      /*process_batch_capture_result=*/nullptr);
 
   std::vector<ProcessBlockRequest> requests(1);
   requests[0].request.output_buffers = {StreamBuffer{}};
diff --git a/common/hal/utils/hdrplus_result_processor.cc b/common/hal/utils/hdrplus_result_processor.cc
index b1747ef..ba08bb4 100644
--- a/common/hal/utils/hdrplus_result_processor.cc
+++ b/common/hal/utils/hdrplus_result_processor.cc
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "GCH_HdrplusResultProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
+#include "hdrplus_result_processor.h"
+
+#include <inttypes.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
-#include <inttypes.h>
-
 #include "hal_utils.h"
-#include "hdrplus_result_processor.h"
 
 namespace android {
 namespace google_camera_hal {
@@ -52,7 +52,8 @@
   raw_stream_id_ = raw_stream_id;
 }
 void HdrplusResultProcessor::SetResultCallback(
-    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify) {
+    ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+    ProcessBatchCaptureResultFunc /*process_batch_capture_result*/) {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(callback_lock_);
   process_capture_result_ = process_capture_result;
diff --git a/common/hal/utils/hdrplus_result_processor.h b/common/hal/utils/hdrplus_result_processor.h
index e6062a5..6719eb9 100644
--- a/common/hal/utils/hdrplus_result_processor.h
+++ b/common/hal/utils/hdrplus_result_processor.h
@@ -34,8 +34,9 @@
   virtual ~HdrplusResultProcessor() = default;
 
   // Override functions of ResultProcessor start.
-  void SetResultCallback(ProcessCaptureResultFunc process_capture_result,
-                         NotifyFunc notify) override;
+  void SetResultCallback(
+      ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
+      ProcessBatchCaptureResultFunc process_batch_capture_result) override;
 
   status_t AddPendingRequests(
       const std::vector<ProcessBlockRequest>& process_block_requests,
diff --git a/common/hal/utils/realtime_process_block.cc b/common/hal/utils/realtime_process_block.cc
index d082886..d5679be 100644
--- a/common/hal/utils/realtime_process_block.cc
+++ b/common/hal/utils/realtime_process_block.cc
@@ -65,6 +65,12 @@
         NotifyHwlPipelineResult(std::move(result));
       });
 
+  hwl_pipeline_callback_.process_pipeline_batch_result =
+      HwlProcessPipelineBatchResultFunc(
+          [this](std::vector<std::unique_ptr<HwlPipelineResult>> results) {
+            NotifyHwlPipelineBatchResult(std::move(results));
+          });
+
   hwl_pipeline_callback_.notify = NotifyHwlPipelineMessageFunc(
       [this](uint32_t pipeline_id, const NotifyMessage& message) {
         NotifyHwlPipelineMessage(pipeline_id, message);
@@ -203,6 +209,31 @@
   result_processor_->ProcessResult(std::move(result));
 }
 
+void RealtimeProcessBlock::NotifyHwlPipelineBatchResult(
+    std::vector<std::unique_ptr<HwlPipelineResult>> hwl_results) {
+  ATRACE_CALL();
+  std::lock_guard<std::mutex> lock(result_processor_lock_);
+  if (result_processor_ == nullptr) {
+    ALOGE("%s: result processor is nullptr. Dropping a result", __FUNCTION__);
+    return;
+  }
+
+  std::vector<ProcessBlockResult> block_results;
+  block_results.reserve(hwl_results.size());
+  for (auto& hwl_result : hwl_results) {
+    auto capture_result =
+        hal_utils::ConvertToCaptureResult(std::move(hwl_result));
+    if (capture_result == nullptr) {
+      ALOGE("%s: Converting to capture result failed.", __FUNCTION__);
+      return;
+    }
+
+    block_results.push_back(
+        ProcessBlockResult{.result = std::move(capture_result)});
+  }
+  result_processor_->ProcessBatchResult(std::move(block_results));
+}
+
 void RealtimeProcessBlock::NotifyHwlPipelineMessage(
     uint32_t /*pipeline_id*/, const NotifyMessage& message) {
   ATRACE_CALL();
diff --git a/common/hal/utils/realtime_process_block.h b/common/hal/utils/realtime_process_block.h
index b1fcf6c..e2eb90f 100644
--- a/common/hal/utils/realtime_process_block.h
+++ b/common/hal/utils/realtime_process_block.h
@@ -18,6 +18,7 @@
 #define HARDWARE_GOOGLE_CAMERA_HAL_GOOGLE_CAMERA_HAL_REALTIME_PROCESS_BLOCK_H_
 
 #include <shared_mutex>
+#include <vector>
 
 #include "process_block.h"
 
@@ -68,6 +69,10 @@
   // Invoked when the HWL pipeline sends a result.
   void NotifyHwlPipelineResult(std::unique_ptr<HwlPipelineResult> hwl_result);
 
+  // Invoked when the HWL pipeline sends a batched result.
+  void NotifyHwlPipelineBatchResult(
+      std::vector<std::unique_ptr<HwlPipelineResult>> hwl_results);
+
   // Invoked when the HWL pipeline sends a message.
   void NotifyHwlPipelineMessage(uint32_t pipeline_id,
                                 const NotifyMessage& message);
diff --git a/common/hal/utils/utils.cc b/common/hal/utils/utils.cc
index b9efc80..f2d8122 100644
--- a/common/hal/utils/utils.cc
+++ b/common/hal/utils/utils.cc
@@ -38,15 +38,16 @@
 
 using FpsRange = std::pair<int32_t, int32_t>;
 
+static const std::vector<std::pair<FpsRange, FpsRange>> kAcceptableTransitions = {
+    std::make_pair<FpsRange, FpsRange>({2, 2}, {12, 12}),
+    std::make_pair<FpsRange, FpsRange>({12, 12}, {30, 30}),
+    std::make_pair<FpsRange, FpsRange>({30, 30}, {60, 60}),
+    std::make_pair<FpsRange, FpsRange>({24, 24}, {24, 30}),
+    std::make_pair<FpsRange, FpsRange>({24, 24}, {30, 30}),
+};
+
 bool IsAcceptableThrottledFpsChange(const FpsRange& old_fps,
                                     const FpsRange& new_fps) {
-  // We allow smooth transitions between [30,30] to [60,60] and [24,24] and [24,30].
-  constexpr std::array<std::pair<FpsRange, FpsRange>, 3> kAcceptableTransitions = {
-      std::make_pair<FpsRange, FpsRange>({30, 30}, {60, 60}),
-      std::make_pair<FpsRange, FpsRange>({24, 24}, {24, 30}),
-      std::make_pair<FpsRange, FpsRange>({24, 24}, {30, 30}),
-  };
-
   for (const std::pair<FpsRange, FpsRange>& range : kAcceptableTransitions) {
     // We don't care about the direction of the transition.
     if ((old_fps == range.first && new_fps == range.second) ||
@@ -54,7 +55,6 @@
       return true;
     }
   }
-
   return false;
 }
 }  // namespace
@@ -430,9 +430,9 @@
       if (old_max_fps == new_max_fps || ignore_fps_range_diff) {
         ALOGI(
             "%s: Ignore fps (%d, %d) to (%d, %d). "
-            "video_60_to_30fps_thermal_throttle: %u",
+            "video_60_to_30fps_thermal_throttle: %u. video_fps_throttle: %u.",
             __FUNCTION__, old_min_fps, old_max_fps, new_min_fps, new_max_fps,
-            video_60_to_30fps_thermal_throttle);
+            video_60_to_30fps_thermal_throttle, video_fps_throttle);
         continue;
       }
 
diff --git a/common/profiler/profiler.cc b/common/profiler/profiler.cc
index 689ef35..c090ab2 100644
--- a/common/profiler/profiler.cc
+++ b/common/profiler/profiler.cc
@@ -21,7 +21,6 @@
 #include <sys/stat.h>
 
 #include <fstream>
-#include <list>
 #include <mutex>
 #include <unordered_map>
 #include <vector>
@@ -95,7 +94,7 @@
   void SetFpsPrintInterval(int32_t interval_seconds) override final;
 
   // Get the latency associated with the name
-  std::list<std::pair<std::string, float>> GetLatencyData() override final;
+  std::vector<LatencyEvent> GetLatencyData() override final;
 
   std::string GetUseCase() const override final {
     return use_case_;
@@ -111,6 +110,11 @@
     int32_t request_id = 0;
   };
 
+  struct TimeSlotEvent {
+    std::string name;
+    TimeSlot slot;
+  };
+
   // A structure to store node's profiling result.
   struct TimeResult {
     std::string node_name;
@@ -499,9 +503,9 @@
 }
 
 // Get the latency associated with the name
-std::list<std::pair<std::string, float>> ProfilerImpl::GetLatencyData() {
-  std::list<std::pair<std::string, TimeSlot>> time_results;
-  std::list<std::pair<std::string, float>> latency_data;
+std::vector<Profiler::LatencyEvent> ProfilerImpl::GetLatencyData() {
+  std::vector<TimeSlotEvent> time_results;
+  std::vector<LatencyEvent> latency_data;
   for (const auto& [node_name, time_series] : timing_map_) {
     for (const auto& slot : time_series) {
       if (slot.count > 0 && time_results.size() < time_results.max_size()) {
@@ -509,8 +513,9 @@
       }
     }
   }
-  time_results.sort(
-      [](const auto& a, const auto& b) { return a.second.end < b.second.end; });
+  std::sort(
+      time_results.begin(), time_results.end(),
+      [](const auto& a, const auto& b) { return a.slot.end < b.slot.end; });
 
   for (const auto& [node_name, slot] : time_results) {
     if (slot.count > 0) {
@@ -549,7 +554,7 @@
     ALOGI("Profiling Case: %s", use_case_.c_str());
 
     // Sort by end time.
-    std::list<std::pair<std::string, TimeSlot>> time_results;
+    std::vector<TimeSlotEvent> time_results;
     for (const auto& [node_name, time_series] : timing_map_) {
       for (const auto& slot : time_series) {
         if (slot.count > 0 && time_results.size() < time_results.max_size()) {
@@ -557,9 +562,9 @@
         }
       }
     }
-    time_results.sort([](const auto& a, const auto& b) {
-      return a.second.end < b.second.end;
-    });
+    std::sort(
+        time_results.begin(), time_results.end(),
+        [](const auto& a, const auto& b) { return a.slot.end < b.slot.end; });
 
     for (const auto& [node_name, slot] : time_results) {
       if (slot.count > 0) {
@@ -598,7 +603,7 @@
   void PrintResult() override final{};
   void ProfileFrameRate(const std::string&) override final{};
   void SetFpsPrintInterval(int32_t) override final{};
-  std::list<std::pair<std::string, float>> GetLatencyData() override final {
+  std::vector<LatencyEvent> GetLatencyData() override final {
     return {};
   }
   std::string GetUseCase() const override final {
diff --git a/common/profiler/profiler.h b/common/profiler/profiler.h
index 8788e59..152a116 100644
--- a/common/profiler/profiler.h
+++ b/common/profiler/profiler.h
@@ -20,9 +20,9 @@
 #include <cutils/properties.h>
 
 #include <limits>
-#include <list>
 #include <memory>
 #include <string>
+#include <vector>
 
 namespace google {
 namespace camera_common {
@@ -150,6 +150,11 @@
 
   virtual ~Profiler() = default;
 
+  struct LatencyEvent {
+    std::string name;
+    float duration;
+  };
+
   // adb setprop options.
   enum SetPropFlag {
     kDisable = 0,
@@ -208,7 +213,7 @@
   // The interval unit is second and interval_seconds must >= 1
   virtual void SetFpsPrintInterval(int32_t interval_seconds) = 0;
 
-  virtual std::list<std::pair<std::string, float>> GetLatencyData() = 0;
+  virtual std::vector<LatencyEvent> GetLatencyData() = 0;
 
   virtual std::string GetUseCase() const = 0;
 
diff --git a/devices/EmulatedCamera/hwl/Android.bp b/devices/EmulatedCamera/hwl/Android.bp
index fad5ef0..b452a70 100644
--- a/devices/EmulatedCamera/hwl/Android.bp
+++ b/devices/EmulatedCamera/hwl/Android.bp
@@ -46,6 +46,7 @@
         "libjsoncpp",
         "liblog",
         "libsync",
+        "libui",
         "libutils",
         "libyuv",
     ],
diff --git a/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.cpp b/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.cpp
index 93cbe57..6ad921d 100644
--- a/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.cpp
+++ b/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.cpp
@@ -32,7 +32,6 @@
 
 namespace android {
 
-using google_camera_hal::Rect;
 using google_camera_hal::utils::GetSensorActiveArraySize;
 using google_camera_hal::utils::HasCapability;
 
@@ -106,7 +105,7 @@
 
 static std::pair<Dimension, Dimension> GetArrayDimensions(
     uint32_t camera_id, const HalCameraMetadata* metadata) {
-  Rect active_array_size;
+  google_camera_hal::Rect active_array_size;
   Dimension active_array_size_dimension;
   Dimension active_array_size_dimension_maximum_resolution;
   status_t ret = GetSensorActiveArraySize(metadata, &active_array_size);
@@ -170,6 +169,14 @@
     return ret;
   }
 
+  ret = SupportsSessionHalBufManager(static_metadata_.get(),
+                                     &supports_session_hal_buf_manager_);
+  if (ret != OK) {
+    ALOGE("%s: Unable to get sensor hal buffer manager support %s (%d)",
+          __FUNCTION__, strerror(-ret), ret);
+    return ret;
+  }
+
   logical_chars_.emplace(camera_id_, sensor_chars_);
   for (const auto& it : *physical_device_map_) {
     SensorCharacteristics physical_chars;
@@ -374,6 +381,27 @@
   return OK;
 }
 
+status_t EmulatedCameraDeviceSessionHwlImpl::ShouldUseHalBufferManager(
+    bool* result) {
+  if (result == nullptr) {
+    ALOGE("%s result is nullptr", __FUNCTION__);
+    return BAD_VALUE;
+  }
+  *result = false;
+  if (!pipelines_built_) {
+    ALOGE("%s: Pipelines haven't been built yet", __FUNCTION__);
+    return INVALID_OPERATION;
+  }
+  if (!supports_session_hal_buf_manager_) {
+    return OK;
+  }
+  // Heuristic which doesn't necessarily correspond to real scenarios
+  if (pipelines_.size() >= 1 && pipelines_[0].streams.size() >= 2) {
+    *result = true;
+  }
+  return OK;
+}
+
 void EmulatedCameraDeviceSessionHwlImpl::DestroyPipelines() {
   ATRACE_CALL();
   std::lock_guard<std::mutex> lock(api_mutex_);
diff --git a/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.h b/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.h
index 81631cf..06c3609 100644
--- a/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.h
+++ b/devices/EmulatedCamera/hwl/EmulatedCameraDeviceSessionHWLImpl.h
@@ -103,6 +103,8 @@
 
   status_t BuildPipelines() override;
 
+  status_t ShouldUseHalBufferManager(bool* result) override;
+
   status_t PreparePipeline(uint32_t /*pipeline_id*/,
                            uint32_t /*frame_number*/) override {
     return OK;
@@ -202,6 +204,7 @@
   bool error_state_ = false;
   bool pipelines_built_ = false;
   bool has_raw_stream_ = false;
+  bool supports_session_hal_buf_manager_ = false;
   std::unique_ptr<HalCameraMetadata> static_metadata_;
   std::vector<EmulatedPipeline> pipelines_;
   std::shared_ptr<EmulatedRequestProcessor> request_processor_;
diff --git a/devices/EmulatedCamera/hwl/EmulatedCameraProviderHWLImpl.cpp b/devices/EmulatedCamera/hwl/EmulatedCameraProviderHWLImpl.cpp
index d4fae3e..7eb7743 100644
--- a/devices/EmulatedCamera/hwl/EmulatedCameraProviderHWLImpl.cpp
+++ b/devices/EmulatedCamera/hwl/EmulatedCameraProviderHWLImpl.cpp
@@ -35,11 +35,14 @@
 namespace android {
 
 // Location of the camera configuration files.
-constexpr std::string_view kConfigurationFileNames[] = {
-    "emu_camera_back.json",
-    "emu_camera_front.json",
-    "emu_camera_depth.json",
-};
+constexpr std::string_view kCameraConfigBack = "emu_camera_back.json";
+constexpr std::string_view kCameraConfigFront = "emu_camera_front.json";
+constexpr std::string_view kCameraConfigExternal = "emu_camera_external.json";
+constexpr std::string_view kCameraConfigDepth = "emu_camera_depth.json";
+constexpr std::string_view kCameraConfigFiles[] = {
+    kCameraConfigBack, kCameraConfigFront, kCameraConfigExternal,
+    kCameraConfigDepth};
+
 constexpr std::string_view kConfigurationFileDirVendor = "/vendor/etc/config/";
 constexpr std::string_view kConfigurationFileDirApex =
     "/apex/com.google.emulated.camera.provider.hal/etc/config/";
@@ -711,8 +714,17 @@
   }
   char prop[PROPERTY_VALUE_MAX];
   if (!property_get_bool("ro.boot.qemu", false)) {
-    for (const auto& iter : kConfigurationFileNames) {
-      config_file_locations.emplace_back(config_dir + iter.data());
+    // Cuttlefish
+    property_get("ro.vendor.camera.config", prop, nullptr);
+    if (strcmp(prop, "external") == 0) {
+      config_file_locations.emplace_back(config_dir +
+                                         kCameraConfigExternal.data());
+      logical_id = 1;
+    } else {
+      // Default phone layout.
+      config_file_locations.emplace_back(config_dir + kCameraConfigBack.data());
+      config_file_locations.emplace_back(config_dir + kCameraConfigFront.data());
+      config_file_locations.emplace_back(config_dir + kCameraConfigDepth.data());
     }
   } else {
     // Android Studio Emulator
@@ -721,22 +733,22 @@
         property_get("vendor.qemu.sf.fake_camera", prop, nullptr);
         if (strcmp(prop, "both") == 0) {
           config_file_locations.emplace_back(config_dir +
-                                             kConfigurationFileNames[0].data());
+                                             kCameraConfigBack.data());
           config_file_locations.emplace_back(config_dir +
-                                             kConfigurationFileNames[1].data());
+                                             kCameraConfigFront.data());
         } else if (strcmp(prop, "front") == 0) {
           config_file_locations.emplace_back(config_dir +
-                                             kConfigurationFileNames[1].data());
+                                             kCameraConfigFront.data());
           logical_id = 1;
         } else if (strcmp(prop, "back") == 0) {
           config_file_locations.emplace_back(config_dir +
-                                             kConfigurationFileNames[0].data());
+                                             kCameraConfigBack.data());
           logical_id = 1;
         }
       }
     }
   }
-  static_metadata_.resize(ARRAY_SIZE(kConfigurationFileNames));
+  static_metadata_.resize(ARRAY_SIZE(kCameraConfigFiles));
 
   for (const auto& config_path : config_file_locations) {
     if (!android::base::ReadFileToString(config_path, &config)) {
diff --git a/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.cpp b/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.cpp
index 0195c95..cd3c136 100644
--- a/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.cpp
+++ b/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.cpp
@@ -99,9 +99,15 @@
 
 std::unique_ptr<HwlPipelineResult>
 EmulatedLogicalRequestState::InitializeLogicalResult(uint32_t pipeline_id,
-                                                     uint32_t frame_number) {
-  auto ret = logical_request_state_->InitializeResult(pipeline_id, frame_number);
-  if (is_logical_device_) {
+                                                     uint32_t frame_number,
+                                                     bool is_partial_result) {
+  auto ret =
+      is_partial_result
+          ? logical_request_state_->InitializePartialResult(pipeline_id,
+                                                            frame_number)
+          : logical_request_state_->InitializeResult(pipeline_id, frame_number);
+
+  if (is_logical_device_ && !is_partial_result) {
     if ((physical_camera_output_ids_.get() != nullptr) &&
         (!physical_camera_output_ids_->empty())) {
       ret->physical_camera_results.reserve(physical_camera_output_ids_->size());
diff --git a/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.h b/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.h
index dcf1595..77f8955 100644
--- a/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.h
+++ b/devices/EmulatedCamera/hwl/EmulatedLogicalRequestState.h
@@ -68,7 +68,7 @@
       std::unique_ptr<HalCameraMetadata>* default_settings /*out*/);
 
   std::unique_ptr<HwlPipelineResult> InitializeLogicalResult(
-      uint32_t pipeline_id, uint32_t frame_number);
+      uint32_t pipeline_id, uint32_t frame_number, bool is_partial_result);
 
   status_t InitializeLogicalSettings(
       std::unique_ptr<HalCameraMetadata> request_settings,
diff --git a/devices/EmulatedCamera/hwl/EmulatedRequestProcessor.cpp b/devices/EmulatedCamera/hwl/EmulatedRequestProcessor.cpp
index ef57437..536b423 100644
--- a/devices/EmulatedCamera/hwl/EmulatedRequestProcessor.cpp
+++ b/devices/EmulatedCamera/hwl/EmulatedRequestProcessor.cpp
@@ -298,7 +298,7 @@
   bool isP010 = static_cast<android_pixel_format_v1_1_t>(
                     stream.override_format) == HAL_PIXEL_FORMAT_YCBCR_P010;
   if ((isYUV_420_888) || (isP010)) {
-    IMapper::Rect map_rect = {0, 0, width, height};
+    android::Rect map_rect = {0, 0, width, height};
     auto yuv_layout = importer_->lockYCbCr(buffer, usage, map_rect);
     if ((yuv_layout.y != nullptr) && (yuv_layout.cb != nullptr) &&
         (yuv_layout.cr != nullptr)) {
@@ -308,17 +308,18 @@
           static_cast<uint8_t*>(yuv_layout.cb);
       sensor_buffer->plane.img_y_crcb.img_cr =
           static_cast<uint8_t*>(yuv_layout.cr);
-      sensor_buffer->plane.img_y_crcb.y_stride = yuv_layout.yStride;
-      sensor_buffer->plane.img_y_crcb.cbcr_stride = yuv_layout.cStride;
-      sensor_buffer->plane.img_y_crcb.cbcr_step = yuv_layout.chromaStep;
-      if (isYUV_420_888 && (yuv_layout.chromaStep == 2) &&
+      sensor_buffer->plane.img_y_crcb.y_stride = yuv_layout.ystride;
+      sensor_buffer->plane.img_y_crcb.cbcr_stride = yuv_layout.cstride;
+      sensor_buffer->plane.img_y_crcb.cbcr_step = yuv_layout.chroma_step;
+      if (isYUV_420_888 && (yuv_layout.chroma_step == 2) &&
           std::abs(sensor_buffer->plane.img_y_crcb.img_cb -
                    sensor_buffer->plane.img_y_crcb.img_cr) != 1) {
-        ALOGE("%s: Unsupported YUV layout, chroma step: %u U/V plane delta: %u",
-              __FUNCTION__, yuv_layout.chromaStep,
-              static_cast<unsigned>(
-                  std::abs(sensor_buffer->plane.img_y_crcb.img_cb -
-                           sensor_buffer->plane.img_y_crcb.img_cr)));
+        ALOGE(
+            "%s: Unsupported YUV layout, chroma step: %zu U/V plane delta: %u",
+            __FUNCTION__, yuv_layout.chroma_step,
+            static_cast<unsigned>(
+                std::abs(sensor_buffer->plane.img_y_crcb.img_cb -
+                         sensor_buffer->plane.img_y_crcb.img_cr)));
         return BAD_VALUE;
       }
       sensor_buffer->plane.img_y_crcb.bytesPerPixel = isP010 ? 2 : 1;
@@ -338,7 +339,7 @@
       sensor_buffer->plane.img.img =
           static_cast<uint8_t*>(importer_->lock(buffer, usage, buffer_size));
     } else {
-      IMapper::Rect region{0, 0, width, height};
+      android::Rect region{0, 0, width, height};
       sensor_buffer->plane.img.img =
           static_cast<uint8_t*>(importer_->lock(buffer, usage, region));
     }
@@ -492,8 +493,12 @@
           }
 
           if (ret == OK) {
-            auto result = request_state_->InitializeLogicalResult(pipeline_id,
-                                                                  frame_number);
+            auto partial_result = request_state_->InitializeLogicalResult(
+                pipeline_id, frame_number,
+                /*partial result*/ true);
+            auto result = request_state_->InitializeLogicalResult(
+                pipeline_id, frame_number,
+                /*partial result*/ false);
             // The screen rotation will be the same for all logical and physical devices
             uint32_t screen_rotation = screen_rotation_;
             for (auto it = logical_settings->begin();
@@ -503,7 +508,8 @@
 
             sensor_->SetCurrentRequest(
                 std::move(logical_settings), std::move(result),
-                std::move(input_buffers), std::move(output_buffers));
+                std::move(partial_result), std::move(input_buffers),
+                std::move(output_buffers));
           } else {
             NotifyMessage msg{.type = MessageType::kError,
                               .message.error = {
diff --git a/devices/EmulatedCamera/hwl/EmulatedRequestState.cpp b/devices/EmulatedCamera/hwl/EmulatedRequestState.cpp
index b79f8fa..ff6ed12 100644
--- a/devices/EmulatedCamera/hwl/EmulatedRequestState.cpp
+++ b/devices/EmulatedCamera/hwl/EmulatedRequestState.cpp
@@ -735,6 +735,20 @@
     }
   }
 
+  // Check manual flash strength level
+  ret = request_settings_->Get(ANDROID_FLASH_STRENGTH_LEVEL, &entry);
+  if ((ret == OK) && (entry.count == 1)) {
+    flash_strength_level_ = entry.data.i32[0];
+    if (ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL > 1 &&
+            ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL > 1 && is_flash_supported_) {
+      ALOGI("%s: Device supports manual flash strength control", __FUNCTION__);
+      flash_strength_level_ = entry.data.i32[0];
+    } else {
+        ALOGI("%s: Device does not support manual flash strength control", __FUNCTION__);
+        return BAD_VALUE;
+      }
+    }
+
   // Check video stabilization parameter
   uint8_t edge_mode = ANDROID_EDGE_MODE_OFF;
   ret = request_settings_->Get(ANDROID_EDGE_MODE, &entry);
@@ -849,6 +863,15 @@
     }
   }
 
+  ret = static_metadata_->Get(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &entry);
+  if ((ret == OK) && (entry.count == 1)) {
+    if (entry.data.u8[0] == ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
+      timestamp_source_ = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
+    } else if (entry.data.u8[0] != ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN) {
+      ALOGE("%s: Unsupported timestamp source", __FUNCTION__);
+    }
+  }
+
   sensor_settings->exposure_time = sensor_exposure_time_;
   sensor_settings->frame_duration = sensor_frame_duration_;
   sensor_settings->gain = sensor_sensitivity_;
@@ -864,12 +887,41 @@
   sensor_settings->edge_mode = edge_mode;
   sensor_settings->sensor_pixel_mode = sensor_pixel_mode_;
   sensor_settings->test_pattern_mode = test_pattern_mode;
+  sensor_settings->timestamp_source = timestamp_source_;
   memcpy(sensor_settings->test_pattern_data, test_pattern_data,
          sizeof(sensor_settings->test_pattern_data));
 
   return OK;
 }
 
+uint32_t EmulatedRequestState::GetPartialResultCount(bool is_partial_result) {
+  uint32_t res = 0;
+
+  if (is_partial_result) {
+    res = 1;
+  } else {
+    res = partial_result_count ? partial_result_count : 1;
+  }
+
+  return res;
+}
+
+std::unique_ptr<HwlPipelineResult> EmulatedRequestState::InitializePartialResult(
+    uint32_t pipeline_id, uint32_t frame_number) {
+  std::lock_guard<std::mutex> lock(request_state_mutex_);
+  auto result = std::make_unique<HwlPipelineResult>();
+
+  if (partial_result_count > 1) {
+    result->camera_id = camera_id_;
+    result->pipeline_id = pipeline_id;
+    result->frame_number = frame_number;
+    result->result_metadata = HalCameraMetadata::Create(0, 0);
+    result->partial_result = GetPartialResultCount(/*is partial result*/ true);
+  }
+
+  return result;
+}
+
 std::unique_ptr<HwlPipelineResult> EmulatedRequestState::InitializeResult(
     uint32_t pipeline_id, uint32_t frame_number) {
   std::lock_guard<std::mutex> lock(request_state_mutex_);
@@ -878,7 +930,7 @@
   result->pipeline_id = pipeline_id;
   result->frame_number = frame_number;
   result->result_metadata = HalCameraMetadata::Clone(request_settings_.get());
-  result->partial_result = partial_result_count_;
+  result->partial_result = GetPartialResultCount(/*is partial result*/ false);
 
   // Results supported on all emulated devices
   result->result_metadata->Set(ANDROID_REQUEST_PIPELINE_DEPTH,
@@ -957,14 +1009,20 @@
   if (report_exposure_time_) {
     result->result_metadata->Set(ANDROID_SENSOR_EXPOSURE_TIME,
                                  &sensor_exposure_time_, 1);
+  } else {
+    result->result_metadata->Erase(ANDROID_SENSOR_EXPOSURE_TIME);
   }
   if (report_frame_duration_) {
     result->result_metadata->Set(ANDROID_SENSOR_FRAME_DURATION,
                                  &sensor_frame_duration_, 1);
+  } else {
+    result->result_metadata->Erase(ANDROID_SENSOR_FRAME_DURATION);
   }
   if (report_sensitivity_) {
     result->result_metadata->Set(ANDROID_SENSOR_SENSITIVITY,
                                  &sensor_sensitivity_, 1);
+  } else {
+    result->result_metadata->Erase(ANDROID_SENSOR_SENSITIVITY);
   }
   if (report_rolling_shutter_skew_) {
     result->result_metadata->Set(
@@ -1006,6 +1064,11 @@
                                  intrinsic_calibration_,
                                  ARRAY_SIZE(intrinsic_calibration_));
   }
+  if (report_lens_intrinsics_samples_) {
+    result->result_metadata->Set(ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES,
+                                 intrinsic_calibration_,
+                                 ARRAY_SIZE(intrinsic_calibration_));
+  }
   if (report_distortion_) {
     result->result_metadata->Set(ANDROID_LENS_DISTORTION, distortion_,
                                  ARRAY_SIZE(distortion_));
@@ -1026,6 +1089,11 @@
     }
     result->result_metadata->Set(ANDROID_SCALER_CROP_REGION, chosen_crop_region,
                                  ARRAY_SIZE(scaler_crop_region_default_));
+    if (report_active_sensor_crop_) {
+      result->result_metadata->Set(
+          ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
+          chosen_crop_region, ARRAY_SIZE(scaler_crop_region_default_));
+    }
   }
   if (report_extended_scene_mode_) {
     result->result_metadata->Set(ANDROID_CONTROL_EXTENDED_SCENE_MODE,
@@ -1282,6 +1350,11 @@
     return BAD_VALUE;
   }
 
+  report_lens_intrinsics_samples_ =
+      (available_results_.find(ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES) !=
+       available_results_.end()) &&
+      (available_results_.find(ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS) !=
+       available_results_.end());
   report_scene_flicker_ =
       available_results_.find(ANDROID_STATISTICS_SCENE_FLICKER) !=
       available_results_.end();
@@ -2374,6 +2447,12 @@
             __FUNCTION__);
       return BAD_VALUE;
     }
+
+    if (available_requests_.find(
+            ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION) !=
+        available_results_.end()) {
+      report_active_sensor_crop_ = true;
+    }
     ret = static_metadata_->Get(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
                                 &entry);
     if ((ret == OK) && (entry.count > 0)) {
@@ -2849,9 +2928,11 @@
 
   ret = static_metadata_->Get(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
   if ((ret == OK) && (entry.count == 1)) {
-    if (entry.data.i32[0] != 1) {
-      ALOGW("%s: Partial results not supported!", __FUNCTION__);
+    if (entry.data.i32[0] > 2) {
+      ALOGW("%s: Partial result count greater than 2 not supported!",
+            __FUNCTION__);
     }
+    partial_result_count = entry.data.i32[0];
   }
 
   ret = static_metadata_->Get(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
diff --git a/devices/EmulatedCamera/hwl/EmulatedRequestState.h b/devices/EmulatedCamera/hwl/EmulatedRequestState.h
index 3af793e..79ad968 100644
--- a/devices/EmulatedCamera/hwl/EmulatedRequestState.h
+++ b/devices/EmulatedCamera/hwl/EmulatedRequestState.h
@@ -48,12 +48,16 @@
 
   std::unique_ptr<HwlPipelineResult> InitializeResult(uint32_t pipeline_id,
                                                       uint32_t frame_number);
+  std::unique_ptr<HwlPipelineResult> InitializePartialResult(
+      uint32_t pipeline_id, uint32_t frame_number);
 
   status_t InitializeSensorSettings(
       std::unique_ptr<HalCameraMetadata> request_settings,
       uint32_t override_frame_number,
       EmulatedSensor::SensorSettings* sensor_settings /*out*/);
 
+  uint32_t GetPartialResultCount(bool is_partial_result);
+
  private:
   bool SupportsCapability(uint8_t cap);
 
@@ -122,7 +126,6 @@
   std::set<int32_t> available_results_;
   std::set<int32_t> available_requests_;
   uint8_t max_pipeline_depth_ = 0;
-  int32_t partial_result_count_ = 1;  // TODO: add support for partial results
   bool supports_manual_sensor_ = false;
   bool supports_manual_post_processing_ = false;
   bool is_backward_compatible_ = false;
@@ -131,6 +134,7 @@
   bool supports_yuv_reprocessing_ = false;
   bool supports_remosaic_reprocessing_ = false;
   bool supports_stream_use_case_ = false;
+  uint8_t partial_result_count = 1;
 
   // android.control.*
   struct SceneOverride {
@@ -245,6 +249,7 @@
   // android.flash.*
   bool is_flash_supported_ = false;
   uint8_t flash_state_ = ANDROID_FLASH_STATE_UNAVAILABLE;
+  int32_t flash_strength_level_ = 1;
 
   // android.sensor.*
   std::pair<int32_t, int32_t> sensor_sensitivity_range_;
@@ -263,6 +268,7 @@
   bool report_green_split_ = false;
   bool report_noise_profile_ = false;
   bool report_extended_scene_mode_ = false;
+  uint32_t timestamp_source_ = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
 
   // android.scaler.*
   bool report_rotate_and_crop_ = false;
@@ -310,6 +316,8 @@
   bool report_pose_translation_ = false;
   bool report_distortion_ = false;
   bool report_intrinsic_calibration_ = false;
+  bool report_active_sensor_crop_ = false;
+  bool report_lens_intrinsics_samples_ = false;
   int32_t shading_map_size_[2] = {0};
 
   unsigned int rand_seed_ = 1;
diff --git a/devices/EmulatedCamera/hwl/EmulatedSensor.cpp b/devices/EmulatedCamera/hwl/EmulatedSensor.cpp
index 29953e6..f96a565 100644
--- a/devices/EmulatedCamera/hwl/EmulatedSensor.cpp
+++ b/devices/EmulatedCamera/hwl/EmulatedSensor.cpp
@@ -682,6 +682,7 @@
 void EmulatedSensor::SetCurrentRequest(
     std::unique_ptr<LogicalCameraSettings> logical_settings,
     std::unique_ptr<HwlPipelineResult> result,
+    std::unique_ptr<HwlPipelineResult> partial_result,
     std::unique_ptr<Buffers> input_buffers,
     std::unique_ptr<Buffers> output_buffers) {
   Mutex::Autolock lock(control_mutex_);
@@ -689,6 +690,7 @@
   current_result_ = std::move(result);
   current_input_buffers_ = std::move(input_buffers);
   current_output_buffers_ = std::move(output_buffers);
+  partial_result_ = std::move(partial_result);
 }
 
 bool EmulatedSensor::WaitForVSyncLocked(nsecs_t reltime) {
@@ -751,6 +753,13 @@
   return ret ? OK : TIMED_OUT;
 }
 
+nsecs_t EmulatedSensor::getSystemTimeWithSource(uint32_t timestamp_source) {
+  if (timestamp_source == ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
+    return systemTime(SYSTEM_TIME_BOOTTIME);
+  }
+  return systemTime(SYSTEM_TIME_MONOTONIC);
+}
+
 bool EmulatedSensor::threadLoop() {
   ATRACE_CALL();
   /**
@@ -764,14 +773,20 @@
   std::unique_ptr<Buffers> next_buffers;
   std::unique_ptr<Buffers> next_input_buffer;
   std::unique_ptr<HwlPipelineResult> next_result;
+  std::unique_ptr<HwlPipelineResult> partial_result;
   std::unique_ptr<LogicalCameraSettings> settings;
-  HwlPipelineCallback callback = {nullptr, nullptr};
+  HwlPipelineCallback callback = {
+      .process_pipeline_result = nullptr,
+      .process_pipeline_batch_result = nullptr,
+      .notify = nullptr,
+  };
   {
     Mutex::Autolock lock(control_mutex_);
     std::swap(settings, current_settings_);
     std::swap(next_buffers, current_output_buffers_);
     std::swap(next_input_buffer, current_input_buffers_);
     std::swap(next_result, current_result_);
+    std::swap(partial_result, partial_result_);
 
     // Signal VSync for start of readout
     ALOGVV("Sensor VSync");
@@ -781,13 +796,15 @@
 
   auto frame_duration = EmulatedSensor::kSupportedFrameDurationRange[0];
   auto exposure_time = EmulatedSensor::kSupportedExposureTimeRange[0];
+  uint32_t timestamp_source = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
   // Frame duration must always be the same among all physical devices
   if ((settings.get() != nullptr) && (!settings->empty())) {
     frame_duration = settings->begin()->second.frame_duration;
     exposure_time = settings->begin()->second.exposure_time;
+    timestamp_source = settings->begin()->second.timestamp_source;
   }
 
-  nsecs_t start_real_time = systemTime();
+  nsecs_t start_real_time = getSystemTimeWithSource(timestamp_source);
   // Stagefright cares about system time for timestamps, so base simulated
   // time on that.
   nsecs_t frame_end_real_time = start_real_time + frame_duration;
@@ -1175,7 +1192,7 @@
     next_input_buffer->clear();
   }
 
-  nsecs_t work_done_real_time = systemTime();
+  nsecs_t work_done_real_time = getSystemTimeWithSource(timestamp_source);
   // Returning the results at this point is not entirely correct from timing
   // perspective. Under ideal conditions where 'ReturnResults' completes
   // in less than 'time_accuracy' we need to return the results after the
@@ -1190,10 +1207,10 @@
   // noticeable effect.
   if ((work_done_real_time + kReturnResultThreshod) > frame_end_real_time) {
     ReturnResults(callback, std::move(settings), std::move(next_result),
-                  reprocess_request);
+                  reprocess_request, std::move(partial_result));
   }
 
-  work_done_real_time = systemTime();
+  work_done_real_time = getSystemTimeWithSource(timestamp_source);
   ALOGVV("Sensor vertical blanking interval");
   const nsecs_t time_accuracy = 2e6;  // 2 ms of imprecision is ok
   if (work_done_real_time < frame_end_real_time - time_accuracy) {
@@ -1208,7 +1225,7 @@
   }
 
   ReturnResults(callback, std::move(settings), std::move(next_result),
-                reprocess_request);
+                reprocess_request, std::move(partial_result));
 
   return true;
 };
@@ -1216,7 +1233,8 @@
 void EmulatedSensor::ReturnResults(
     HwlPipelineCallback callback,
     std::unique_ptr<LogicalCameraSettings> settings,
-    std::unique_ptr<HwlPipelineResult> result, bool reprocess_request) {
+    std::unique_ptr<HwlPipelineResult> result, bool reprocess_request,
+    std::unique_ptr<HwlPipelineResult> partial_result) {
   if ((callback.process_pipeline_result != nullptr) &&
       (result.get() != nullptr) && (result->result_metadata.get() != nullptr)) {
     auto logical_settings = settings->find(logical_camera_id_);
@@ -1233,6 +1251,15 @@
     }
     result->result_metadata->Set(ANDROID_SENSOR_TIMESTAMP, &next_capture_time_,
                                  1);
+
+    camera_metadata_ro_entry_t lensEntry;
+    auto lensRet = result->result_metadata->Get(
+        ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES, &lensEntry);
+    if ((lensRet == OK) && (lensEntry.count > 0)) {
+      result->result_metadata->Set(ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS,
+                                   &next_capture_time_, 1);
+    }
+
     uint8_t raw_binned_factor_used = false;
     if (sensor_binning_factor_info_.find(logical_camera_id_) !=
         sensor_binning_factor_info_.end()) {
@@ -1343,6 +1370,11 @@
       }
     }
 
+    // Partial result count for partial result is set to a value
+    // only when partial results are supported
+    if (partial_result->partial_result != 0) {
+      callback.process_pipeline_result(std::move(partial_result));
+    }
     callback.process_pipeline_result(std::move(result));
   }
 }
diff --git a/devices/EmulatedCamera/hwl/EmulatedSensor.h b/devices/EmulatedCamera/hwl/EmulatedSensor.h
index 192cadd..9e21364 100644
--- a/devices/EmulatedCamera/hwl/EmulatedSensor.h
+++ b/devices/EmulatedCamera/hwl/EmulatedSensor.h
@@ -184,6 +184,7 @@
   ColorSpaceProfileMap color_space_profiles;
   int32_t raw_crop_region_zoomed[4] = {0};
   int32_t raw_crop_region_unzoomed[4] = {0};
+  int32_t timestamp_source = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
 };
 
 // Maps logical/physical camera ids to sensor characteristics
@@ -278,6 +279,7 @@
     uint8_t test_pattern_mode = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
     uint32_t test_pattern_data[4] = {0, 0, 0, 0};
     uint32_t screen_rotation = 0;
+    uint32_t timestamp_source = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
   };
 
   // Maps physical and logical camera ids to individual device settings
@@ -285,6 +287,7 @@
 
   void SetCurrentRequest(std::unique_ptr<LogicalCameraSettings> logical_settings,
                          std::unique_ptr<HwlPipelineResult> result,
+                         std::unique_ptr<HwlPipelineResult> partial_result,
                          std::unique_ptr<Buffers> input_buffers,
                          std::unique_ptr<Buffers> output_buffers);
 
@@ -362,6 +365,7 @@
   bool got_vsync_;
   std::unique_ptr<LogicalCameraSettings> current_settings_;
   std::unique_ptr<HwlPipelineResult> current_result_;
+  std::unique_ptr<HwlPipelineResult> partial_result_;
   std::unique_ptr<Buffers> current_output_buffers_;
   std::unique_ptr<Buffers> current_input_buffers_;
   std::unique_ptr<JpegCompressor> jpeg_compressor_;
@@ -455,11 +459,14 @@
   void ReturnResults(HwlPipelineCallback callback,
                      std::unique_ptr<LogicalCameraSettings> settings,
                      std::unique_ptr<HwlPipelineResult> result,
-                     bool reprocess_request);
+                     bool reprocess_request,
+                     std::unique_ptr<HwlPipelineResult> partial_result);
 
   static float GetBaseGainFactor(float max_raw_value) {
     return max_raw_value / EmulatedSensor::kSaturationElectrons;
   }
+
+  nsecs_t getSystemTimeWithSource(uint32_t timestamp_source);
 };
 
 }  // namespace android
diff --git a/devices/EmulatedCamera/hwl/apex/Android.bp b/devices/EmulatedCamera/hwl/apex/Android.bp
index 55f492b..b864d72 100644
--- a/devices/EmulatedCamera/hwl/apex/Android.bp
+++ b/devices/EmulatedCamera/hwl/apex/Android.bp
@@ -70,6 +70,7 @@
         "emu_camera_back.json",
         "emu_camera_depth.json",
         "emu_camera_front.json",
+        "emu_camera_external.json",
     ],
 }
 
diff --git a/devices/EmulatedCamera/hwl/configs/Android.bp b/devices/EmulatedCamera/hwl/configs/Android.bp
index 1c74d1d..ca089b8 100644
--- a/devices/EmulatedCamera/hwl/configs/Android.bp
+++ b/devices/EmulatedCamera/hwl/configs/Android.bp
@@ -42,4 +42,10 @@
     name: "emu_camera_front.json",
     src: "emu_camera_front.json",
     defaults: ["emu_camera_config_defaults"],
-}
\ No newline at end of file
+}
+
+prebuilt_etc {
+    name: "emu_camera_external.json",
+    src: "emu_camera_external.json",
+    defaults: ["emu_camera_config_defaults"],
+}
diff --git a/devices/EmulatedCamera/hwl/configs/emu_camera_back.json b/devices/EmulatedCamera/hwl/configs/emu_camera_back.json
index a873bea..f9488dd 100644
--- a/devices/EmulatedCamera/hwl/configs/emu_camera_back.json
+++ b/devices/EmulatedCamera/hwl/configs/emu_camera_back.json
@@ -118,6 +118,18 @@
   "2",
   "3"
  ],
+ "android.flash.singleStrengthMaxLevel" : [
+  "10"
+ ],
+ "android.flash.singleStrengthDefaultLevel": [
+   "2"
+ ],
+ "android.flash.torchStrengthDefaultLevel": [
+   "5"
+ ],
+ "android.flash.torchStrengthMaxLevel" :[
+   "15"
+ ],
  "android.flash.info.available": [
   "TRUE"
  ],
@@ -485,6 +497,8 @@
   "917523",
   "917526",
   "851985",
+  "1114133",
+  "1114134",
   "-2080374783",
   "-2080374782"
  ],
@@ -498,7 +512,7 @@
   "1"
  ],
  "android.request.partialResultCount": [
-  "1"
+  "2"
  ],
  "android.request.pipelineMaxDepth": [
   "8"
diff --git a/devices/EmulatedCamera/hwl/configs/emu_camera_external.json b/devices/EmulatedCamera/hwl/configs/emu_camera_external.json
new file mode 100644
index 0000000..f2b4293
--- /dev/null
+++ b/devices/EmulatedCamera/hwl/configs/emu_camera_external.json
@@ -0,0 +1,498 @@
+{
+	"android.colorCorrection.availableAberrationModes": [
+		"0"
+	],
+	"android.control.aeAvailableAntibandingModes": [
+		"3"
+	],
+	"android.control.aeAvailableModes": [
+		"1"
+	],
+	"android.control.aeAvailableTargetFpsRanges": [
+		"10",
+		"20",
+		"24",
+		"24",
+		"30",
+		"30",
+		"15",
+		"30"
+	],
+	"android.control.aeCompensationRange": [
+		"0",
+		"0"
+	],
+	"android.control.aeCompensationStep": [
+		"0",
+		"1"
+	],
+	"android.control.aeLockAvailable": [
+		"FALSE"
+	],
+	"android.control.afAvailableModes": [
+		"1",
+		"0"
+	],
+	"android.control.autoframingAvailable": [
+		"FALSE"
+	],
+	"android.control.availableEffects": [
+		"0"
+	],
+	"android.control.availableModes": [
+		"0",
+		"1"
+	],
+	"android.control.availableSceneModes": [
+		"0"
+	],
+	"android.control.availableVideoStabilizationModes": [
+		"0"
+	],
+	"android.control.awbAvailableModes": [
+		"1"
+	],
+	"android.control.awbLockAvailable": [
+		"FALSE"
+	],
+	"android.control.maxRegions": [
+		"0",
+		"0",
+		"0"
+	],
+	"android.control.zoomRatioRange": [
+		"1.00000000",
+		"4.00000000"
+	],
+	"android.edge.availableEdgeModes": [
+		"0",
+		"1"
+	],
+	"android.flash.info.available": [
+		"FALSE"
+	],
+	"android.hotPixel.availableHotPixelModes": [
+		"0"
+	],
+	"android.info.supportedHardwareLevel": [
+		"EXTERNAL"
+	],
+	"android.jpeg.availableThumbnailSizes": [
+		"0",
+		"0",
+		"176",
+		"144",
+		"240",
+		"144",
+		"256",
+		"144",
+		"240",
+		"160",
+		"256",
+		"154",
+		"240",
+		"180"
+	],
+	"android.jpeg.maxSize": [
+		"3145728"
+	],
+	"android.lens.facing": [
+		"EXTERNAL"
+	],
+	"android.lens.info.availableOpticalStabilization": [
+		"0"
+	],
+	"android.lens.info.focusDistanceCalibration": [
+		"UNCALIBRATED"
+	],
+	"android.noiseReduction.availableNoiseReductionModes": [
+		"0"
+	],
+	"android.noiseReduction.mode": [
+		"OFF"
+	],
+	"android.request.availableCapabilities": [
+		"BACKWARD_COMPATIBLE"
+	],
+	"android.request.availableCharacteristicsKeys": [
+		"4",
+		"65554",
+		"65555",
+		"65556",
+		"65557",
+		"65558",
+		"65572",
+		"65559",
+		"65560",
+		"65574",
+		"65561",
+		"65562",
+		"65563",
+		"65573",
+		"65564",
+		"327680",
+		"1376256",
+		"458759",
+		"524293",
+		"589827",
+		"589831",
+		"655362",
+		"786444",
+		"786440",
+		"786438",
+		"786443",
+		"786442",
+		"851972",
+		"851978",
+		"851981",
+		"983040",
+		"983044",
+		"983046",
+		"983050",
+		"983048",
+		"917518",
+		"1048578",
+		"1179648",
+		"1179654",
+		"1179655",
+		"1179650",
+		"1507329",
+		"65582",
+		"589824",
+		"589826",
+		"589825",
+		"1245189"
+	],
+	"android.request.availableRequestKeys": [
+		"3",
+		"65536",
+		"65537",
+		"65538",
+		"65539",
+		"65542",
+		"65541",
+		"65543",
+		"65545",
+		"65546",
+		"65547",
+		"65549",
+		"65550",
+		"65551",
+		"65552",
+		"65553",
+		"262146",
+		"458755",
+		"458756",
+		"458757",
+		"458758",
+		"524292",
+		"655360",
+		"851968",
+		"917528",
+		"1114112",
+		"1114115",
+		"65583"
+	],
+	"android.request.availableResultKeys": [
+		"3",
+		"65536",
+		"65537",
+		"65538",
+		"65539",
+		"65542",
+		"65567",
+		"65541",
+		"65543",
+		"65568",
+		"65545",
+		"65546",
+		"65547",
+		"65570",
+		"65549",
+		"65550",
+		"65551",
+		"65552",
+		"65553",
+		"262146",
+		"262149",
+		"458755",
+		"458756",
+		"458757",
+		"458758",
+		"524292",
+		"655360",
+		"786441",
+		"851968",
+		"917520",
+		"1114112",
+		"1114115",
+		"1114128",
+		"1114126",
+		"65583"
+	],
+	"android.request.maxNumInputStreams": [
+		"0"
+	],
+	"android.request.maxNumOutputStreams": [
+		"0",
+		"2",
+		"1"
+	],
+	"android.request.partialResultCount": [
+		"1"
+	],
+	"android.request.pipelineMaxDepth": [
+		"4"
+	],
+	"android.scaler.availableMaxDigitalZoom": [
+		"4.00000000"
+	],
+	"android.scaler.availableMinFrameDurations": [
+		"33",
+		"320",
+		"240",
+		"33333333",
+		"35",
+		"320",
+		"240",
+		"33333333",
+		"34",
+		"320",
+		"240",
+		"33333333",
+		"33",
+		"640",
+		"480",
+		"33333333",
+		"35",
+		"640",
+		"480",
+		"33333333",
+		"34",
+		"640",
+		"480",
+		"33333333",
+		"33",
+		"1280",
+		"720",
+		"33333333",
+		"35",
+		"1280",
+		"720",
+		"33333333",
+		"34",
+		"1280",
+		"720",
+		"33333333",
+		"33",
+		"1920",
+		"1080",
+		"33333333",
+		"35",
+		"1920",
+		"1080",
+		"33333333",
+		"34",
+		"1920",
+		"1080",
+		"33333333",
+		"33",
+		"1920",
+		"1080",
+		"33333333",
+		"35",
+		"1920",
+		"1080",
+		"33333333",
+		"34",
+		"1920",
+		"1080",
+		"33333333"
+	],
+	"android.scaler.availableStallDurations": [
+		"33",
+		"320",
+		"240",
+		"1000000000",
+		"35",
+		"320",
+		"240",
+		"0",
+		"34",
+		"320",
+		"240",
+		"0",
+		"33",
+		"640",
+		"480",
+		"1000000000",
+		"35",
+		"640",
+		"480",
+		"0",
+		"34",
+		"640",
+		"480",
+		"0",
+		"33",
+		"1280",
+		"720",
+		"1000000000",
+		"35",
+		"1280",
+		"720",
+		"0",
+		"34",
+		"1280",
+		"720",
+		"0",
+		"33",
+		"1920",
+		"1080",
+		"1000000000",
+		"35",
+		"1920",
+		"1080",
+		"0",
+		"34",
+		"1920",
+		"1080",
+		"0",
+		"33",
+		"1920",
+		"1080",
+		"1000000000",
+		"35",
+		"1920",
+		"1080",
+		"0",
+		"34",
+		"1920",
+		"1080",
+		"0"
+	],
+	"android.scaler.availableStreamConfigurations": [
+		"33",
+		"320",
+		"240",
+		"OUTPUT",
+		"35",
+		"320",
+		"240",
+		"OUTPUT",
+		"34",
+		"320",
+		"240",
+		"OUTPUT",
+		"33",
+		"640",
+		"480",
+		"OUTPUT",
+		"35",
+		"640",
+		"480",
+		"OUTPUT",
+		"34",
+		"640",
+		"480",
+		"OUTPUT",
+		"33",
+		"1280",
+		"720",
+		"OUTPUT",
+		"35",
+		"1280",
+		"720",
+		"OUTPUT",
+		"34",
+		"1280",
+		"720",
+		"OUTPUT",
+		"33",
+		"1920",
+		"1080",
+		"OUTPUT",
+		"35",
+		"1920",
+		"1080",
+		"OUTPUT",
+		"34",
+		"1920",
+		"1080",
+		"OUTPUT",
+		"33",
+		"1920",
+		"1080",
+		"OUTPUT",
+		"35",
+		"1920",
+		"1080",
+		"OUTPUT",
+		"34",
+		"1920",
+		"1080",
+		"OUTPUT"
+	],
+	"android.scaler.croppingType": [
+		"CENTER_ONLY"
+	],
+	"android.sensor.availableTestPatternModes": [
+		"0",
+		"1"
+	],
+	"android.sensor.info.activeArraySize": [
+		"0",
+		"0",
+		"1920",
+		"1080"
+	],
+	"android.sensor.info.maxFrameDuration": [
+		"200000000"
+	],
+	"android.sensor.info.pixelArraySize": [
+		"1920",
+		"1080"
+	],
+	"android.sensor.info.preCorrectionActiveArraySize": [
+		"0",
+		"0",
+		"1920",
+		"1080"
+	],
+	"android.sensor.info.timestampSource": [
+		"REALTIME"
+	],
+	"android.sensor.orientation": [
+		"0"
+	],
+	"android.shading.availableModes": [
+		"0"
+	],
+	"android.statistics.info.availableFaceDetectModes": [
+		"0"
+	],
+	"android.statistics.info.availableHotPixelMapModes": [
+		"0"
+	],
+	"android.statistics.info.availableLensShadingMapModes": [
+		"0"
+	],
+	"android.statistics.info.maxFaceCount": [
+		"0"
+	],
+	"android.sync.maxLatency": [
+		"UNKNOWN"
+	],
+	"android.lens.info.availableApertures": [
+		"1.70000005"
+	],
+	"android.lens.info.availableFocalLengths": [
+		"3.25999999"
+	],
+	"android.lens.info.availableFilterDensities": [
+		"0.00000000"
+	],
+	"android.tonemap.availableToneMapModes": [
+		"1"
+	]
+}
diff --git a/devices/EmulatedCamera/hwl/configs/emu_camera_front.json b/devices/EmulatedCamera/hwl/configs/emu_camera_front.json
index 5c4b617..46d89ce 100644
--- a/devices/EmulatedCamera/hwl/configs/emu_camera_front.json
+++ b/devices/EmulatedCamera/hwl/configs/emu_camera_front.json
@@ -186,6 +186,18 @@
    "0",
    "3"
   ],
+  "android.flash.singleStrengthMaxLevel" : [
+  "10"
+ ],
+ "android.flash.singleStrengthDefaultLevel": [
+   "2"
+ ],
+ "android.flash.torchStrengthDefaultLevel": [
+   "5"
+ ],
+ "android.flash.torchStrengthMaxLevel" :[
+   "15"
+ ],
   "android.flash.info.available": [
    "TRUE"
   ],
@@ -630,7 +642,8 @@
    "1703938",
    "917530",
    "851985",
-   "917536"
+   "917536",
+   "1703939"
   ],
   "android.request.maxNumOutputStreams": [
    "1",
@@ -641,7 +654,7 @@
    "0"
   ],
   "android.request.partialResultCount": [
-   "1"
+   "2"
   ],
   "android.request.pipelineMaxDepth": [
    "8"
@@ -1490,7 +1503,7 @@
    "10"
   ],
   "android.info.supportedBufferManagementVersion" : [
-    "HIDL_DEVICE_3_5"
+    "SESSION_CONFIGURABLE"
   ],
   "android.sync.maxLatency": [
    "PER_FRAME_CONTROL"
@@ -1688,6 +1701,18 @@
    "0",
    "3"
   ],
+  "android.flash.singleStrengthMaxLevel" : [
+  "10"
+ ],
+ "android.flash.singleStrengthDefaultLevel": [
+   "2"
+ ],
+ "android.flash.torchStrengthDefaultLevel": [
+   "5"
+ ],
+ "android.flash.torchStrengthMaxLevel" :[
+   "15"
+ ],
   "android.flash.info.available": [
    "TRUE"
   ],
@@ -2089,7 +2114,7 @@
    "0"
   ],
   "android.request.partialResultCount": [
-   "1"
+   "2"
   ],
   "android.request.pipelineMaxDepth": [
    "8"
@@ -2961,7 +2986,7 @@
    "10"
   ],
   "android.info.supportedBufferManagementVersion" : [
-    "HIDL_DEVICE_3_5"
+    "SESSION_CONFIGURABLE"
   ],
   "android.sync.maxLatency": [
    "PER_FRAME_CONTROL"
@@ -3159,6 +3184,18 @@
    "0",
    "3"
   ],
+  "android.flash.singleStrengthMaxLevel" : [
+  "10"
+ ],
+ "android.flash.singleStrengthDefaultLevel": [
+   "2"
+ ],
+ "android.flash.torchStrengthDefaultLevel": [
+   "5"
+ ],
+ "android.flash.torchStrengthMaxLevel" :[
+   "15"
+ ],
   "android.flash.info.available": [
    "TRUE"
   ],
@@ -3561,7 +3598,7 @@
    "0"
   ],
   "android.request.partialResultCount": [
-   "1"
+   "2"
   ],
   "android.request.pipelineMaxDepth": [
    "8"
@@ -4477,7 +4514,7 @@
    "10"
   ],
   "android.info.supportedBufferManagementVersion" : [
-    "HIDL_DEVICE_3_5"
+    "SESSION_CONFIGURABLE"
   ],
   "android.sync.maxLatency": [
    "PER_FRAME_CONTROL"
diff --git a/devices/EmulatedCamera/hwl/utils/HWLUtils.cpp b/devices/EmulatedCamera/hwl/utils/HWLUtils.cpp
index f034a7a..2d156ab 100644
--- a/devices/EmulatedCamera/hwl/utils/HWLUtils.cpp
+++ b/devices/EmulatedCamera/hwl/utils/HWLUtils.cpp
@@ -45,6 +45,29 @@
   }
   return video_call_use_case;
 }
+status_t SupportsSessionHalBufManager(const HalCameraMetadata* metadata,
+                                      bool* result /*out*/) {
+  if ((metadata == nullptr) || (result == nullptr)) {
+    return BAD_VALUE;
+  }
+
+  status_t ret = OK;
+  camera_metadata_ro_entry_t entry;
+  *result = false;
+  ret = metadata->Get(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+  if (ret != OK) {
+    return OK;
+  }
+  if ((ret == OK) && (entry.count != 1)) {
+    ALOGE("%s: Invalid ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION!",
+          __FUNCTION__);
+    return BAD_VALUE;
+  }
+  *result =
+      (entry.data.u8[0] ==
+       ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE);
+  return OK;
+}
 
 status_t GetSensorCharacteristics(const HalCameraMetadata* metadata,
                                   SensorCharacteristics* sensor_chars /*out*/) {
diff --git a/devices/EmulatedCamera/hwl/utils/HWLUtils.h b/devices/EmulatedCamera/hwl/utils/HWLUtils.h
index 4ee0054..5c3a281 100644
--- a/devices/EmulatedCamera/hwl/utils/HWLUtils.h
+++ b/devices/EmulatedCamera/hwl/utils/HWLUtils.h
@@ -43,6 +43,9 @@
 typedef std::unique_ptr<PhysicalDeviceMap> PhysicalDeviceMapPtr;
 
 // Metadata utility functions start
+
+status_t SupportsSessionHalBufManager(const HalCameraMetadata* metadata,
+                                      bool* result /*out*/);
 status_t GetSensorCharacteristics(const HalCameraMetadata* metadata,
                                   SensorCharacteristics* sensor_chars /*out*/);
 PhysicalDeviceMapPtr ClonePhysicalDeviceMap(const PhysicalDeviceMapPtr& src);