Merge "Change total sample count type to 64 bit" into tm-dev
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index f5d0120..88783fb 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -44,4 +44,9 @@
      * {@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_270}).
      */
     int getRotateAndCropOverride(String packageName, int lensFacing, int userId);
+
+    /**
+     * Checks if the camera has been disabled via device policy.
+     */
+    boolean isCameraDisabled();
 }
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 3f7ff8b..913854c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -858,7 +858,7 @@
      * routine is enabled, overriding the application's selected
      * ACAMERA_COLOR_CORRECTION_TRANSFORM, ACAMERA_COLOR_CORRECTION_GAINS and
      * ACAMERA_COLOR_CORRECTION_MODE. Note that when ACAMERA_CONTROL_AE_MODE
-     * is OFF, the behavior of AWB is device dependent. It is recommened to
+     * is OFF, the behavior of AWB is device dependent. It is recommended to
      * also set AWB mode to OFF or lock AWB by using ACAMERA_CONTROL_AWB_LOCK before
      * setting AE mode to OFF.</p>
      * <p>When set to the OFF mode, the camera device's auto-white balance
@@ -989,13 +989,15 @@
      *
      * <p>This control (except for MANUAL) is only effective if
      * <code>ACAMERA_CONTROL_MODE != OFF</code> and any 3A routine is active.</p>
-     * <p>All intents are supported by all devices, except that:
-     *   * ZERO_SHUTTER_LAG will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
-     * PRIVATE_REPROCESSING or YUV_REPROCESSING.
-     *   * MANUAL will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
-     * MANUAL_SENSOR.
-     *   * MOTION_TRACKING will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
-     * MOTION_TRACKING.</p>
+     * <p>All intents are supported by all devices, except that:</p>
+     * <ul>
+     * <li>ZERO_SHUTTER_LAG will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
+     * PRIVATE_REPROCESSING or YUV_REPROCESSING.</li>
+     * <li>MANUAL will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
+     * MANUAL_SENSOR.</li>
+     * <li>MOTION_TRACKING will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
+     * MOTION_TRACKING.</li>
+     * </ul>
      *
      * @see ACAMERA_CONTROL_MODE
      * @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -1486,7 +1488,7 @@
      * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is START, sequence done | FLASH_REQUIRED | Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.
      * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is START, sequence done | CONVERGED      | Converged after a precapture sequence, transient states are skipped by camera device.
      * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL, converged    | FLASH_REQUIRED | Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.
-     * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL, converged    | CONVERGED      | Converged after a precapture sequenceis canceled, transient states are skipped by camera device.
+     * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL, converged    | CONVERGED      | Converged after a precapture sequences canceled, transient states are skipped by camera device.
      * CONVERGED      | Camera device finished AE scan                              | FLASH_REQUIRED | Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.
      * FLASH_REQUIRED | Camera device finished AE scan                              | CONVERGED      | Converged after a new scan, transient states are skipped by camera device.</p>
      *
@@ -1722,7 +1724,7 @@
      * </ul></p>
      *
      * <p>Devices support post RAW sensitivity boost  will advertise
-     * ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST key for controling
+     * ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST key for controlling
      * post RAW sensitivity boost.</p>
      * <p>This key will be <code>null</code> for devices that do not support any RAW format
      * outputs. For devices that do support RAW format outputs, this key will always
@@ -2193,7 +2195,7 @@
      *
      * <p>If this value is greater than 1, then the device supports controlling the
      * flashlight brightness level via
-     * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#turnOnTorchWithStrengthLevel">CameraManager#turnOnTorchWithStrengthLevel</a>.
      * If this value is equal to 1, flashlight brightness control is not supported.
      * The value for this key will be null for devices with no flash unit.</p>
      */
@@ -2201,7 +2203,7 @@
             ACAMERA_FLASH_INFO_START + 2,
     /**
      * <p>Default flashlight brightness level to be set via
-     * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.</p>
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#turnOnTorchWithStrengthLevel">CameraManager#turnOnTorchWithStrengthLevel</a>.</p>
      *
      * <p>Type: int32</p>
      *
@@ -2423,7 +2425,7 @@
      *   and keep jpeg and thumbnail image data unrotated.</li>
      * <li>Rotate the jpeg and thumbnail image data and not set
      *   <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>. In this
-     *   case, LIMITED or FULL hardware level devices will report rotated thumnail size in
+     *   case, LIMITED or FULL hardware level devices will report rotated thumbnail size in
      *   capture result, so the width and height will be interchanged if 90 or 270 degree
      *   orientation is requested. LEGACY device will always report unrotated thumbnail
      *   size.</li>
@@ -2452,7 +2454,7 @@
      *
      * <p>This list will include at least one non-zero resolution, plus <code>(0,0)</code> for indicating no
      * thumbnail should be generated.</p>
-     * <p>Below condiditions will be satisfied for this size list:</p>
+     * <p>Below conditions will be satisfied for this size list:</p>
      * <ul>
      * <li>The sizes will be sorted by increasing pixel area (width x height).
      * If several resolutions have the same area, they will be sorted by increasing width.</li>
@@ -2766,7 +2768,7 @@
      * <p>When the state is STATIONARY, the lens parameters are not changing. This could be
      * either because the parameters are all fixed, or because the lens has had enough
      * time to reach the most recently-requested values.
-     * If all these lens parameters are not changable for a camera device, as listed below:</p>
+     * If all these lens parameters are not changeable for a camera device, as listed below:</p>
      * <ul>
      * <li>Fixed focus (<code>ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE == 0</code>), which means
      * ACAMERA_LENS_FOCUS_DISTANCE parameter will always be 0.</li>
@@ -3218,7 +3220,7 @@
      * the camera device. Using more streams simultaneously may require more hardware and
      * CPU resources that will consume more power. The image format for an output stream can
      * be any supported format provided by ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS.
-     * The formats defined in ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS can be catergorized
+     * The formats defined in ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS can be categorized
      * into the 3 stream types as below:</p>
      * <ul>
      * <li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.
@@ -3445,7 +3447,7 @@
      * but clients should be aware and expect delays during their application.
      * An example usage scenario could look like this:</p>
      * <ul>
-     * <li>The camera client starts by quering the session parameter key list via
+     * <li>The camera client starts by querying the session parameter key list via
      *   {@link ACameraManager_getCameraCharacteristics }.</li>
      * <li>Before triggering the capture session create sequence, a capture request
      *   must be built via
@@ -3711,7 +3713,7 @@
      * IMPLEMENTATION_DEFINED | same as YUV_420_888                  | Any            |</p>
      * <p>For applications targeting SDK version 31 or newer, if the mobile device declares to be
      * media performance class 12 or higher by setting
-     * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CDOES/MEDIA_PERFORMANCE_CLASS.html">MEDIA_PERFORMANCE_CLASS</a> to be 31 or larger,
+     * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES/MEDIA_PERFORMANCE_CLASS.html">MEDIA_PERFORMANCE_CLASS</a> to be 31 or larger,
      * the primary camera devices (first rear/front camera in the camera ID list) will not
      * support JPEG sizes smaller than 1080p. If the application configures a JPEG stream
      * smaller than 1080p, the camera device will round up the JPEG image size to at least
@@ -3730,7 +3732,7 @@
      * IMPLEMENTATION_DEFINED | same as YUV_420_888                  | Any            |</p>
      * <p>For applications targeting SDK version 31 or newer, if the mobile device doesn't declare
      * to be media performance class 12 or better by setting
-     * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CDOES/MEDIA_PERFORMANCE_CLASS.html">MEDIA_PERFORMANCE_CLASS</a> to be 31 or larger,
+     * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES/MEDIA_PERFORMANCE_CLASS.html">MEDIA_PERFORMANCE_CLASS</a> to be 31 or larger,
      * or if the camera device isn't a primary rear/front camera, the minimum required output
      * stream configurations are the same as for applications targeting SDK version older than
      * 31.</p>
@@ -4224,14 +4226,16 @@
      * to output different resolution images depending on the current active physical camera or
      * pixel mode. With multi-resolution input streams, the camera device can reprocess images
      * of different resolutions from different physical cameras or sensor pixel modes.</p>
-     * <p>When set to TRUE:
-     * * For a logical multi-camera, the camera framework derives
+     * <p>When set to TRUE:</p>
+     * <ul>
+     * <li>For a logical multi-camera, the camera framework derives
      * android.scaler.multiResolutionStreamConfigurationMap by combining the
      * ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS from its physical
-     * cameras.
-     * * For an ultra-high resolution sensor camera, the camera framework directly copies
+     * cameras.</li>
+     * <li>For an ultra-high resolution sensor camera, the camera framework directly copies
      * the value of ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS to
-     * android.scaler.multiResolutionStreamConfigurationMap.</p>
+     * android.scaler.multiResolutionStreamConfigurationMap.</li>
+     * </ul>
      *
      * @see ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS
      */
@@ -4253,7 +4257,7 @@
      * capture, video record for encoding the camera output for the purpose of future playback,
      * and video call for live realtime video conferencing.</p>
      * <p>With this flag, the camera device can optimize the image processing pipeline
-     * parameters, such as tuning, sensor mode, and ISP settings, indepedent of
+     * parameters, such as tuning, sensor mode, and ISP settings, independent of
      * the properties of the immediate camera output surface. For example, if the output
      * surface is a SurfaceTexture, the stream use case flag can be used to indicate whether
      * the camera frames eventually go to display, video encoder,
@@ -4275,7 +4279,7 @@
      * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE</a>
      * capability is documented in the camera device
      * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">guideline</a>. The
-     * application is strongly recommended to use one of the guaranteed stream combintations.
+     * application is strongly recommended to use one of the guaranteed stream combinations.
      * If the application creates a session with a stream combination not in the guaranteed
      * list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
      * the camera device may ignore some stream use cases due to hardware constraints
@@ -4839,7 +4843,7 @@
      * noise model used here is:</p>
      * <p>N(x) = sqrt(Sx + O)</p>
      * <p>Where x represents the recorded signal of a CFA channel normalized to
-     * the range [0, 1], and S and O are the noise model coeffiecients for
+     * the range [0, 1], and S and O are the noise model coefficients for
      * that channel.</p>
      * <p>A more detailed description of the noise model can be found in the
      * Adobe DNG specification for the NoiseProfile tag.</p>
@@ -4888,7 +4892,7 @@
      * <li>1.20 &lt;= R &gt;= 1.03 will require some software
      * correction to avoid demosaic errors (3-20% divergence).</li>
      * <li>R &gt; 1.20 will require strong software correction to produce
-     * a usuable image (&gt;20% divergence).</li>
+     * a usable image (&gt;20% divergence).</li>
      * </ul>
      * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
      * the camera device has RAW capability.</p>
@@ -5145,7 +5149,7 @@
      *   <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
      * </ul></p>
      *
-     * <p>This key will only be present in devices advertisting the
+     * <p>This key will only be present in devices advertising the
      * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
      * capability which also advertise <code>REMOSAIC_REPROCESSING</code> capability. On all other devices
      * RAW targets will have a regular bayer pattern.</p>
@@ -6330,9 +6334,11 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
-     * <p>The tonemap curve will be defined the following formula:
-     * * OUT = pow(IN, 1.0 / gamma)
-     * where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
+     * <p>The tonemap curve will be defined the following formula:</p>
+     * <ul>
+     * <li>OUT = pow(IN, 1.0 / gamma)</li>
+     * </ul>
+     * <p>where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
      * pow is the power function and gamma is the gamma value specified by this
      * key.</p>
      * <p>The same curve will be applied to all color channels. The camera device
@@ -7294,7 +7300,7 @@
      * EXTERIOR_* value.</p>
      * <p>If a camera has INTERIOR_OTHER or EXTERIOR_OTHER, or more than one camera is at the
      * same location and facing the same direction, their static metadata will list the
-     * following entries, so that applications can determain their lenses' exact facing
+     * following entries, so that applications can determine their lenses' exact facing
      * directions:</p>
      * <ul>
      * <li>ACAMERA_LENS_POSE_REFERENCE</li>
@@ -8705,7 +8711,7 @@
 
     /**
      * <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the origin of the
-     * automotive sensor coodinate system, which is at the center of the rear axle.</p>
+     * automotive sensor coordinate system, which is at the center of the rear axle.</p>
      *
      * @see ACAMERA_LENS_POSE_TRANSLATION
      */
@@ -9024,7 +9030,7 @@
      * for the largest YUV_420_888 size.</p>
      * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, {@link AIMAGE_FORMAT_Y8 }, then those can also be
      * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
-     * <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranted to have a value between 0
+     * <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranteed to have a value between 0
      * and 4, inclusive. ACAMERA_CONTROL_AE_LOCK_AVAILABLE and ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
      * are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields
      * consistent image output.</p>
@@ -9190,7 +9196,7 @@
      * non-active physical cameras. For example, if the logical camera has a wide-ultrawide
      * configuration where the wide lens is the default, when the crop region is set to the
      * logical camera's active array size, (and the zoom ratio set to 1.0 starting from
-     * Android 11), a physical stream for the ultrawide camera may prefer outputing images
+     * Android 11), a physical stream for the ultrawide camera may prefer outputting images
      * with larger field-of-view than that of the wide camera for better stereo matching
      * margin or more robust motion tracking. At the same time, the physical non-RAW streams'
      * field of view must not be smaller than the requested crop region and zoom ratio, as
@@ -9316,22 +9322,26 @@
      * <a href="https://developer.android.com/reference/android/hardware/camera2/params/OutputConfiguration.html#setStreamUseCase">OutputConfiguration#setStreamUseCase</a>
      * so that the device can optimize camera pipeline parameters such as tuning, sensor
      * mode, or ISP settings for a specific user scenario.
-     * Some sample usages of this capability are:
-     * * Distinguish high quality YUV captures from a regular YUV stream where
-     *   the image quality may not be as good as the JPEG stream, or
-     * * Use one stream to serve multiple purposes: viewfinder, video recording and
+     * Some sample usages of this capability are:</p>
+     * <ul>
+     * <li>Distinguish high quality YUV captures from a regular YUV stream where
+     *   the image quality may not be as good as the JPEG stream, or</li>
+     * <li>Use one stream to serve multiple purposes: viewfinder, video recording and
      *   still capture. This is common with applications that wish to apply edits equally
-     *   to preview, saved images, and saved videos.</p>
+     *   to preview, saved images, and saved videos.</li>
+     * </ul>
      * <p>This capability requires the camera device to support the following
-     * stream use cases:
-     * * DEFAULT for backward compatibility where the application doesn't set
-     *   a stream use case
-     * * PREVIEW for live viewfinder and in-app image analysis
-     * * STILL_CAPTURE for still photo capture
-     * * VIDEO_RECORD for recording video clips
-     * * PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
-     *   recording, and still capture.
-     * * VIDEO_CALL for long running video calls</p>
+     * stream use cases:</p>
+     * <ul>
+     * <li>DEFAULT for backward compatibility where the application doesn't set
+     *   a stream use case</li>
+     * <li>PREVIEW for live viewfinder and in-app image analysis</li>
+     * <li>STILL_CAPTURE for still photo capture</li>
+     * <li>VIDEO_RECORD for recording video clips</li>
+     * <li>PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
+     *   recording, and still capture.</li>
+     * <li>VIDEO_CALL for long running video calls</li>
+     * </ul>
      * <p><a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_STREAM_USE_CASES">CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES</a>
      * lists all of the supported stream use cases.</p>
      * <p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for the
@@ -9632,10 +9642,10 @@
      * <p>Live stream shown to the user.</p>
      * <p>Optimized for performance and usability as a viewfinder, but not necessarily for
      * image quality. The output is not meant to be persisted as saved images or video.</p>
-     * <p>No stall if android.control.<em> are set to FAST; may have stall if android.control.</em>
-     * are set to HIGH_QUALITY. This use case has the same behavior as the default
-     * SurfaceView and SurfaceTexture targets. Additionally, this use case can be used for
-     * in-app image analysis.</p>
+     * <p>No stall if ACAMERA_CONTROL_* are set to FAST. There may be stall if
+     * they are set to HIGH_QUALITY. This use case has the same behavior as the
+     * default SurfaceView and SurfaceTexture targets. Additionally, this use case can be
+     * used for in-app image analysis.</p>
      */
     ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW                = 0x1,
 
@@ -9678,7 +9688,7 @@
     ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL    = 0x4,
 
     /**
-     * <p>Long-running video call optimized for both power efficienty and video quality.</p>
+     * <p>Long-running video call optimized for both power efficiency and video quality.</p>
      * <p>The camera sensor may run in a lower-resolution mode to reduce power consumption
      * at the cost of some image and digital zoom quality. Unlike VIDEO_RECORD, VIDEO_CALL
      * outputs are expected to work in dark conditions, so are usually accompanied with
@@ -10105,7 +10115,7 @@
     ACAMERA_TONEMAP_MODE_HIGH_QUALITY                                = 2,
 
     /**
-     * <p>Use the gamma value specified in ACAMERA_TONEMAP_GAMMA to peform
+     * <p>Use the gamma value specified in ACAMERA_TONEMAP_GAMMA to perform
      * tonemapping.</p>
      * <p>All color enhancement and tonemapping must be disabled, except
      * for applying the tonemapping curve specified by ACAMERA_TONEMAP_GAMMA.</p>
@@ -10117,7 +10127,7 @@
 
     /**
      * <p>Use the preset tonemapping curve specified in
-     * ACAMERA_TONEMAP_PRESET_CURVE to peform tonemapping.</p>
+     * ACAMERA_TONEMAP_PRESET_CURVE to perform tonemapping.</p>
      * <p>All color enhancement and tonemapping must be disabled, except
      * for applying the tonemapping curve specified by
      * ACAMERA_TONEMAP_PRESET_CURVE.</p>
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 85ab0c2..0a57590 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -491,6 +491,7 @@
     }
 
     if (mRemote != nullptr) {
+        ALOGD("%s: binder disconnect reached", __FUNCTION__);
         auto ret = mRemote->disconnect();
         if (!ret.isOk()) {
             ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
diff --git a/drm/mediadrm/plugins/clearkey/service-lazy.mk b/drm/mediadrm/plugins/clearkey/service-lazy.mk
new file mode 100644
index 0000000..0d16f4c
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/service-lazy.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+PRODUCT_PACKAGES += android.hardware.drm-service-lazy.clearkey
diff --git a/drm/mediadrm/plugins/clearkey/service.mk b/drm/mediadrm/plugins/clearkey/service.mk
new file mode 100644
index 0000000..15988fb
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/service.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+PRODUCT_PACKAGES += android.hardware.drm-service.clearkey
diff --git a/media/codec2/components/base/SimpleC2Interface.cpp b/media/codec2/components/base/SimpleC2Interface.cpp
index 29740d1..993e602 100644
--- a/media/codec2/components/base/SimpleC2Interface.cpp
+++ b/media/codec2/components/base/SimpleC2Interface.cpp
@@ -28,6 +28,14 @@
 
 /* SimpleInterface */
 
+static C2R SubscribedParamIndicesSetter(
+        bool mayBlock, C2InterfaceHelper::C2P<C2SubscribedParamIndicesTuning> &me) {
+    (void)mayBlock;
+    (void)me;
+
+    return C2R::Ok();
+}
+
 SimpleInterface<void>::BaseParams::BaseParams(
         const std::shared_ptr<C2ReflectorHelper> &reflector,
         C2String name,
@@ -186,7 +194,7 @@
             .withDefault(C2SubscribedParamIndicesTuning::AllocShared(0u))
             .withFields({ C2F(mSubscribedParamIndices, m.values[0]).any(),
                           C2F(mSubscribedParamIndices, m.values).any() })
-            .withSetter(Setter<C2SubscribedParamIndicesTuning>::NonStrictValuesWithNoDeps)
+            .withSetter(SubscribedParamIndicesSetter)
             .build());
 
     /* TODO
diff --git a/media/codec2/components/base/include/SimpleC2Interface.h b/media/codec2/components/base/include/SimpleC2Interface.h
index 2051d3d..916f392 100644
--- a/media/codec2/components/base/include/SimpleC2Interface.h
+++ b/media/codec2/components/base/include/SimpleC2Interface.h
@@ -209,6 +209,7 @@
         return me.F(me.v.value).validatePossible(me.v.value);
     }
 
+    // TODO(b/230146771): fix crash
     static C2R NonStrictValuesWithNoDeps(
             bool mayBlock, C2InterfaceHelper::C2P<type> &me) {
         (void)mayBlock;
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
index f370f5e..3965bcc 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
@@ -49,7 +49,7 @@
     #define INPUT_DUMP_EXT      "m2v"
     #define GENERATE_FILE_NAMES() {                         \
         nsecs_t now = systemTime();                         \
-        sprintf(mInFile, "%s_%" PRId64 ".%s",
+        sprintf(mInFile, "%s_%" PRId64 ".%s",               \
                 INPUT_DUMP_PATH, now,                       \
                 INPUT_DUMP_EXT);                            \
     }
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 88fe1f3..8783c2c 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -30,6 +30,7 @@
 #include <android/hardware/media/c2/1.0/IInputSurface.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gui/IGraphicBufferProducer.h>
@@ -1011,7 +1012,9 @@
             // Query vendor format for Flexible YUV
             std::vector<std::unique_ptr<C2Param>> heapParams;
             C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr;
-            if (mClient->query(
+            int vendorSdkVersion = base::GetIntProperty(
+                    "ro.vendor.build.version.sdk", android_get_device_api_level());
+            if (vendorSdkVersion >= __ANDROID_API_S__ && mClient->query(
                         {},
                         {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
                         C2_MAY_BLOCK,
@@ -1071,6 +1074,17 @@
                 }
             } else {
                 if ((config->mDomain & Config::IS_ENCODER) || !surface) {
+                    if (vendorSdkVersion < __ANDROID_API_S__ &&
+                            (format == COLOR_FormatYUV420Flexible ||
+                             format == COLOR_FormatYUV420Planar ||
+                             format == COLOR_FormatYUV420PackedPlanar ||
+                             format == COLOR_FormatYUV420SemiPlanar ||
+                             format == COLOR_FormatYUV420PackedSemiPlanar)) {
+                        // pre-S framework used to map these color formats into YV12.
+                        // Codecs from older vendor partition may be relying on
+                        // this assumption.
+                        format = HAL_PIXEL_FORMAT_YV12;
+                    }
                     switch (format) {
                         case COLOR_FormatYUV420Flexible:
                             format = COLOR_FormatYUV420Planar;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index a086128..62a1d02 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -2098,12 +2098,13 @@
 }
 
 PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
-    // When client pushed EOS, we want all the work to be done quickly.
     // Otherwise, component may have stalled work due to input starvation up to
     // the sum of the delay in the pipeline.
+    // TODO(b/231253301): When client pushed EOS, the pipeline could have less
+    //                    number of frames.
     size_t n = 0;
-    if (!mInputMetEos) {
-        size_t outputDelay = mOutput.lock()->outputDelay;
+    size_t outputDelay = mOutput.lock()->outputDelay;
+    {
         Mutexed<Input>::Locked input(mInput);
         n = input->inputDelay + input->pipelineDelay + outputDelay;
     }
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 132902b..f3fb5ff 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -20,6 +20,8 @@
 #include <log/log.h>
 #include <utils/NativeHandle.h>
 
+#include <android-base/properties.h>
+
 #include <C2Component.h>
 #include <C2Param.h>
 #include <util/C2InterfaceHelper.h>
@@ -1070,6 +1072,13 @@
                     C2_PARAMKEY_SURFACE_SCALING_MODE);
         } else {
             addLocalParam(new C2StreamColorAspectsInfo::input(0u), C2_PARAMKEY_COLOR_ASPECTS);
+
+            if (domain.value == C2Component::DOMAIN_VIDEO) {
+                addLocalParam(new C2AndroidStreamAverageBlockQuantizationInfo::output(0u, 0),
+                              C2_PARAMKEY_AVERAGE_QP);
+                addLocalParam(new C2StreamPictureTypeMaskInfo::output(0u, 0),
+                              C2_PARAMKEY_PICTURE_TYPE);
+            }
         }
     }
 
@@ -1111,15 +1120,21 @@
         const std::shared_ptr<Codec2Client::Configurable> &configurable,
         const std::vector<C2Param::Index> &indices,
         c2_blocking_t blocking) {
+    static const int32_t kProductFirstApiLevel =
+        base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
+    static const int32_t kBoardApiLevel =
+        base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
+    static const int32_t kFirstApiLevel =
+        (kBoardApiLevel != 0) ? kBoardApiLevel : kProductFirstApiLevel;
     mSubscribedIndices.insert(indices.begin(), indices.end());
-    // TODO: enable this when components no longer crash on this config
-    if (mSubscribedIndices.size() != mSubscribedIndicesSize && false) {
-        std::vector<uint32_t> indices;
+    if (mSubscribedIndices.size() != mSubscribedIndicesSize
+            && kFirstApiLevel >= __ANDROID_API_T__) {
+        std::vector<uint32_t> indicesVector;
         for (C2Param::Index ix : mSubscribedIndices) {
-            indices.push_back(ix);
+            indicesVector.push_back(ix);
         }
         std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
-            C2SubscribedParamIndicesTuning::AllocUnique(indices);
+            C2SubscribedParamIndicesTuning::AllocUnique(indicesVector);
         std::vector<std::unique_ptr<C2SettingResult>> results;
         c2_status_t c2Err = configurable->config({ subscribeTuning.get() }, blocking, &results);
         if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 2cca3c8..63b0f39 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -576,14 +576,7 @@
     }
 
     ~Impl() {
-        bool noInit = false;
         for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
-            if (!noInit && mProducer) {
-                Return<HStatus> transResult =
-                        mProducer->detachBuffer(static_cast<int32_t>(i));
-                noInit = !transResult.isOk() ||
-                         static_cast<HStatus>(transResult) == HStatus::NO_INIT;
-            }
             mBuffers[i].clear();
         }
     }
@@ -692,15 +685,6 @@
         {
             sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
             std::scoped_lock<std::mutex> lock(mMutex);
-            bool noInit = false;
-            for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
-                if (!noInit && mProducer) {
-                    Return<HStatus> transResult =
-                            mProducer->detachBuffer(static_cast<int32_t>(i));
-                    noInit = !transResult.isOk() ||
-                             static_cast<HStatus>(transResult) == HStatus::NO_INIT;
-                }
-            }
             int32_t oldGeneration = mGeneration;
             if (producer) {
                 mProducer = producer;
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0871365..15203d6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1331,6 +1331,7 @@
     const sp<IAudioRecordCallback> callback = mCallback.promote();
     if (!callback) {
         mCallback = nullptr;
+        mLock.unlock();
         return NS_NEVER;
     }
     if (mAwaitBoost) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 9a7b9c1..de8c298 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -70,6 +70,7 @@
 dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
 record_config_callback AudioSystem::gRecordConfigCallback = NULL;
 routing_callback AudioSystem::gRoutingCallback = NULL;
+vol_range_init_req_callback AudioSystem::gVolRangeInitReqCallback = NULL;
 
 // Required to be held while calling into gSoundTriggerCaptureStateListener.
 class CaptureStateListenerImpl;
@@ -781,6 +782,11 @@
     gRoutingCallback = cb;
 }
 
+/*static*/ void AudioSystem::setVolInitReqCallback(vol_range_init_req_callback cb) {
+    Mutex::Autolock _l(gLock);
+    gVolRangeInitReqCallback = cb;
+}
+
 // client singleton for AudioPolicyService binder interface
 // protected by gLockAPS
 sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -826,6 +832,11 @@
     return ap;
 }
 
+void AudioSystem::clearAudioPolicyService() {
+    Mutex::Autolock _l(gLockAPS);
+    gAudioPolicyService.clear();
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::onNewAudioModulesAvailable() {
@@ -1144,8 +1155,15 @@
             legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
     int32_t indexMinAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMin));
     int32_t indexMaxAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMax));
-    return statusTFromBinderStatus(
+    status_t status = statusTFromBinderStatus(
             aps->initStreamVolume(streamAidl, indexMinAidl, indexMaxAidl));
+    if (status == DEAD_OBJECT) {
+        // This is a critical operation since w/o proper stream volumes no audio
+        // will be heard. Make sure we recover from a failure in any case.
+        ALOGE("Received DEAD_OBJECT from APS, clearing the client");
+        clearAudioPolicyService();
+    }
+    return status;
 }
 
 status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
@@ -1406,10 +1424,7 @@
         }
         gAudioFlinger.clear();
     }
-    {
-        Mutex::Autolock _l(gLockAPS);
-        gAudioPolicyService.clear();
-    }
+    clearAudioPolicyService();
 }
 
 status_t AudioSystem::setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
@@ -2574,6 +2589,19 @@
     return Status::ok();
 }
 
+Status AudioSystem::AudioPolicyServiceClient::onVolumeRangeInitRequest() {
+    vol_range_init_req_callback cb = NULL;
+    {
+        Mutex::Autolock _l(AudioSystem::gLock);
+        cb = gVolRangeInitReqCallback;
+    }
+
+    if (cb != NULL) {
+        cb();
+    }
+    return Status::ok();
+}
+
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused) {
     {
         Mutex::Autolock _l(mLock);
@@ -2584,10 +2612,7 @@
             mAudioVolumeGroupCallback[i]->onServiceDied();
         }
     }
-    {
-        Mutex::Autolock _l(gLockAPS);
-        AudioSystem::gAudioPolicyService.clear();
-    }
+    AudioSystem::clearAudioPolicyService();
 
     ALOGW("AudioPolicyService server died!");
 }
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index bec6b10..36f8e10 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2448,6 +2448,7 @@
     sp<IAudioTrackCallback> callback = mCallback.promote();
     if (!callback) {
         mCallback = nullptr;
+        mLock.unlock();
         return NS_NEVER;
     }
     if (mAwaitBoost) {
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
index d93a59d..c0cdd96 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
@@ -46,4 +46,7 @@
                                         AudioSource source);
      /** Notifies a change of audio routing */
      void onRoutingUpdated();
+     /** Notifies a request for volume index ranges to be reset after they were observed as invalid
+      */
+     void onVolumeRangeInitRequest();
 }
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index b871238..a61ad58 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -57,8 +57,10 @@
     boolean isHeadTrackingSupported();
 
     /** Reports the list of supported head tracking modes (see SpatializerHeadTrackingMode.aidl).
-     * The list can be empty if the spatializer implementation does not support head tracking or if
-     * no head tracking sensor is registered (see setHeadSensor() and setScreenSensor()).
+     * The list always contains SpatializerHeadTrackingMode.DISABLED and can include other modes
+     * if the spatializer effect implementation supports head tracking.
+     * The result does not depend on currently connected sensors but reflects the capabilities
+     * when sensors are available.
      */
     SpatializerHeadTrackingMode[] getSupportedHeadTrackingModes();
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 1cc22a0..360b83d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -77,6 +77,7 @@
                                        audio_patch_handle_t patchHandle,
                                        audio_source_t source);
 typedef void (*routing_callback)();
+typedef void (*vol_range_init_req_callback)();
 
 class IAudioFlinger;
 class String8;
@@ -154,6 +155,7 @@
     static void setDynPolicyCallback(dynamic_policy_callback cb);
     static void setRecordConfigCallback(record_config_callback);
     static void setRoutingCallback(routing_callback cb);
+    static void setVolInitReqCallback(vol_range_init_req_callback cb);
 
     // Sets the binder to use for accessing the AudioFlinger service. This enables the system server
     // to grant specific isolated processes access to the audio system. Currently used only for the
@@ -348,6 +350,7 @@
     static void clearAudioConfigCache();
 
     static const sp<media::IAudioPolicyService> get_audio_policy_service();
+    static void clearAudioPolicyService();
 
     // helpers for android.media.AudioManager.getProperty(), see description there for meaning
     static uint32_t getPrimaryOutputSamplingRate();
@@ -736,6 +739,7 @@
                 int32_t patchHandle,
                 media::audio::common::AudioSource source) override;
         binder::Status onRoutingUpdated();
+        binder::Status onVolumeRangeInitRequest();
 
     private:
         Mutex                               mLock;
@@ -763,6 +767,7 @@
     static dynamic_policy_callback gDynPolicyCallback;
     static record_config_callback gRecordConfigCallback;
     static routing_callback gRoutingCallback;
+    static vol_range_init_req_callback gVolRangeInitReqCallback;
 
     static size_t gInBuffSize;
     // previous parameters for recording buffer size queries
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
index 553a319..0a8188f 100644
--- a/media/libaudiofoundation/AudioContainers.cpp
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -70,6 +70,13 @@
     return audioDeviceOutAllBleSet;
 }
 
+const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet() {
+    static const DeviceTypeSet audioDeviceOutLeAudioUnicastSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY));
+    return audioDeviceOutLeAudioUnicastSet;
+}
+
 std::string deviceTypesToString(const DeviceTypeSet &deviceTypes) {
     if (deviceTypes.empty()) {
         return "Empty device types";
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index a9c7824..b6e6c84 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -41,6 +41,7 @@
 const DeviceTypeSet& getAudioDeviceInAllSet();
 const DeviceTypeSet& getAudioDeviceInAllUsbSet();
 const DeviceTypeSet& getAudioDeviceOutAllBleSet();
+const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet();
 
 template<typename T>
 static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
diff --git a/media/libheadtracking/SensorPoseProvider.cpp b/media/libheadtracking/SensorPoseProvider.cpp
index f3f9b77..4884ae4 100644
--- a/media/libheadtracking/SensorPoseProvider.cpp
+++ b/media/libheadtracking/SensorPoseProvider.cpp
@@ -158,7 +158,6 @@
     enum DataFormat {
         kUnknown,
         kQuaternion,
-        kRotationVectorsAndFlags,
         kRotationVectorsAndDiscontinuityCount,
     };
 
@@ -283,10 +282,6 @@
             return DataFormat::kRotationVectorsAndDiscontinuityCount;
         }
 
-        if (sensor->getStringType() == "com.google.hardware.sensor.hid_dynamic.headtracker") {
-            return DataFormat::kRotationVectorsAndFlags;
-        }
-
         return DataFormat::kUnknown;
     }
 
@@ -332,21 +327,6 @@
                 return PoseEvent{Pose3f(quat), std::optional<Twist3f>(), false};
             }
 
-            case DataFormat::kRotationVectorsAndFlags: {
-                // Custom sensor, assumed to contain:
-                // 3 floats representing orientation as a rotation vector (in rad).
-                // 3 floats representing angular velocity as a rotation vector (in rad/s).
-                // 1 uint32_t of flags, where:
-                // - LSb is '1' iff the given sample is the first one in a new frame of reference.
-                // - The rest of the bits are reserved for future use.
-                Eigen::Vector3f rotation = {event.data[0], event.data[1], event.data[2]};
-                Eigen::Vector3f twist = {event.data[3], event.data[4], event.data[5]};
-                Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
-                uint32_t flags = *reinterpret_cast<const uint32_t*>(&event.data[6]);
-                return PoseEvent{Pose3f(quat), Twist3f(Eigen::Vector3f::Zero(), twist),
-                                 (flags & (1 << 0)) != 0};
-            }
-
             case DataFormat::kRotationVectorsAndDiscontinuityCount: {
                 Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
                                             event.head_tracker.rz};
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 95afa62..9607425 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -564,9 +564,11 @@
     // Set the preview display. Skip this if mSurface is null because
     // applications may already set a surface to the camera.
     if (mSurface != NULL) {
-        // This CHECK is good, since we just passed the lock/unlock
-        // check earlier by calling mCamera->setParameters().
-        CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface));
+        // Surface may be set incorrectly or could already be used even if we just
+        // passed the lock/unlock check earlier by calling mCamera->setParameters().
+        if ((err = mCamera->setPreviewTarget(mSurface)) != OK) {
+            return err;
+        }
     }
 
     // Use buffer queue to receive video buffers from camera
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 2a75342..5a27362 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -186,9 +186,12 @@
 // XXX suppress until we get our representation right
 static bool kEmitHistogram = false;
 
+static int64_t getId(IResourceManagerClient const * client) {
+    return (int64_t) client;
+}
 
 static int64_t getId(const std::shared_ptr<IResourceManagerClient> &client) {
-    return (int64_t) client.get();
+    return getId(client.get());
 }
 
 static bool isResourceError(status_t err) {
@@ -205,12 +208,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 struct ResourceManagerClient : public BnResourceManagerClient {
-    explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
+    explicit ResourceManagerClient(MediaCodec* codec, int32_t pid) :
+            mMediaCodec(codec), mPid(pid) {}
 
     Status reclaimResource(bool* _aidl_return) override {
         sp<MediaCodec> codec = mMediaCodec.promote();
         if (codec == NULL) {
-            // codec is already gone.
+            // Codec is already gone, so remove the resources as well
+            ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+            std::shared_ptr<IResourceManagerService> service =
+                    IResourceManagerService::fromBinder(binder);
+            if (service == nullptr) {
+                ALOGW("MediaCodec::ResourceManagerClient unable to find ResourceManagerService");
+            }
+            service->removeClient(mPid, getId(this));
             *_aidl_return = true;
             return Status::ok();
         }
@@ -247,6 +258,7 @@
 
 private:
     wp<MediaCodec> mMediaCodec;
+    int32_t mPid;
 
     DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
 };
@@ -820,7 +832,7 @@
       mGetCodecBase(getCodecBase),
       mGetCodecInfo(getCodecInfo) {
     mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
-            ::ndk::SharedRefBase::make<ResourceManagerClient>(this));
+            ::ndk::SharedRefBase::make<ResourceManagerClient>(this, pid));
     if (!mGetCodecBase) {
         mGetCodecBase = [](const AString &name, const char *owner) {
             return GetCodecBase(name, owner);
diff --git a/media/libstagefright/foundation/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
index 980eb22..3370748 100644
--- a/media/libstagefright/foundation/MetaDataBase.cpp
+++ b/media/libstagefright/foundation/MetaDataBase.cpp
@@ -521,9 +521,64 @@
                 }
                 setData(key, type, blob.data(), size);
                 blob.release();
+            } else if (type == TYPE_C_STRING) {
+                // copy data directly from Parcel storage, then advance position
+                // NB: readInplace() bumps position, it is NOT idempotent.
+                const void *src = parcel.readInplace(size);
+                char *str = (char *) src;
+                if (src == nullptr || size == 0 || str[size-1] != '\0') {
+                    char ccKey[5];
+                    MakeFourCCString(key, ccKey);
+                    if (src == nullptr) {
+                        ALOGW("ignoring key '%s' string with no data (expected %d)", ccKey, size);
+                    } else {
+                        ALOGW("ignoring key '%s': unterminated string of %d bytes", ccKey, size);
+                    }
+                } else {
+                    setData(key, type, src, size);
+                }
             } else {
                 // copy data directly from Parcel storage, then advance position
-                setData(key, type, parcel.readInplace(size), size);
+                // verify that the received size is enough
+                uint32_t needed = 0;
+                switch (type) {
+                    case TYPE_INT32:
+                        needed = sizeof(int32_t);
+                        break;
+                    case TYPE_INT64:
+                        needed = sizeof(int64_t);
+                        break;
+                    case TYPE_FLOAT:
+                        needed = sizeof(float);
+                        break;
+                    case TYPE_POINTER:
+                        // NB: this rejects passing between 32-bit and 64-bit space.
+                        needed = sizeof(void*);
+                        break;
+                    case TYPE_RECT:
+                        needed = sizeof(Rect);
+                        break;
+                    default:
+                        // non-standard entities can be any size >= 0
+                        needed = 0;
+                        break;
+                }
+                const void *src = parcel.readInplace(size);
+                if (src == nullptr || (needed != 0 && size != needed)) {
+                    char ccKey[5];
+                    MakeFourCCString(key, ccKey);
+                    char ccType[5];
+                    MakeFourCCString(type, ccType);
+                    if (src == nullptr) {
+                        ALOGW("ignoring key '%s' type '%s' missing data (expected %d)",
+                              ccKey, ccType, size);
+                    } else {
+                        ALOGW("ignoring key '%s': type '%s' bytes: expected %d != %d received",
+                               ccKey, ccType, needed, size);
+                    }
+                } else {
+                    setData(key, type, src, size);
+                }
             }
          }
 
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
index e8fee42..7e33f09 100644
--- a/media/libstagefright/omx/OMXStore.cpp
+++ b/media/libstagefright/omx/OMXStore.cpp
@@ -99,6 +99,15 @@
     }
 }
 
+static int getFirstApiLevel() {
+    int boardApiLevel = android::base::GetIntProperty("ro.board.first_api_level", 0);
+    if (boardApiLevel != 0) {
+        return boardApiLevel;
+    }
+
+    return android::base::GetIntProperty("ro.product.first_api_level", __ANDROID_API_T__);
+}
+
 void OMXStore::addPlugin(OMXPluginBase *plugin) {
     Mutex::Autolock autoLock(mLock);
 
@@ -110,6 +119,29 @@
                     name, sizeof(name), index++)) == OMX_ErrorNone) {
         String8 name8(name);
 
+        Vector<String8> roles;
+        OMX_ERRORTYPE err = plugin->getRolesOfComponent(name, &roles);
+        if (err == OMX_ErrorNone) {
+            bool skip = false;
+            for (String8 role : roles) {
+                if (role.find("video_decoder") != -1 || role.find("video_encoder") != -1) {
+                    if (getFirstApiLevel() >= __ANDROID_API_S__) {
+                        skip = true;
+                        break;
+                    }
+                }
+                if (role.find("audio_decoder") != -1 || role.find("audio_encoder") != -1) {
+                    if (getFirstApiLevel() >= __ANDROID_API_T__) {
+                        skip = true;
+                        break;
+                    }
+                }
+            }
+            if (skip) {
+                continue;
+            }
+        }
+
         if (mPluginByComponentName.indexOfKey(name8) >= 0) {
             ALOGE("A component of name '%s' already exists, ignoring this one.",
                  name8.string());
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 07fc5de..6d3c348 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -388,9 +388,11 @@
         mode = CryptoPlugin::kMode_AES_CTR;
     }
 
+    sp<ABuffer> clearbuf;
+    sp<ABuffer> cryptedbuf;
     if (sizeof(uint32_t) != sizeof(size_t)) {
-        sp<ABuffer> clearbuf   = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)cleardata);
-        sp<ABuffer> cryptedbuf = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)crypteddata);
+        clearbuf   = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)cleardata);
+        cryptedbuf = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)crypteddata);
         cleardata   = clearbuf    == NULL ? NULL : clearbuf->data();
         crypteddata = crypteddata == NULL ? NULL : cryptedbuf->data();
         if(crypteddata == NULL || cleardata == NULL) {
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 5633374..4938f76 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -437,18 +437,28 @@
 
 /**
  * Set an asynchronous callback for actionable AMediaCodec events.
- * When asynchronous callback is enabled, the client should not call
+ * When asynchronous callback is enabled, it is an error for the client to call
  * AMediaCodec_getInputBuffers(), AMediaCodec_getOutputBuffers(),
  * AMediaCodec_dequeueInputBuffer() or AMediaCodec_dequeueOutputBuffer().
  *
- * Also, AMediaCodec_flush() behaves differently in asynchronous mode.
- * After calling AMediaCodec_flush(), you must call AMediaCodec_start() to
- * "resume" receiving input buffers, even if an input surface was created.
+ * AMediaCodec_flush() behaves differently in asynchronous mode.
+ * After calling AMediaCodec_flush(), the client must call AMediaCodec_start() to
+ * "resume" receiving input buffers. Even if the client does not receive
+ * AMediaCodecOnAsyncInputAvailable callbacks from video encoders configured
+ * with an input surface, the client still needs to call AMediaCodec_start()
+ * to resume the input surface to send buffers to the encoders.
+ *
+ * When called with null callback, this method unregisters any previously set callback.
  *
  * Refer to the definition of AMediaCodecOnAsyncNotifyCallback on how each
  * callback function is called and what are specified.
- * The specified userdata is the pointer used when those callback functions are
- * called.
+ * The specified userdata is opaque data which will be passed along
+ * when the callback functions are called. MediaCodec does not look at or alter the
+ * value of userdata. Often it is a pointer to a client-owned object,
+ * and client manages the lifecycle of the object in that case.
+ *
+ * Once the callback is unregistered or the codec is reset / released, the
+ * previously registered callback will not be called.
  *
  * All callbacks are fired on one NDK internal thread.
  * AMediaCodec_setAsyncNotifyCallback should not be called on the callback thread.
@@ -471,10 +481,17 @@
  * render timing samples, and can be significantly delayed and batched. Some frames may have
  * been rendered even if there was no callback generated.
  *
+ * When called with null callback, this method unregisters any previously set callback.
+ *
  * Refer to the definition of AMediaCodecOnFrameRendered on how each
  * callback function is called and what are specified.
- * The specified userdata is the pointer used when those callback functions are
- * called.
+ * The specified userdata is opaque data which will be passed along
+ * when the callback functions are called. MediaCodec does not look at or alter the
+ * value of userdata. Often it is a pointer to a client-owned object,
+ * and client manages the lifecycle of the object in that case.
+ *
+ * Once the callback is unregistered or the codec is reset / released, the
+ * previously registered callback will not be called.
  *
  * All callbacks are fired on one NDK internal thread.
  * AMediaCodec_setOnFrameRenderedCallback should not be called on the callback thread.
diff --git a/media/utils/include/mediautils/ScopedStatistics.h b/media/utils/include/mediautils/ScopedStatistics.h
new file mode 100644
index 0000000..c5fc1e9
--- /dev/null
+++ b/media/utils/include/mediautils/ScopedStatistics.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "MethodStatistics.h"
+#include <chrono>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android::mediautils {
+
+class ScopedStatistics {
+  public:
+    /**
+     * ScopedStatistics is a RAII way of obtaining
+     * execution time statistics for a scoped C++ block.
+     *
+     * It updates the MethodStatistics shared pointer parameter
+     * with the methodName parameter and the duration/lifetime of the
+     * ScopedStatistics object.
+     *
+     * Not thread-safe, but expected to run in a single execution
+     * thread, and there are no user serviceable parts exposed.
+     *
+     * Example:
+     *
+     * std::shared_ptr<mediautils::MethodStatistics<std::string>> stats =
+     *     std::make_shared<mediautils::MethodStatistics<std::string>>();
+     *
+     * // ...
+     * {
+     *    mediautils::ScopedStatistics scopedStatistics("MyClass:myMethod", stats);
+     *
+     *    // some work to be timed here - up to the end of the block.
+     * }
+     *
+     * \param methodName the methodname to use "ClassName::methodName"
+     * \param statistics a shared ptr to the MethodStatistics object to use.
+     */
+    ScopedStatistics(std::string methodName,
+               std::shared_ptr<mediautils::MethodStatistics<std::string>> statistics)
+        : mMethodName{std::move(methodName)}
+        , mStatistics{std::move(statistics)}
+        , mBegin{std::chrono::steady_clock::now()} {}
+
+    // No copy constructor.
+    ScopedStatistics(const ScopedStatistics& scopedStatistics) = delete;
+    ScopedStatistics& operator=(const ScopedStatistics& scopedStatistics) = delete;
+
+    ~ScopedStatistics() {
+        if (mStatistics) {
+            const float elapsedMs = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                                            std::chrono::steady_clock::now() - mBegin)
+                                            .count() *
+                                    1e-6; // ns to ms.
+            mStatistics->event(mMethodName, elapsedMs);
+        }
+    }
+
+  private:
+    const std::string mMethodName;
+    const std::shared_ptr<mediautils::MethodStatistics<std::string>> mStatistics;
+    const std::chrono::steady_clock::time_point mBegin;
+};
+
+} // namespace android::mediautils
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index a6f408d..1024018 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -124,6 +124,27 @@
 }
 
 cc_test {
+    name: "mediautils_scopedstatistics_tests",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "liblog",
+        "libmediautils",
+        "libutils",
+    ],
+
+    srcs: [
+        "mediautils_scopedstatistics_tests.cpp",
+    ],
+}
+
+cc_test {
     name: "methodstatistics_tests",
 
     cflags: [
diff --git a/media/utils/tests/mediautils_scopedstatistics_tests.cpp b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
new file mode 100644
index 0000000..807ce63
--- /dev/null
+++ b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediautils_scopedstatistics_tests"
+
+#include <mediautils/ScopedStatistics.h>
+
+#include <atomic>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <thread>
+#include <utils/Log.h>
+
+using namespace android::mediautils;
+using namespace std::chrono_literals;
+
+TEST(mediautils_scopedstatistics_tests, basic) {
+    auto methodStatistics = std::make_shared<MethodStatistics<std::string>>();
+    std::string METHOD_NAME{"MyMethod"};
+
+    // no stats before
+    auto empty = methodStatistics->getStatistics(METHOD_NAME);
+    ASSERT_EQ(0, empty.getN());
+
+    // create a scoped statistics object.
+    {
+        ScopedStatistics scopedStatistics(METHOD_NAME, methodStatistics);
+
+        std::this_thread::sleep_for(100ms);
+    }
+
+    // check that some stats were logged.
+    auto stats = methodStatistics->getStatistics(METHOD_NAME);
+    ASSERT_EQ(1, stats.getN());
+    auto mean = stats.getMean();
+
+    // mean should be about 100ms, but to avoid false failures,
+    // we check 50ms < mean < 300ms.
+    ASSERT_GT(mean, 50.);   // took more than 50ms.
+    ASSERT_LT(mean, 300.);  // took less than 300ms.
+}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9344e20..49f6bfc 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -978,7 +978,8 @@
             || mType == MIXER
             || mType == DUPLICATING
             || mType == DIRECT
-            || mType == OFFLOAD) {
+            || mType == OFFLOAD
+            || mType == SPATIALIZER) {
         dprintf(fd, "  Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
         dprintf(fd, "  Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
     }
@@ -3007,6 +3008,7 @@
 
     // Calculate size of normal sink buffer relative to the HAL output buffer size
     double multiplier = 1.0;
+    // Note: mType == SPATIALIZER does not support FastMixer.
     if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
             kUseFastMixer == FastMixer_Dynamic)) {
         size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
@@ -3468,7 +3470,7 @@
     sp<EffectBufferHalInterface> halInBuffer, halOutBuffer;
     effect_buffer_t *buffer = nullptr; // only used for non global sessions
 
-    if (mType == SPATIALIZER ) {
+    if (mType == SPATIALIZER) {
         if (!audio_is_global_session(session)) {
             // player sessions on a spatializer output will use a dedicated input buffer and
             // will either output multi channel to mEffectBuffer if the track is spatilaized
@@ -3694,7 +3696,7 @@
     cacheParameters_l();
     mSleepTimeUs = mIdleSleepTimeUs;
 
-    if (mType == MIXER) {
+    if (mType == MIXER || mType == SPATIALIZER) {
         sleepTimeShift = 0;
     }
 
@@ -3872,7 +3874,7 @@
 
                     mStandbyTimeNs = systemTime() + mStandbyDelayNs;
                     mSleepTimeUs = mIdleSleepTimeUs;
-                    if (mType == MIXER) {
+                    if (mType == MIXER || mType == SPATIALIZER) {
                         sleepTimeShift = 0;
                     }
 
@@ -4149,7 +4151,8 @@
 
                             // write blocked detection
                             const int64_t deltaWriteNs = lastIoEndNs - lastIoBeginNs;
-                            if (mType == MIXER && deltaWriteNs > maxPeriod) {
+                            if ((mType == MIXER || mType == SPATIALIZER)
+                                    && deltaWriteNs > maxPeriod) {
                                 mNumDelayedWrites++;
                                 if ((lastIoEndNs - lastWarning) > kWarningThrottleNs) {
                                     ATRACE_NAME("underrun");
@@ -4170,7 +4173,7 @@
                         (mMixerStatus == MIXER_DRAIN_ALL)) {
                     threadLoop_drain();
                 }
-                if (mType == MIXER && !mStandby) {
+                if ((mType == MIXER || mType == SPATIALIZER) && !mStandby) {
 
                     if (mThreadThrottle
                             && mMixerStatus == MIXER_TRACKS_READY // we are mixing (active tracks)
@@ -4295,13 +4298,6 @@
 
 void AudioFlinger::PlaybackThread::collectTimestamps_l()
 {
-    // Collect timestamp statistics for the Playback Thread types that support it.
-    if (mType != MIXER
-            && mType != DUPLICATING
-            && mType != DIRECT
-            && mType != OFFLOAD) {
-        return;
-    }
     if (mStandby) {
         mTimestampVerifier.discontinuity(discontinuityForStandbyOrFlush());
         return;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 20d0523..496591a 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -533,6 +533,10 @@
 
     virtual void onRoutingUpdated() = 0;
 
+    // Used to notify AudioService that an error was encountering when reading
+    // the volume ranges, and that they should be re-initialized
+    virtual void onVolumeRangeInitRequest() = 0;
+
     // Used to notify the sound trigger module that an audio capture is about to
     // take place. This should typically result in any active recognition
     // sessions to be preempted on modules that do not support sound trigger
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 64c7923..75fa595 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -518,6 +518,14 @@
                                       uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
 
     /**
+     * @brief isStrategyActive checks if the given strategy is active
+     * on the given output
+     * @param ps product strategy to be checked upon activity status
+     * @return true if an output following the strategy is active, false otherwise
+     */
+    bool isStrategyActive(product_strategy_t ps) const;
+
+    /**
      * @brief clearSessionRoutesForDevice: when a device is disconnected, and if this device has
      * been chosen as the preferred device by any client, the policy manager shall
      * prevent from using this device any more by clearing all the session routes involving this
@@ -562,6 +570,11 @@
 
     sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
 
+    /**
+     * return whether any output is active and routed to any of the specified devices
+     */
+    bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+
     void dump(String8 *dst) const;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 009fa82..40a1eaa 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -841,6 +841,16 @@
     return false;
 }
 
+bool SwAudioOutputCollection::isStrategyActive(product_strategy_t ps) const
+{
+    for (size_t i = 0; i < size(); i++) {
+        if (valueAt(i)->isStrategyActive(ps)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 audio_io_handle_t SwAudioOutputCollection::getA2dpOutput() const
 {
     for (size_t i = 0; i < size(); i++) {
@@ -916,6 +926,16 @@
         }
     }
 }
+bool SwAudioOutputCollection::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+    for (size_t i = 0; i < size(); i++) {
+        const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+        if (outputDesc->isActive()
+                && outputDesc->devices().containsDeviceAmongTypes(deviceTypes)) {
+            return true;
+        }
+    }
+    return false;
+}
 
 void SwAudioOutputCollection::dump(String8 *dst) const
 {
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index d1655ef..713b0ac 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -125,7 +125,7 @@
 
 void SourceClientCollection::dump(String8 *dst) const
 {
-    dst->append("\n Audio sources (%zu):\n", size());
+    dst->appendFormat("\n Audio sources (%zu):\n", size());
     for (size_t i = 0; i < size(); i++) {
         const std::string prefix = base::StringPrintf("  %zu. ", i + 1);
         dst->appendFormat("%s", prefix.c_str());
diff --git a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
index 22ff954..d34cca0 100644
--- a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
@@ -11,17 +11,7 @@
                      channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
         </mixPort>
         <!-- Le Audio Audio Ports -->
-        <mixPort name="le audio output" role="source">
-            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                     samplingRates="8000,16000,24000,32000,44100,48000"
-                     channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
-            <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                     samplingRates="8000,16000,24000,32000,44100,48000"
-                     channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
-            <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
-                     samplingRates="8000,16000,24000,32000,44100,48000"
-                     channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
-        </mixPort>
+        <mixPort name="le audio output" role="source"/>
         <mixPort name="le audio input" role="sink">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                      samplingRates="8000,16000,24000,32000,44100,48000"
diff --git a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
index aad00d6..e7908eb 100644
--- a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
@@ -11,17 +11,7 @@
                      channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
         </mixPort>
         <!-- Le Audio Audio Ports -->
-        <mixPort name="le audio output" role="source">
-            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                     samplingRates="8000 16000 24000 32000 44100 48000"
-                     channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
-            <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                     samplingRates="8000 16000 24000 32000 44100 48000"
-                     channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
-            <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
-                     samplingRates="8000 16000 24000 32000 44100 48000"
-                     channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
-        </mixPort>
+        <mixPort name="le audio output" role="source" />
         <mixPort name="le audio input" role="sink">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                      samplingRates="8000 16000 24000 32000 44100 48000"
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 0f8b0a5..7d21ae0 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -87,10 +87,17 @@
 
     status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
 
+    /**
+     * Get the list of currently connected removable device types ordered from most recently
+     * connected to least recently connected.
+     * @param group the device group to consider: wired, a2dp... If none, consider all groups.
+     * @param excludedDevices list of device types to ignore
+     * @return a potentially empty ordered list of connected removable devices.
+     */
     std::vector<audio_devices_t> getLastRemovableMediaDevices(
-            device_out_group_t group = GROUP_NONE) const
-    {
-        return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group);
+            device_out_group_t group = GROUP_NONE,
+            std::vector<audio_devices_t> excludedDevices = {}) const {
+        return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group, excludedDevices);
     }
 
     void dump(String8 *dst) const override;
diff --git a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
index d7f8b1e..2662cd3 100644
--- a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
+++ b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
@@ -35,7 +35,8 @@
 public:
     void setRemovableMediaDevices(sp<DeviceDescriptor> desc, audio_policy_dev_state_t state);
     std::vector<audio_devices_t> getLastRemovableMediaDevices(
-            device_out_group_t group = GROUP_NONE) const;
+            device_out_group_t group = GROUP_NONE,
+            std::vector<audio_devices_t> excludedDevices = {}) const;
     sp<DeviceDescriptor> getLastRemovableMediaDevice(
             const DeviceVector& excludedDevices, device_out_group_t group = GROUP_NONE) const;
 
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 7a06206..99507ee 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -72,9 +72,12 @@
 {
     audio_devices_t deviceType = devDesc->type();
     if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)
-            && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+            && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET
+            && deviceType != AUDIO_DEVICE_OUT_BLE_BROADCAST) {
         // USB dock does not follow the rule of last removable device connected wins.
         // It is only used if no removable device is connected or if set as preferred device
+        // LE audio broadcast device has a specific policy depending on active strategies and
+        // devices and does not follow the rule of last connected removable device.
         mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
     }
 
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index 06cc799..93122e0 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -44,12 +44,15 @@
 }
 
 std::vector<audio_devices_t> LastRemovableMediaDevices::getLastRemovableMediaDevices(
-        device_out_group_t group) const
+        device_out_group_t group, std::vector<audio_devices_t> excludedDevices) const
 {
     std::vector<audio_devices_t> ret;
     for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
-        if ((group == GROUP_NONE) || (group == getDeviceOutGroup((iter->desc)->type()))) {
-            ret.push_back((iter->desc)->type());
+        audio_devices_t type = (iter->desc)->type();
+        if ((group == GROUP_NONE || group == getDeviceOutGroup(type))
+                && std::find(excludedDevices.begin(), excludedDevices.end(), type) ==
+                                       excludedDevices.end()) {
+            ret.push_back(type);
         }
     }
     return ret;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index dc34a38..95aacb2 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -270,7 +270,7 @@
         devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
         if (!devices.isEmpty()) break;
         devices = availableOutputDevices.getFirstDevicesFromTypes(
-                                          getLastRemovableMediaDevices());
+                        getLastRemovableMediaDevices(GROUP_NONE, {AUDIO_DEVICE_OUT_BLE_HEADSET}));
         if (!devices.isEmpty()) break;
         devices = availableOutputDevices.getFirstDevicesFromTypes({
                 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_EARPIECE});
@@ -344,6 +344,30 @@
             (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
             devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
+
+        // LE audio broadcast device is only used if:
+        // - No call is active
+        // - either MEDIA or SONIFICATION_RESPECTFUL is the highest priority active strategy
+        //   OR the LE audio unicast device is not active
+        if (devices2.isEmpty() && !isInCall()
+                && (strategy == STRATEGY_MEDIA || strategy == STRATEGY_SONIFICATION_RESPECTFUL)) {
+            legacy_strategy topActiveStrategy = STRATEGY_NONE;
+            for (const auto &ps : getOrderedProductStrategies()) {
+                if (outputs.isStrategyActive(ps)) {
+                    topActiveStrategy =  mLegacyStrategyMap.find(ps) != end(mLegacyStrategyMap) ?
+                            mLegacyStrategyMap.at(ps) : STRATEGY_NONE;
+                    break;
+                }
+            }
+
+            if (topActiveStrategy == STRATEGY_NONE || topActiveStrategy == STRATEGY_MEDIA
+                    || topActiveStrategy == STRATEGY_SONIFICATION_RESPECTFUL
+                    || !outputs.isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet())) {
+                devices2 =
+                        availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST);
+            }
+        }
+
         if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
             if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
                 // Get the last connected device of wired and bluetooth a2dp
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 49a0dde..d6384f0 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -190,6 +190,9 @@
         // save a copy of the opened output descriptors before any output is opened or closed
         // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
         mPreviousOutputs = mOutputs;
+
+        bool wasLeUnicastActive = isLeUnicastActive();
+
         switch (state)
         {
         // handle output device connection
@@ -356,6 +359,8 @@
             cleanUpForDevice(device);
         }
 
+        checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, 0);
+
         mpClientInterface->onAudioPortListUpdate();
         return NO_ERROR;
     }  // end if is output device
@@ -804,6 +809,7 @@
     ALOGV("setPhoneState() state %d", state);
     // store previous phone state for management of sonification strategy below
     int oldState = mEngine->getPhoneState();
+    bool wasLeUnicastActive = isLeUnicastActive();
 
     if (mEngine->setPhoneState(state) != NO_ERROR) {
         ALOGW("setPhoneState() invalid or same state %d", state);
@@ -882,6 +888,8 @@
         }
     }
 
+    checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
+
     if (isStateInCall(state)) {
         ALOGV("setPhoneState() in call state management: new state is %d", state);
         // force reevaluating accessibility routing when call starts
@@ -1989,6 +1997,22 @@
     return status;
 }
 
+bool AudioPolicyManager::isLeUnicastActive() const {
+    if (isInCall()) {
+        return true;
+    }
+    return isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet());
+}
+
+bool AudioPolicyManager::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+    if (mAvailableOutputDevices.getDevicesFromTypes(deviceTypes).isEmpty()) {
+        return false;
+    }
+    bool active = mOutputs.isAnyDeviceTypeActive(deviceTypes);
+    ALOGV("%s active %d", __func__, active);
+    return active;
+}
+
 status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
                                          const sp<TrackClientDescriptor>& client,
                                          uint32_t *delayMs)
@@ -2040,6 +2064,7 @@
     // and muting would result in unnecessary delay and dropped audio.
     const uint32_t outputLatencyMs = outputDesc->latency();
     bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2);  // account for drain
+    bool wasLeUnicastActive = isLeUnicastActive();
 
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -2118,11 +2143,15 @@
 
         // apply volume rules for current stream and device if necessary
         auto &curves = getVolumeCurves(client->attributes());
-        checkAndSetVolume(curves, client->volumeSource(),
+        if (NO_ERROR != checkAndSetVolume(curves, client->volumeSource(),
                           curves.getVolumeIndex(outputDesc->devices().types()),
                           outputDesc,
                           outputDesc->devices().types(), 0 /*delay*/,
-                          outputDesc->useHwGain() /*force*/);
+                          outputDesc->useHwGain() /*force*/)) {
+            // request AudioService to reinitialize the volume curves asynchronously
+            ALOGE("checkAndSetVolume failed, requesting volume range init");
+            mpClientInterface->onVolumeRangeInitRequest();
+        };
 
         // update the outputs if starting an output with a stream that can affect notification
         // routing
@@ -2163,9 +2192,38 @@
                                     AUDIO_FORMAT_DEFAULT);
     }
 
+    checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, *delayMs);
+
     return NO_ERROR;
 }
 
+void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive,
+        sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs) {
+    bool isUnicastActive = isLeUnicastActive();
+
+    if (wasUnicastActive != isUnicastActive) {
+        //reroute all outputs routed to LE broadcast if LE unicast activy changed on any output
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+            if (desc != ignoredOutput && desc->isActive()
+                    && ((isUnicastActive &&
+                            !desc->devices().
+                                    getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST).isEmpty())
+                        || (wasUnicastActive &&
+                            !desc->devices().getDevicesFromTypes(
+                                    getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) {
+                DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/);
+                bool force = desc->devices() != newDevices;
+                setOutputDevices(desc, newDevices, force, delayMs);
+                // re-apply device specific volume if not done by setOutputDevice()
+                if (!force) {
+                    applyStreamVolumes(desc, newDevices.types(), delayMs);
+                }
+            }
+        }
+    }
+}
+
 status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
 {
     ALOGV("%s portId %d", __FUNCTION__, portId);
@@ -2194,6 +2252,7 @@
     // always handle stream stop, check which stream type is stopping
     audio_stream_type_t stream = client->stream();
     auto clientVolSrc = client->volumeSource();
+    bool wasLeUnicastActive = isLeUnicastActive();
 
     handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
 
@@ -2272,6 +2331,9 @@
         if (followsSameRouting(client->attributes(), attributes_initializer(AUDIO_USAGE_MEDIA))) {
             selectOutputForMusicEffects();
         }
+
+        checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, outputDesc->latency()*2);
+
         return NO_ERROR;
     } else {
         ALOGW("stopOutput() refcount is already 0");
@@ -2347,7 +2409,6 @@
           session, flags, toString(*attr).c_str(), *selectedDeviceId);
 
     status_t status = NO_ERROR;
-    audio_source_t halInputSource;
     audio_attributes_t attributes = *attr;
     sp<AudioPolicyMix> policyMix;
     sp<DeviceDescriptor> device;
@@ -2418,8 +2479,6 @@
     *input = AUDIO_IO_HANDLE_NONE;
     *inputType = API_INPUT_INVALID;
 
-    halInputSource = attributes.source;
-
     if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
             strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
         status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
@@ -3581,6 +3640,7 @@
 void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
 {
     uint32_t waitMs = 0;
+    bool wasLeUnicastActive = isLeUnicastActive();
     if (updateCallRouting(true /*fromCache*/, delayMs, &waitMs) == NO_ERROR) {
         // Only apply special touch sound delay once
         delayMs = 0;
@@ -3604,6 +3664,7 @@
             applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
         }
     }
+    checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
 }
 
 void AudioPolicyManager::updateInputRouting() {
@@ -7290,6 +7351,11 @@
         deviceTypes = outputDesc->devices().types();
     }
 
+    if (curves.getVolumeIndexMin() < 0 || curves.getVolumeIndexMax() < 0) {
+        ALOGE("invalid volume index range");
+        return BAD_VALUE;
+    }
+
     float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
     if (outputDesc->isFixedVolume(deviceTypes) ||
             // Force VoIP volume to max for bluetooth SCO device except if muted
@@ -7434,13 +7500,11 @@
     return mEngine->getForceUse(usage);
 }
 
-bool AudioPolicyManager::isInCall()
-{
+bool AudioPolicyManager::isInCall() const {
     return isStateInCall(mEngine->getPhoneState());
 }
 
-bool AudioPolicyManager::isStateInCall(int state)
-{
+bool AudioPolicyManager::isStateInCall(int state) const {
     return is_state_in_call(state);
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 0d9b5bf..441a0b7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -598,9 +598,9 @@
         audio_mode_t getPhoneState();
 
         // true if device is in a telephony or VoIP call
-        virtual bool isInCall();
+        virtual bool isInCall() const;
         // true if given state represents a device in a telephony or VoIP call
-        virtual bool isStateInCall(int state);
+        virtual bool isStateInCall(int state) const;
         // true if playback to call TX or capture from call RX is possible
         bool isCallAudioAccessible();
 
@@ -887,6 +887,21 @@
         void closeActiveClients(const sp<AudioInputDescriptor>& input);
         void closeClient(audio_port_handle_t portId);
 
+        /**
+         * @brief isAnyDeviceTypeActive: returns true if at least one active client is routed to
+         * one of the specified devices
+         * @param deviceTypes list of devices to consider
+         */
+        bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+        /**
+         * @brief isLeUnicastActive: returns true if a call is active or at least one active client
+         * is routed to a LE unicast device
+         */
+        bool isLeUnicastActive() const;
+
+        void checkLeBroadcastRoutes(bool wasUnicastActive,
+                sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs);
+
         const uid_t mUidCached;                         // AID_AUDIOSERVER
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 63a1e71..c766a15 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -277,6 +277,11 @@
     mAudioPolicyService->onRoutingUpdated();
 }
 
+void AudioPolicyService::AudioPolicyClient::onVolumeRangeInitRequest()
+{
+    mAudioPolicyService->onVolumeRangeInitRequest();
+}
+
 audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId(audio_unique_id_use_t use)
 {
     return AudioSystem::newAudioUniqueId(use);
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index da0a4a9..e7d945f 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -488,6 +488,19 @@
     }
 }
 
+void AudioPolicyService::onVolumeRangeInitRequest()
+{
+    mOutputCommandThread->volRangeInitReqCommand();
+}
+
+void AudioPolicyService::doOnVolumeRangeInitRequest()
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+    for (size_t i = 0; i < mNotificationClients.size(); i++) {
+        mNotificationClients.valueAt(i)->onVolumeRangeInitRequest();
+    }
+}
+
 void AudioPolicyService::onCheckSpatializer()
 {
     Mutex::Autolock _l(mLock);
@@ -721,6 +734,13 @@
     }
 }
 
+void AudioPolicyService::NotificationClient::onVolumeRangeInitRequest()
+{
+    if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
+        mAudioPolicyServiceClient->onVolumeRangeInitRequest();
+    }
+}
+
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
             IPCThreadState::self()->getCallingPid());
@@ -1938,12 +1958,16 @@
     while (!exitPending())
     {
         sp<AudioPolicyService> svc;
+        int numTimesBecameEmpty = 0;
         while (!mAudioCommands.isEmpty() && !exitPending()) {
             nsecs_t curTime = systemTime();
             // commands are sorted by increasing time stamp: execute them from index 0 and up
             if (mAudioCommands[0]->mTime <= curTime) {
                 sp<AudioCommand> command = mAudioCommands[0];
                 mAudioCommands.removeAt(0);
+                if (mAudioCommands.isEmpty()) {
+                  ++numTimesBecameEmpty;
+                }
                 mLastCommand = command;
 
                 switch (command->mCommand) {
@@ -2157,6 +2181,17 @@
                     mLock.lock();
                     } break;
 
+                case VOL_RANGE_INIT_REQUEST: {
+                    ALOGV("AudioCommandThread() processing volume range init request");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnVolumeRangeInitRequest();
+                    mLock.lock();
+                    } break;
+
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
@@ -2180,8 +2215,9 @@
             }
         }
 
-        // release delayed commands wake lock if the queue is empty
-        if (mAudioCommands.isEmpty()) {
+        // release delayed commands wake lock as many times as we made the  queue is
+        // empty during popping.
+        while (numTimesBecameEmpty--) {
             release_wake_lock(mName.string());
         }
 
@@ -2480,6 +2516,14 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::volRangeInitReqCommand()
+{
+    sp<AudioCommand>command = new AudioCommand();
+    command->mCommand = VOL_RANGE_INIT_REQUEST;
+    ALOGV("AudioCommandThread() adding volume range init request");
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
 {
     {
@@ -2647,6 +2691,10 @@
 
         } break;
 
+        case VOL_RANGE_INIT_REQUEST: {
+            // command may come from different requests, do not filter
+        } break;
+
         default:
             break;
         }
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d863ff1..3a08cf8 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -343,6 +343,9 @@
     void onRoutingUpdated();
     void doOnRoutingUpdated();
 
+    void onVolumeRangeInitRequest();
+    void doOnVolumeRangeInitRequest();
+
     /**
      * Spatializer SpatializerPolicyCallback implementation.
      * onCheckSpatializer() sends an event on mOutputCommandThread which executes
@@ -530,7 +533,8 @@
             ROUTING_UPDATED,
             UPDATE_UID_STATES,
             CHECK_SPATIALIZER_OUTPUT, // verify if spatializer effect should be created or moved
-            UPDATE_ACTIVE_SPATIALIZER_TRACKS // Update active track counts on spalializer output
+            UPDATE_ACTIVE_SPATIALIZER_TRACKS, // Update active track counts on spalializer output
+            VOL_RANGE_INIT_REQUEST, // request to reset the volume range indices
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -581,6 +585,7 @@
                     void        updateUidStatesCommand();
                     void        checkSpatializerCommand();
                     void        updateActiveSpatializerTracksCommand();
+                    void        volRangeInitReqCommand();
 
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
     private:
@@ -803,6 +808,8 @@
 
         virtual void onRoutingUpdated();
 
+        virtual void onVolumeRangeInitRequest();
+
         virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
 
         void setSoundTriggerCaptureState(bool active) override;
@@ -842,6 +849,7 @@
                                                     audio_patch_handle_t patchHandle,
                                                     audio_source_t source);
                             void      onRoutingUpdated();
+                            void      onVolumeRangeInitRequest();
                             void      setAudioPortCallbacksEnabled(bool enabled);
                             void setAudioVolumeGroupCallbacksEnabled(bool enabled);
 
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 389233e..ef11072 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -342,12 +342,7 @@
 
     modes->push_back(SpatializerHeadTrackingMode::DISABLED);
     if (mSupportsHeadTracking) {
-        if (mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
-            modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
-            if (mScreenSensor != SpatializerPoseController::INVALID_SENSOR) {
-                modes->push_back(SpatializerHeadTrackingMode::RELATIVE_SCREEN);
-            }
-        }
+        modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
     }
     return Status::ok();
 }
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index adef8f1..057fa58 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -138,7 +138,12 @@
     }
 
     size_t getRoutingUpdatedCounter() const {
-        return mRoutingUpdatedUpdateCount; }
+        return mRoutingUpdatedUpdateCount;
+    }
+
+    void onVolumeRangeInitRequest() override {
+
+    }
 
     status_t updateSecondaryOutputs(
             const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index da85658..8a85fee 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -85,6 +85,7 @@
                                         audio_patch_handle_t patchHandle __unused,
                                         audio_source_t source __unused) override { }
     void onRoutingUpdated() override { }
+    void onVolumeRangeInitRequest() override { }
     void setEffectSuspended(int effectId __unused,
                             audio_session_t sessionId __unused,
                             bool suspended __unused) {}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 1e2dccb..9bacaf4 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -42,6 +42,7 @@
 
     srcs: [
         "CameraService.cpp",
+        "CameraServiceWatchdog.cpp",
         "CameraFlashlight.cpp",
         "common/Camera2ClientBase.cpp",
         "common/CameraDeviceBase.cpp",
@@ -81,6 +82,7 @@
         "device3/Camera3OutputUtils.cpp",
         "device3/Camera3DeviceInjectionMethods.cpp",
         "device3/UHRCropAndMeteringRegionMapper.cpp",
+        "device3/PreviewFrameSpacer.cpp",
         "device3/hidl/HidlCamera3Device.cpp",
         "device3/hidl/HidlCamera3OfflineSession.cpp",
         "device3/hidl/HidlCamera3OutputUtils.cpp",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a965080..741138e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1688,6 +1688,13 @@
         return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
 
+    if (CameraServiceProxyWrapper::isCameraDisabled()) {
+        String8 msg =
+                String8::format("Camera disabled by device policy");
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(ERROR_DISABLED, msg.string());
+    }
+
     // enforce system camera permissions
     if (oomScoreOffset > 0 &&
             !hasPermissionsForSystemCamera(callingPid, CameraThreadState::getCallingUid())) {
@@ -3717,21 +3724,10 @@
 
 void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
         int64_t procStateSeq __unused, int32_t capability __unused) {
-    bool procStateChange = false;
-    {
-        Mutex::Autolock _l(mUidLock);
-        if (mMonitoredUids.find(uid) != mMonitoredUids.end() &&
-                mMonitoredUids[uid].procState != procState) {
-            mMonitoredUids[uid].procState = procState;
-            procStateChange = true;
-        }
-    }
-
-    if (procStateChange) {
-        sp<CameraService> service = mService.promote();
-        if (service != nullptr) {
-            service->notifyMonitoredUids();
-        }
+    Mutex::Autolock _l(mUidLock);
+    if (mMonitoredUids.find(uid) != mMonitoredUids.end() &&
+            mMonitoredUids[uid].procState != procState) {
+        mMonitoredUids[uid].procState = procState;
     }
 }
 
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.cpp b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
new file mode 100644
index 0000000..fcd6ebe
--- /dev/null
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CameraServiceWatchdog"
+
+#include "CameraServiceWatchdog.h"
+
+namespace android {
+
+bool CameraServiceWatchdog::threadLoop()
+{
+    {
+        AutoMutex _l(mWatchdogLock);
+
+        while (mPause) {
+            mWatchdogCondition.wait(mWatchdogLock);
+        }
+    }
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(mCycleLengthMs));
+
+    {
+        AutoMutex _l(mWatchdogLock);
+
+        for (auto it = tidToCycleCounterMap.begin(); it != tidToCycleCounterMap.end(); it++) {
+            uint32_t currentThreadId = it->first;
+
+            tidToCycleCounterMap[currentThreadId]++;
+
+            if (tidToCycleCounterMap[currentThreadId] >= mMaxCycles) {
+                ALOGW("CameraServiceWatchdog triggering kill for pid: %d", getpid());
+                kill(getpid(), SIGKILL);
+            }
+        }
+    }
+
+    return true;
+}
+
+void CameraServiceWatchdog::requestExit()
+{
+    Thread::requestExit();
+
+    AutoMutex _l(mWatchdogLock);
+
+    tidToCycleCounterMap.clear();
+
+    if (mPause) {
+        mPause = false;
+        mWatchdogCondition.signal();
+    }
+}
+
+void CameraServiceWatchdog::stop(uint32_t tid)
+{
+    AutoMutex _l(mWatchdogLock);
+
+    tidToCycleCounterMap.erase(tid);
+
+    if (tidToCycleCounterMap.empty()) {
+        mPause = true;
+    }
+}
+
+void CameraServiceWatchdog::start(uint32_t tid)
+{
+    AutoMutex _l(mWatchdogLock);
+
+    tidToCycleCounterMap[tid] = 0;
+
+    if (mPause) {
+        mPause = false;
+        mWatchdogCondition.signal();
+    }
+}
+
+}   // namespace android
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
new file mode 100644
index 0000000..f4955e2
--- /dev/null
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The CameraService watchdog is used to help detect bad states in the
+ * Camera HAL. The threadloop uses cycle counters, assigned to each calling
+ * thread, to monitor the elapsing time and kills the process when the
+ * expected duration has exceeded.
+ * Notes on multi-threaded behaviors:
+ *    - The threadloop is blocked/paused when there are no calls being
+ *   monitored.
+ *   - The start and stop functions handle simultaneous call monitoring
+ *   and single call monitoring differently. See function documentation for
+ *   more details.
+ */
+
+#include <chrono>
+#include <thread>
+#include <time.h>
+#include <utils/Thread.h>
+#include <utils/Log.h>
+#include <unordered_map>
+
+// Used to wrap the call of interest in start and stop calls
+#define WATCH(toMonitor) watchThread([&]() { return toMonitor;}, gettid())
+#define WATCH_CUSTOM_TIMER(toMonitor, cycles, cycleLength) \
+        watchThread([&]() { return toMonitor;}, gettid(), cycles, cycleLength);
+
+// Default cycles and cycle length values used to calculate permitted elapsed time
+const static size_t   kMaxCycles     = 100;
+const static uint32_t kCycleLengthMs = 100;
+
+namespace android {
+
+class CameraServiceWatchdog : public Thread {
+
+public:
+    explicit CameraServiceWatchdog() : mPause(true), mMaxCycles(kMaxCycles),
+            mCycleLengthMs(kCycleLengthMs) {};
+
+    explicit CameraServiceWatchdog (size_t maxCycles, uint32_t cycleLengthMs) :
+            mPause(true), mMaxCycles(maxCycles), mCycleLengthMs(cycleLengthMs) {};
+
+    virtual ~CameraServiceWatchdog() {};
+
+    virtual void requestExit();
+
+    /** Used to wrap monitored calls in start and stop functions using custom timer values */
+    template<typename T>
+    auto watchThread(T func, uint32_t tid, uint32_t cycles, uint32_t cycleLength) {
+        auto res = NULL;
+
+        if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) {
+            // Create another instance of the watchdog to prevent disruption
+            // of timer for current monitored calls
+            sp<CameraServiceWatchdog> tempWatchdog =
+                    new CameraServiceWatchdog(cycles, cycleLength);
+            tempWatchdog->run("CameraServiceWatchdog");
+            res = tempWatchdog->watchThread(func, tid);
+            tempWatchdog->requestExit();
+            tempWatchdog.clear();
+        } else {
+            // If custom timer values are equivalent to set class timer values, use
+            // current thread
+            res = watchThread(func, tid);
+        }
+
+        return res;
+    }
+
+    /** Used to wrap monitored calls in start and stop functions using class timer values */
+    template<typename T>
+    auto watchThread(T func, uint32_t tid) {
+        auto res = NULL;
+
+        start(tid);
+        res = func();
+        stop(tid);
+
+        return res;
+    }
+
+private:
+
+    /**
+     * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused,
+     * start() unblocks and starts the watchdog
+     */
+    void start(uint32_t tid);
+
+    /**
+     * If there are no calls left to be monitored, stop blocks/pauses threadloop
+     * otherwise stop() erases the cycle counter to end watchdog for the calling thread
+     */
+    void stop(uint32_t tid);
+
+    virtual bool    threadLoop();
+
+    Mutex           mWatchdogLock;        // Lock for condition variable
+    Condition       mWatchdogCondition;   // Condition variable for stop/start
+    bool            mPause;               // True if thread is currently paused
+    uint32_t        mMaxCycles;           // Max cycles
+    uint32_t        mCycleLengthMs;       // Length of time elapsed per cycle
+
+    std::unordered_map<uint32_t, uint32_t> tidToCycleCounterMap; // Thread Id to cycle counter map
+};
+
+}   // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 1f0e095..5db3fa6 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -721,8 +721,10 @@
     }
 
     *status = false;
+    camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
+          return mDevice->infoPhysical(id);};
     ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.string(),
-            sessionConfiguration, mOverrideForPerfClass, status);
+            sessionConfiguration, mOverrideForPerfClass, getMetadata, status);
     switch (ret) {
         case OK:
             // Expected, do nothing.
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 0ac047a..a7097fb 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -243,20 +243,23 @@
 template <typename TClientBase>
 binder::Status Camera2ClientBase<TClientBase>::disconnect() {
     ATRACE_CALL();
+    ALOGD("Camera %s: start to disconnect", TClientBase::mCameraIdStr.string());
     Mutex::Autolock icl(mBinderSerializationLock);
 
+    ALOGD("Camera %s: serializationLock acquired", TClientBase::mCameraIdStr.string());
     binder::Status res = binder::Status::ok();
     // Allow both client and the media server to disconnect at all times
     int callingPid = CameraThreadState::getCallingPid();
     if (callingPid != TClientBase::mClientPid &&
         callingPid != TClientBase::mServicePid) return res;
 
-    ALOGV("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
+    ALOGD("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
 
     // Before detaching the device, cache the info from current open session.
     // The disconnected check avoids duplication of info and also prevents
     // deadlock while acquiring service lock in cacheDump.
     if (!TClientBase::mDisconnected) {
+        ALOGD("Camera %s: start to cacheDump", TClientBase::mCameraIdStr.string());
         Camera2ClientBase::getCameraService()->cacheDump();
     }
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 4cc03f0..6edf1ac 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -40,7 +40,6 @@
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 #include <hwbinder/IPCThreadState.h>
-#include <utils/SessionConfigurationUtils.h>
 #include <utils/Trace.h>
 
 #include "api2/HeicCompositeStream.h"
@@ -338,14 +337,15 @@
 
 status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
         const SessionConfiguration &configuration, bool overrideForPerfClass,
-        bool *status /*out*/) const {
+        metadataGetter getMetadata, bool *status /*out*/) const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
     auto deviceInfo = findDeviceInfoLocked(id);
     if (deviceInfo == nullptr) {
         return NAME_NOT_FOUND;
     }
 
-    return deviceInfo->isSessionConfigurationSupported(configuration, overrideForPerfClass, status);
+    return deviceInfo->isSessionConfigurationSupported(configuration,
+            overrideForPerfClass, getMetadata, status);
 }
 
 status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
@@ -1243,6 +1243,34 @@
     return OK;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTags() {
+    status_t res = OK;
+    auto& c = mCameraCharacteristics;
+    auto flashInfoStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
+    if (flashInfoStrengthDefaultLevelEntry.count == 0) {
+        int32_t flashInfoStrengthDefaultLevel = 1;
+        res = c.update(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+                &flashInfoStrengthDefaultLevel, 1);
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+                    __FUNCTION__,strerror(-res), res);
+            return res;
+        }
+    }
+    auto flashInfoStrengthMaximumLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
+    if (flashInfoStrengthMaximumLevelEntry.count == 0) {
+        int32_t flashInfoStrengthMaximumLevel = 1;
+        res = c.update(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
+                &flashInfoStrengthMaximumLevel, 1);
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL: %s (%d)",
+                    __FUNCTION__,strerror(-res), res);
+            return res;
+        }
+    }
+    return res;
+}
+
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
     status_t res = OK;
     auto& c = mCameraCharacteristics;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 3d108bd..3a366e5 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -33,6 +33,7 @@
 #include <utils/Errors.h>
 #include <android/hardware/ICameraService.h>
 #include <utils/IPCTransport.h>
+#include <utils/SessionConfigurationUtils.h>
 #include <aidl/android/hardware/camera/provider/ICameraProvider.h>
 #include <android/hardware/camera/common/1.0/types.h>
 #include <android/hardware/camera/provider/2.5/ICameraProvider.h>
@@ -278,7 +279,7 @@
      */
     status_t isSessionConfigurationSupported(const std::string& id,
             const SessionConfiguration &configuration,
-            bool overrideForPerfClass,
+            bool overrideForPerfClass, camera3::metadataGetter getMetadata,
             bool *status /*out*/) const;
 
     /**
@@ -587,6 +588,7 @@
             virtual status_t isSessionConfigurationSupported(
                     const SessionConfiguration &/*configuration*/,
                     bool /*overrideForPerfClass*/,
+                    camera3::metadataGetter /*getMetadata*/,
                     bool * /*status*/) {
                 return INVALID_OPERATION;
             }
@@ -639,6 +641,7 @@
                     CameraMetadata *characteristics) const override;
             virtual status_t isSessionConfigurationSupported(
                     const SessionConfiguration &configuration, bool /*overrideForPerfClass*/,
+                    camera3::metadataGetter /*getMetadata*/,
                     bool *status /*out*/) = 0;
             virtual status_t filterSmallJpegSizes() override;
             virtual void notifyDeviceStateChange(
@@ -658,10 +661,13 @@
             // A copy of mCameraCharacteristics without performance class
             // override
             std::unique_ptr<CameraMetadata> mCameraCharNoPCOverride;
+            // Only contains characteristics for hidden physical cameras,
+            // not for public physical cameras.
             std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
             void queryPhysicalCameraIds();
             SystemCameraKind getSystemCameraKind();
             status_t fixupMonochromeTags();
+            status_t fixupTorchStrengthTags();
             status_t addDynamicDepthTags(bool maxResolution = false);
             status_t deriveHeicTags(bool maxResolution = false);
             status_t addRotateCropTags();
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 6f35e56..81b4779 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -538,6 +538,13 @@
     if (flashAvailable.count == 1 &&
             flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
         mHasFlashUnit = true;
+        // Fix up flash strength tags for devices without these keys.
+        res = fixupTorchStrengthTags();
+        if (OK != res) {
+            ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and"
+                    "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+        }
     } else {
         mHasFlashUnit = false;
     }
@@ -693,15 +700,11 @@
 }
 
 status_t AidlProviderInfo::AidlDeviceInfo3::isSessionConfigurationSupported(
-        const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+        const SessionConfiguration &configuration, bool overrideForPerfClass,
+        camera3::metadataGetter getMetadata, bool *status) {
 
     camera::device::StreamConfiguration streamConfiguration;
     bool earlyExit = false;
-    camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
-          CameraMetadata physicalChars;
-          getPhysicalCameraCharacteristics(id.c_str(), &physicalChars);
-          return physicalChars;
-    };
     auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
             String8(mId.c_str()), mCameraCharacteristics, getMetadata, mPhysicalIds,
             streamConfiguration, overrideForPerfClass, &earlyExit);
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
index aa71e85..97a8fed 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -129,7 +129,7 @@
 
         virtual status_t isSessionConfigurationSupported(
                 const SessionConfiguration &/*configuration*/,
-                bool overrideForPerfClass,
+                bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
                 bool *status/*status*/);
 
         std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 3c5ea75..7415e0f 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -662,6 +662,13 @@
     if (flashAvailable.count == 1 &&
             flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
         mHasFlashUnit = true;
+        // Fix up flash strength tags for devices without these keys.
+        res = fixupTorchStrengthTags();
+        if (OK != res) {
+            ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and"
+                    "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+        }
     } else {
         mHasFlashUnit = false;
     }
@@ -878,15 +885,11 @@
 }
 
 status_t HidlProviderInfo::HidlDeviceInfo3::isSessionConfigurationSupported(
-        const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+        const SessionConfiguration &configuration, bool overrideForPerfClass,
+        metadataGetter getMetadata, bool *status) {
 
     hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
     bool earlyExit = false;
-    camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
-          CameraMetadata physicalChars;
-          getPhysicalCameraCharacteristics(id.c_str(), &physicalChars);
-          return physicalChars;
-    };
     auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
             String8(mId.c_str()), mCameraCharacteristics, getMetadata, mPhysicalIds,
             streamConfiguration, overrideForPerfClass, &earlyExit);
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
index 4181fea..e0f1646 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -105,7 +105,7 @@
 
         virtual status_t isSessionConfigurationSupported(
                 const SessionConfiguration &/*configuration*/,
-                bool overrideForPerfClass,
+                bool overrideForPerfClass, camera3::metadataGetter getMetadata,
                 bool *status/*status*/);
         sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
     };
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 04e65d4..ecb60c6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -115,6 +115,10 @@
 
 status_t Camera3Device::initializeCommonLocked() {
 
+    /** Start watchdog thread */
+    mCameraServiceWatchdog = new CameraServiceWatchdog();
+    mCameraServiceWatchdog->run("CameraServiceWatchdog");
+
     /** Start up status tracker thread */
     mStatusTracker = new StatusTracker(this);
     status_t res = mStatusTracker->run(String8::format("C3Dev-%s-Status", mId.string()).string());
@@ -316,7 +320,7 @@
 
         // Call close without internal mutex held, as the HAL close may need to
         // wait on assorted callbacks,etc, to complete before it can return.
-        interface->close();
+        mCameraServiceWatchdog->WATCH(interface->close());
 
         flushInflightRequests();
 
@@ -339,6 +343,12 @@
         }
     }
     ALOGI("%s: X", __FUNCTION__);
+
+    if (mCameraServiceWatchdog != NULL) {
+        mCameraServiceWatchdog->requestExit();
+        mCameraServiceWatchdog.clear();
+    }
+
     return res;
 }
 
@@ -1549,13 +1559,22 @@
     }
 
     bool stateSeen = false;
+    nsecs_t startTime = systemTime();
     do {
         if (active == (mStatus == STATUS_ACTIVE)) {
             // Desired state is current
             break;
         }
 
-        res = mStatusChanged.waitRelative(mLock, timeout);
+        nsecs_t timeElapsed = systemTime() - startTime;
+        nsecs_t timeToWait = timeout - timeElapsed;
+        if (timeToWait <= 0) {
+            // Thread woke up spuriously but has timed out since.
+            // Force out of loop with TIMED_OUT result.
+            res = TIMED_OUT;
+            break;
+        }
+        res = mStatusChanged.waitRelative(mLock, timeToWait);
         if (res != OK) break;
 
         // This is impossible, but if not, could result in subtle deadlocks and invalid state
@@ -1719,7 +1738,12 @@
         mSessionStatsBuilder.stopCounter();
     }
 
-    return mRequestThread->flush();
+    // Calculate expected duration for flush with additional buffer time in ms for watchdog
+    uint64_t maxExpectedDuration = (getExpectedInFlightDuration() + kBaseGetBufferWait) / 1e6;
+    status_t res = mCameraServiceWatchdog->WATCH_CUSTOM_TIMER(mRequestThread->flush(),
+            maxExpectedDuration / kCycleLengthMs, kCycleLengthMs);
+
+    return res;
 }
 
 status_t Camera3Device::prepare(int streamId) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 749b342..748d063 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -32,6 +32,7 @@
 #include <camera/CaptureResult.h>
 
 #include "android/hardware/camera/metadata/3.8/types.h"
+#include "CameraServiceWatchdog.h"
 #include "common/CameraDeviceBase.h"
 #include "device3/BufferUtils.h"
 #include "device3/StatusTracker.h"
@@ -98,6 +99,9 @@
 
     metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
 
+    // Watchdog thread
+    sp<CameraServiceWatchdog> mCameraServiceWatchdog;
+
     // Transitions to idle state on success.
     virtual status_t initialize(sp<CameraProviderManager> /*manager*/,
             const String8& /*monitorTags*/) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 37f9227..c5bdd00 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -376,24 +376,35 @@
             dumpImageToDisk(timestamp, anwBuffer, anwReleaseFence);
         }
 
-        nsecs_t captureTime = (mSyncToDisplay ? readoutTimestamp : timestamp) - mTimestampOffset;
-        nsecs_t presentTime = mSyncToDisplay ?
-                syncTimestampToDisplayLocked(captureTime) : captureTime;
+        if (mPreviewFrameSpacer != nullptr) {
+            res = mPreviewFrameSpacer->queuePreviewBuffer(timestamp - mTimestampOffset, transform,
+                    anwBuffer, anwReleaseFence);
+            if (res != OK) {
+                ALOGE("%s: Stream %d: Error queuing buffer to preview buffer spacer: %s (%d)",
+                        __FUNCTION__, mId, strerror(-res), res);
+                return res;
+            }
+        } else {
+            nsecs_t captureTime = (mSyncToDisplay ? readoutTimestamp : timestamp)
+                    - mTimestampOffset;
+            nsecs_t presentTime = mSyncToDisplay ?
+                    syncTimestampToDisplayLocked(captureTime) : captureTime;
 
-        setTransform(transform, true/*mayChangeMirror*/);
-        res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
-        if (res != OK) {
-            ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
-                  __FUNCTION__, mId, strerror(-res), res);
-            return res;
-        }
+            setTransform(transform, true/*mayChangeMirror*/);
+            res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
+            if (res != OK) {
+                ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
+                      __FUNCTION__, mId, strerror(-res), res);
+                return res;
+            }
 
-        queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+            queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
 
-        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
-        if (shouldLogError(res, state)) {
-            ALOGE("%s: Stream %d: Error queueing buffer to native window:"
-                  " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+            res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
+            if (shouldLogError(res, state)) {
+                ALOGE("%s: Stream %d: Error queueing buffer to native window:"
+                      " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+            }
         }
     }
     mLock.lock();
@@ -468,7 +479,7 @@
         return res;
     }
 
-    if ((res = configureConsumerQueueLocked(true /*allowDisplaySync*/)) != OK) {
+    if ((res = configureConsumerQueueLocked(true /*allowPreviewRespace*/)) != OK) {
         return res;
     }
 
@@ -492,7 +503,7 @@
     return OK;
 }
 
-status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowDisplaySync) {
+status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowPreviewRespace) {
     status_t res;
 
     mTraceFirstBuffer = true;
@@ -582,20 +593,25 @@
     int timestampBase = getTimestampBase();
     bool isDefaultTimeBase = (timestampBase ==
             OutputConfiguration::TIMESTAMP_BASE_DEFAULT);
-    if (allowDisplaySync)  {
-        // We cannot distinguish between a SurfaceView and an ImageReader of
-        // preview buffer format. Frames are synchronized to display in both
-        // cases.
+    if (allowPreviewRespace)  {
         bool forceChoreographer = (timestampBase ==
                 OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
-        bool defaultToChoreographer = (isDefaultTimeBase && isConsumedByHWComposer() &&
+        bool defaultToChoreographer = (isDefaultTimeBase &&
+                isConsumedByHWComposer() &&
                 !property_get_bool("camera.disable_preview_scheduler", false));
         if (forceChoreographer || defaultToChoreographer) {
             mSyncToDisplay = true;
             mTotalBufferCount += kDisplaySyncExtraBuffer;
+        } else if (isConsumedByHWTexture() && !isVideoStream()) {
+            mPreviewFrameSpacer = new PreviewFrameSpacer(*this, mConsumer);
+            mTotalBufferCount ++;
+            res = mPreviewFrameSpacer->run(String8::format("PreviewSpacer-%d", mId).string());
+            if (res != OK) {
+                ALOGE("%s: Unable to start preview spacer", __FUNCTION__);
+                return res;
+            }
         }
     }
-
     mHandoutTotalBufferCount = 0;
     mFrameCount = 0;
     mLastTimestamp = 0;
@@ -1316,6 +1332,11 @@
     return expectedPresentT - vsyncEventData.frameInterval/3;
 }
 
+bool Camera3OutputStream::shouldLogError(status_t res) {
+    Mutex::Autolock l(mLock);
+    return shouldLogError(res, mState);
+}
+
 }; // namespace camera3
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 6ea7ef7..e68bc67 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -28,6 +28,7 @@
 #include "Camera3IOStreamBase.h"
 #include "Camera3OutputStreamInterface.h"
 #include "Camera3BufferManager.h"
+#include "PreviewFrameSpacer.h"
 
 namespace android {
 
@@ -250,6 +251,7 @@
     static void applyZSLUsageQuirk(int format, uint64_t *consumerUsage /*inout*/);
 
     void setImageDumpMask(int mask) { mImageDumpMask = mask; }
+    bool shouldLogError(status_t res);
 
   protected:
     Camera3OutputStream(int id, camera_stream_type_t type,
@@ -282,7 +284,7 @@
 
     status_t getEndpointUsageForSurface(uint64_t *usage,
             const sp<Surface>& surface) const;
-    status_t configureConsumerQueueLocked(bool allowDisplaySync);
+    status_t configureConsumerQueueLocked(bool allowPreviewRespace);
 
     // Consumer as the output of camera HAL
     sp<Surface> mConsumer;
@@ -396,15 +398,14 @@
 
     void returnPrefetchedBuffersLocked();
 
-    // Synchronize camera timestamp to display, and the return value
-    // can be used as presentation timestamp
-    nsecs_t syncTimestampToDisplayLocked(nsecs_t t);
 
     static const int32_t kDequeueLatencyBinSize = 5; // in ms
     CameraLatencyHistogram mDequeueBufferLatency;
 
     int mImageDumpMask = 0;
 
+    // Re-space frames by overriding timestamp to align with display Vsync.
+    // Default is on for SurfaceView bound streams.
     nsecs_t mMinExpectedDuration = 0;
     bool mSyncToDisplay = false;
     DisplayEventReceiver mDisplayEventReceiver;
@@ -414,6 +415,12 @@
     static constexpr size_t kDisplaySyncExtraBuffer = 2;
     static constexpr nsecs_t kSpacingResetIntervalNs = 1000000000LL; // 1 second
     static constexpr nsecs_t kTimelineThresholdNs = 1000000LL; // 1 millisecond
+    nsecs_t syncTimestampToDisplayLocked(nsecs_t t);
+
+    // Re-space frames by delaying queueBuffer so that frame delivery has
+    // the same cadence as capture. Default is on for SurfaceTexture bound
+    // streams.
+    sp<PreviewFrameSpacer> mPreviewFrameSpacer;
 }; // class Camera3OutputStream
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index d24b527..82958a2 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -251,7 +251,7 @@
         return res;
     }
 
-    res = configureConsumerQueueLocked(false/*allowDisplaySync*/);
+    res = configureConsumerQueueLocked(false/*allowPreviewRespace*/);
     if (res != OK) {
         ALOGE("Failed to configureConsumerQueueLocked: %s(%d)", strerror(-res), res);
         return res;
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
new file mode 100644
index 0000000..9112b93
--- /dev/null
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera3-PreviewFrameSpacer"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "PreviewFrameSpacer.h"
+#include "Camera3OutputStream.h"
+
+namespace android {
+
+namespace camera3 {
+
+PreviewFrameSpacer::PreviewFrameSpacer(Camera3OutputStream& parent, sp<Surface> consumer) :
+        mParent(parent),
+        mConsumer(consumer) {
+}
+
+PreviewFrameSpacer::~PreviewFrameSpacer() {
+    Thread::requestExitAndWait();
+}
+
+status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
+        ANativeWindowBuffer* anwBuffer, int releaseFence) {
+    Mutex::Autolock l(mLock);
+    mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
+    ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64, __FUNCTION__,
+            mPendingBuffers.size(), timestamp);
+
+    mBufferCond.signal();
+    return OK;
+}
+
+bool PreviewFrameSpacer::threadLoop() {
+    Mutex::Autolock l(mLock);
+    if (mPendingBuffers.size() == 0) {
+        mBufferCond.waitRelative(mLock, kWaitDuration);
+        return true;
+    }
+
+    nsecs_t currentTime = systemTime();
+    auto buffer = mPendingBuffers.front();
+    nsecs_t captureInterval = buffer.timestamp - mLastCameraCaptureTime;
+    // If the capture interval exceeds threshold, directly queue
+    // cached buffer.
+    if (captureInterval >= kFrameIntervalThreshold) {
+        mPendingBuffers.pop();
+        queueBufferToClientLocked(buffer, currentTime);
+        return true;
+    }
+
+    // Cache the frame to match capture time interval, for up to 33ms
+    nsecs_t expectedQueueTime = mLastCameraPresentTime + captureInterval;
+    nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
+    if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
+        mBufferCond.waitRelative(mLock, frameWaitTime);
+        if (exitPending()) {
+            return true;
+        }
+        currentTime = systemTime();
+    }
+    ALOGV("%s: captureInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
+            ", timestamp %" PRId64, __FUNCTION__, captureInterval,
+            currentTime - mLastCameraPresentTime, frameWaitTime, buffer.timestamp);
+    mPendingBuffers.pop();
+    queueBufferToClientLocked(buffer, currentTime);
+    return true;
+}
+
+void PreviewFrameSpacer::requestExit() {
+    // Call parent to set up shutdown
+    Thread::requestExit();
+    // Exit from other possible wait
+    mBufferCond.signal();
+}
+
+void PreviewFrameSpacer::queueBufferToClientLocked(
+        const BufferHolder& bufferHolder, nsecs_t currentTime) {
+    mParent.setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
+
+    status_t res = native_window_set_buffers_timestamp(mConsumer.get(), bufferHolder.timestamp);
+    if (res != OK) {
+        ALOGE("%s: Preview Stream: Error setting timestamp: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+    }
+
+    Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
+            mParent.getDynamicRangeProfile());
+
+    res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
+            bufferHolder.releaseFence);
+    if (res != OK) {
+        close(bufferHolder.releaseFence);
+        if (mParent.shouldLogError(res)) {
+            ALOGE("%s: Failed to queue buffer to client: %s(%d)", __FUNCTION__,
+                    strerror(-res), res);
+        }
+    }
+
+    mLastCameraPresentTime = currentTime;
+    mLastCameraCaptureTime = bufferHolder.timestamp;
+}
+
+}; // namespace camera3
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
new file mode 100644
index 0000000..5062553
--- /dev/null
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA3_PREVIEWFRAMESPACER_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_PREVIEWFRAMESPACER_H
+
+#include <queue>
+
+#include <gui/Surface.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3OutputStream;
+
+/***
+ * Preview stream spacer for better frame spacing
+ *
+ * The ideal viewfinder user experience is that frames are presented to the
+ * user in the same cadence as outputed by the camera sensor. However, the
+ * processing latency between frames could vary, due to factors such
+ * as CPU load, differences in request settings, etc. This frame processing
+ * latency results in variation in presentation of frames to the user.
+ *
+ * The PreviewFrameSpacer improves the viewfinder user experience by:
+ * - Cache the frame buffers if the intervals between queueBuffer is shorter
+ *   than the camera capture intervals.
+ * - Queue frame buffers in the same cadence as the camera capture time.
+ * - Maintain at most 1 queue-able buffer. If the 2nd preview buffer becomes
+ *   available, queue the oldest cached buffer to the buffer queue.
+ */
+class PreviewFrameSpacer : public Thread {
+  public:
+    explicit PreviewFrameSpacer(Camera3OutputStream& parent, sp<Surface> consumer);
+    virtual ~PreviewFrameSpacer();
+
+    // Queue preview buffer locally
+    status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
+            ANativeWindowBuffer* anwBuffer, int releaseFence);
+
+    bool threadLoop() override;
+    void requestExit() override;
+
+  private:
+    // structure holding cached preview buffer info
+    struct BufferHolder {
+        nsecs_t timestamp;
+        int32_t transform;
+        sp<ANativeWindowBuffer> anwBuffer;
+        int releaseFence;
+
+        BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
+                timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
+    };
+
+    void queueBufferToClientLocked(const BufferHolder& bufferHolder, nsecs_t currentTime);
+
+
+    Camera3OutputStream& mParent;
+    sp<ANativeWindow> mConsumer;
+    mutable Mutex mLock;
+    Condition mBufferCond;
+
+    std::queue<BufferHolder> mPendingBuffers;
+    nsecs_t mLastCameraCaptureTime = 0;
+    nsecs_t mLastCameraPresentTime = 0;
+    static constexpr nsecs_t kWaitDuration = 5000000LL; // 50ms
+    static constexpr nsecs_t kFrameIntervalThreshold = 80000000LL; // 80ms
+    static constexpr nsecs_t kMaxFrameWaitTime = 33333333LL; // 33ms
+};
+
+}; //namespace camera3
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index a00b221..f7cede8 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -260,4 +260,16 @@
     sessionStats->onClose(latencyMs);
 }
 
+bool CameraServiceProxyWrapper::isCameraDisabled() {
+    sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+    if (proxyBinder == nullptr) return true;
+    bool ret = false;
+    auto status = proxyBinder->isCameraDisabled(&ret);
+    if (!status.isOk()) {
+        ALOGE("%s: Failed during camera disabled query: %s", __FUNCTION__,
+                status.exceptionMessage().c_str());
+    }
+    return ret;
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index 6604aa1..61fc915 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -95,6 +95,9 @@
 
     // Return the current top activity rotate and crop override.
     static int getRotateAndCropOverride(String16 packageName, int lensFacing, int userId);
+
+    // Detect if the camera is disabled by device policy.
+    static bool isCameraDisabled();
 };
 
 } // android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 4090dae..a46266e 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -322,6 +322,10 @@
             streamUseCase == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
         return true;
     }
+    // Allow vendor stream use case unconditionally.
+    if (streamUseCase >= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
+        return true;
+    }
 
     for (size_t i = 0; i < availableStreamUseCases.count; i++) {
         if (availableStreamUseCases.data.i64[i] == streamUseCase) {
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 8abcc95..038c075 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -48,7 +48,7 @@
 namespace android {
 namespace camera3 {
 
-typedef std::function<CameraMetadata (const String8 &, int targetSdkVersion)> metadataGetter;
+typedef std::function<CameraMetadata (const String8 &, bool overrideForPerfClass)> metadataGetter;
 
 class StreamConfiguration {
 public:
diff --git a/services/mediametrics/AudioTypes.cpp b/services/mediametrics/AudioTypes.cpp
index 594809c..6e24a58 100644
--- a/services/mediametrics/AudioTypes.cpp
+++ b/services/mediametrics/AudioTypes.cpp
@@ -128,6 +128,9 @@
         {"AUDIO_DEVICE_OUT_BLE_HEADSET",               1LL << 31},
         {"AUDIO_DEVICE_OUT_BLE_SPEAKER",               1LL << 32},
         {"AUDIO_DEVICE_OUT_HDMI_EARC",                 1LL << 33},
+        // S values above
+        {"AUDIO_DEVICE_OUT_BLE_BROADCAST",             1LL << 34},
+        // T values above
     };
     return map;
 }
@@ -145,6 +148,8 @@
         {"MMAP_PLAYBACK", 5},          // Thread class for MMAP playback stream
         {"MMAP_CAPTURE",  6},          // Thread class for MMAP capture stream
         // R values above.
+        {"SPATIALIZER",   7},          // Thread class for SpatializerThread
+        // S values above.
     };
     return map;
 }
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index e0584df..b4610bc 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -732,6 +732,7 @@
         return true;
     }
 
+    int failedClientPid = -1;
     {
         Mutex::Autolock lock(mLock);
         bool found = false;
@@ -746,11 +747,14 @@
                 }
             }
             if (found) {
+                failedClientPid = mMap.keyAt(i);
                 break;
             }
         }
-        if (!found) {
-            ALOGV("didn't find failed client");
+        if (found) {
+            ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid);
+        } else {
+            ALOGW("Failed to reclaim resources from unlocateable client");
         }
     }
 
diff --git a/services/tuner/hidl/TunerHidlFilter.cpp b/services/tuner/hidl/TunerHidlFilter.cpp
index 6d8ae03..fe74a5c 100644
--- a/services/tuner/hidl/TunerHidlFilter.cpp
+++ b/services/tuner/hidl/TunerHidlFilter.cpp
@@ -390,7 +390,9 @@
                 static_cast<int32_t>(Result::INVALID_STATE));
     }
 
-    HidlResult res = mFilter->releaseAvHandle(hidl_handle(makeFromAidl(in_handle)), in_avDataId);
+    hidl_handle handle;
+    handle.setTo(makeFromAidl(in_handle), true);
+    HidlResult res = mFilter->releaseAvHandle(handle, in_avDataId);
     if (res != HidlResult::SUCCESS) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
     }