MediaPlayer2: create MP2AudioOutput in constructor

Move MP2AudioOutput creator from setDataSource() to constructor.
Test: MediaPlayer2Test, RoutingTest

Change-Id: Ibe19c8a259c735ea2b5822f769babaf4d7f2bed0
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 297d11b..cb474f4 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3524,6 +3524,8 @@
      * <p>Some devices may choose to provide a second set of calibration
      * information for improved quality, including
      * ACAMERA_SENSOR_REFERENCE_ILLUMINANT2 and its corresponding matrices.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_CALIBRATION_TRANSFORM1
      * @see ACAMERA_SENSOR_COLOR_TRANSFORM1
@@ -3553,6 +3555,8 @@
      * <p>If this key is present, then ACAMERA_SENSOR_COLOR_TRANSFORM2,
      * ACAMERA_SENSOR_CALIBRATION_TRANSFORM2, and
      * ACAMERA_SENSOR_FORWARD_MATRIX2 will also be present.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_CALIBRATION_TRANSFORM2
      * @see ACAMERA_SENSOR_COLOR_TRANSFORM2
@@ -3580,6 +3584,8 @@
      * colorspace) into this camera device's native sensor color
      * space under the first reference illuminant
      * (ACAMERA_SENSOR_REFERENCE_ILLUMINANT1).</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -3607,6 +3613,8 @@
      * (ACAMERA_SENSOR_REFERENCE_ILLUMINANT2).</p>
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -3635,6 +3643,8 @@
      * and the CIE XYZ colorspace when calculating this transform will
      * match the standard white point for the first reference illuminant
      * (i.e. no chromatic adaptation will be applied by this transform).</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -3665,6 +3675,8 @@
      * (i.e. no chromatic adaptation will be applied by this transform).</p>
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -3691,6 +3703,8 @@
      * this matrix is chosen so that the standard white point for this reference
      * illuminant in the reference sensor colorspace is mapped to D50 in the
      * CIE XYZ colorspace.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -3719,6 +3733,8 @@
      * CIE XYZ colorspace.</p>
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      *
      * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -3751,6 +3767,7 @@
      * level values. For raw capture in particular, it is recommended to use
      * pixels from ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS to calculate black
      * level values for each frame.</p>
+     * <p>For a MONOCHROME camera device, all of the 2x2 channels must have the same values.</p>
      *
      * @see ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL
      * @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
@@ -3845,6 +3862,8 @@
      * used to interpolate between the provided color transforms when
      * processing raw sensor data.</p>
      * <p>The order of the values is R, G, B; where R is in the lowest index.</p>
+     * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+     * the camera device has RAW capability.</p>
      */
     ACAMERA_SENSOR_NEUTRAL_COLOR_POINT =                        // rational[3]
             ACAMERA_SENSOR_START + 18,
@@ -3875,6 +3894,8 @@
      * 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>
+     * <p>For a MONOCHROME camera, there is only one color channel. So the noise model coefficients
+     * will only contain one S and one O.</p>
      *
      * @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
      */
@@ -3920,6 +3941,8 @@
      * <li>R &gt; 1.20 will require strong software correction to produce
      * a usuable 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>
      */
     ACAMERA_SENSOR_GREEN_SPLIT =                                // float
             ACAMERA_SENSOR_START + 22,
@@ -4072,6 +4095,7 @@
      * layout key (see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT), i.e. the
      * nth value given corresponds to the black level offset for the nth
      * color channel listed in the CFA.</p>
+     * <p>For a MONOCHROME camera, all of the 2x2 channels must have the same values.</p>
      * <p>This key will be available if ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS is available or the
      * camera device advertises this key via {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS }.</p>
      *
@@ -4174,7 +4198,8 @@
     /**
      * <p>The arrangement of color filters on sensor;
      * represents the colors in the top-left 2x2 section of
-     * the sensor, in reading order.</p>
+     * the sensor, in reading order, for a Bayer camera, or the
+     * light spectrum it captures for MONOCHROME camera.</p>
      *
      * <p>Type: byte (acamera_metadata_enum_android_sensor_info_color_filter_arrangement_t)</p>
      *
@@ -4643,13 +4668,13 @@
      * (x,y) ϵ (0 ... N-1, 0 ... M-1) is the value of the shading map at
      * pixel ( ((W-1)/(N-1)) * x, ((H-1)/(M-1)) * y) for the four color channels.
      * The map is assumed to be bilinearly interpolated between the sample points.</p>
-     * <p>The channel order is [R, Geven, Godd, B], where Geven is the green
-     * channel for the even rows of a Bayer pattern, and Godd is the odd rows.
+     * <p>For a Bayer camera, the channel order is [R, Geven, Godd, B], where Geven is
+     * the green channel for the even rows of a Bayer pattern, and Godd is the odd rows.
      * The shading map is stored in a fully interleaved format, and its size
      * is provided in the camera static metadata by ACAMERA_LENS_INFO_SHADING_MAP_SIZE.</p>
      * <p>The shading map will generally have on the order of 30-40 rows and columns,
      * and will be smaller than 64x64.</p>
-     * <p>As an example, given a very small map defined as:</p>
+     * <p>As an example, given a very small map for a Bayer camera defined as:</p>
      * <pre><code>ACAMERA_LENS_INFO_SHADING_MAP_SIZE = [ 4, 3 ]
      * ACAMERA_STATISTICS_LENS_SHADING_MAP =
      * [ 1.3, 1.2, 1.15, 1.2,  1.2, 1.2, 1.15, 1.2,
@@ -4669,6 +4694,17 @@
      * image of a gray wall (using bicubic interpolation for visual quality)
      * as captured by the sensor gives:</p>
      * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+     * <p>For a MONOCHROME camera, all of the 2x2 channels must have the same values. An example
+     * shading map for such a camera is defined as:</p>
+     * <pre><code>ACAMERA_LENS_INFO_SHADING_MAP_SIZE = [ 4, 3 ]
+     * ACAMERA_STATISTICS_LENS_SHADING_MAP =
+     * [ 1.3, 1.3, 1.3, 1.3,  1.2, 1.2, 1.2, 1.2,
+     *     1.1, 1.1, 1.1, 1.1,  1.3, 1.3, 1.3, 1.3,
+     *   1.2, 1.2, 1.2, 1.2,  1.1, 1.1, 1.1, 1.1,
+     *     1.0, 1.0, 1.0, 1.0,  1.2, 1.2, 1.2, 1.2,
+     *   1.3, 1.3, 1.3, 1.3,   1.2, 1.2, 1.2, 1.2,
+     *     1.2, 1.2, 1.2, 1.2,  1.3, 1.3, 1.3, 1.3 ]
+     * </code></pre>
      * <p>Note that the RAW image data might be subject to lens shading
      * correction not reported on this map. Query
      * ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED to see if RAW image data has subject
@@ -5012,8 +5048,8 @@
      * of points can be less than max (that is, the request doesn't have to
      * always provide a curve with number of points equivalent to
      * ACAMERA_TONEMAP_MAX_CURVE_POINTS).</p>
-     * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
-     * are ignored.</p>
+     * <p>For devices with MONOCHROME capability, all three channels must have the same set of
+     * control points.</p>
      * <p>A few examples, and their corresponding graphical mappings; these
      * only specify the red channel and the precision is limited to 4
      * digits, for conciseness.</p>
@@ -7373,11 +7409,15 @@
 
     /**
      * <p>The camera device is a monochrome camera that doesn't contain a color filter array,
-     * and the pixel values on U and V planes are all 128.</p>
+     * and for YUV_420_888 stream, the pixel values on U and V planes are all 128.</p>
      * <p>A MONOCHROME camera must support the guaranteed stream combinations required for
      * its device level and capabilities. Additionally, if the monochrome camera device
      * supports Y8 format, all mandatory stream combination requirements related to {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888} apply
-     * to {@link AIMAGE_FORMAT_Y8 Y8} as well.</p>
+     * to {@link AIMAGE_FORMAT_Y8 Y8} as well. There are no
+     * mandatory stream combination requirements with regard to
+     * {@link AIMAGE_FORMAT_Y8 Y8} for Bayer camera devices.</p>
+     * <p>Starting from Android Q, the SENSOR_INFO_COLOR_FILTER_ARRANGEMENT of a MONOCHROME
+     * camera will be either MONO or NIR.</p>
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME                = 12,
 
@@ -7643,6 +7683,21 @@
      */
     ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB                 = 4,
 
+    /**
+     * <p>Sensor doesn't have any Bayer color filter.
+     * Such sensor captures visible light in monochrome. The exact weighting and
+     * wavelengths captured is not specified, but generally only includes the visible
+     * frequencies. This value implies a MONOCHROME camera.</p>
+     */
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO                = 5,
+
+    /**
+     * <p>Sensor has a near infrared filter capturing light with wavelength between
+     * roughly 750nm and 1400nm, and the same filter covers the whole sensor array. This
+     * value implies a MONOCHROME camera.</p>
+     */
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR                 = 6,
+
 } acamera_metadata_enum_android_sensor_info_color_filter_arrangement_t;
 
 // ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 4991e50..94f9e02 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -32,6 +32,7 @@
         "libutils",
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
         "libhidlallocatorutils",
         "libhidlbase",
         "libhidltransport",
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index ce9dc38..14ff493 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -23,7 +23,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
-#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.2/types.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 
@@ -43,12 +43,13 @@
 using drm::V1_0::KeyStatusType;
 using drm::V1_0::KeyType;
 using drm::V1_0::KeyValue;
-using drm::V1_1::HdcpLevel;;
 using drm::V1_0::SecureStop;
-using drm::V1_1::SecureStopRelease;
 using drm::V1_0::SecureStopId;
-using drm::V1_1::SecurityLevel;
 using drm::V1_0::Status;
+using drm::V1_1::HdcpLevel;
+using drm::V1_1::SecureStopRelease;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeySetId;
 using ::android::hardware::drm::V1_1::DrmMetricGroup;
 using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_string;
@@ -139,6 +140,18 @@
     }
 }
 
+static DrmPlugin::OfflineLicenseState toOfflineLicenseState(
+        OfflineLicenseState licenseState) {
+    switch(licenseState) {
+    case OfflineLicenseState::USABLE:
+        return DrmPlugin::kOfflineLicenseStateUsable;
+    case OfflineLicenseState::INACTIVE:
+        return DrmPlugin::kOfflineLicenseStateInactive;
+    default:
+        return DrmPlugin::kOfflineLicenseStateUnknown;
+    }
+}
+
 static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel level) {
     switch(level) {
     case HdcpLevel::HDCP_NONE:
@@ -199,6 +212,15 @@
     return secureStopIds;
 }
 
+static List<Vector<uint8_t>> toKeySetIds(const hidl_vec<KeySetId>&
+        hKeySetIds) {
+    List<Vector<uint8_t>> keySetIds;
+    for (size_t i = 0; i < hKeySetIds.size(); i++) {
+        keySetIds.push_back(toVector(hKeySetIds[i]));
+    }
+    return keySetIds;
+}
+
 static status_t toStatusT(Status status) {
     switch (status) {
     case Status::OK:
@@ -305,6 +327,7 @@
     }
     mPlugin.clear();
     mPluginV1_1.clear();
+    mPluginV1_2.clear();
 }
 
 Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
@@ -333,6 +356,16 @@
                     }
                 }
             );
+        manager->listByInterface(drm::V1_2::IDrmFactory::descriptor,
+                [&factories](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        auto factory = drm::V1_2::IDrmFactory::getService(instance);
+                        if (factory != NULL) {
+                            factories.push_back(factory);
+                        }
+                    }
+                }
+            );
     }
 
     if (factories.size() == 0) {
@@ -525,6 +558,7 @@
             mPlugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
             if (mPlugin != NULL) {
                 mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
+                mPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mPlugin);
             }
         }
     }
@@ -1063,6 +1097,73 @@
     return hResult.isOk() ? err : DEAD_OBJECT;
 }
 
+status_t DrmHal::getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPluginV1_2 == NULL) {
+        return ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPluginV1_2->getOfflineLicenseKeySetIds(
+            [&](Status status, const hidl_vec<KeySetId>& hKeySetIds) {
+                if (status == Status::OK) {
+                    keySetIds = toKeySetIds(hKeySetIds);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::removeOfflineLicense(Vector<uint8_t> const &keySetId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPluginV1_2 == NULL) {
+        return ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
+    return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHal::getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+        DrmPlugin::OfflineLicenseState *licenseState) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPluginV1_2 == NULL) {
+        return ERROR_DRM_CANNOT_HANDLE;
+    }
+    *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPluginV1_2->getOfflineLicenseState(toHidlVec(keySetId),
+            [&](Status status, OfflineLicenseState hLicenseState) {
+                if (status == Status::OK) {
+                    *licenseState = toOfflineLicenseState(hLicenseState);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
 status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
     Mutex::Autolock autoLock(mLock);
     return getPropertyStringInternal(name, value);
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 509961f..8c26317 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -61,7 +61,10 @@
     GET_NUMBER_OF_SESSIONS,
     GET_SECURITY_LEVEL,
     REMOVE_SECURE_STOP,
-    GET_SECURE_STOP_IDS
+    GET_SECURE_STOP_IDS,
+    GET_OFFLINE_LICENSE_KEYSET_IDS,
+    REMOVE_OFFLINE_LICENSE,
+    GET_OFFLINE_LICENSE_STATE
 };
 
 struct BpDrm : public BpInterface<IDrm> {
@@ -376,6 +379,52 @@
         return reply.readInt32();
     }
 
+    virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t> > &keySetIds) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(GET_OFFLINE_LICENSE_KEYSET_IDS, data, &reply);
+        if (status != OK) {
+            return status;
+        }
+
+        keySetIds.clear();
+        uint32_t count = reply.readInt32();
+        for (size_t i = 0; i < count; i++) {
+            Vector<uint8_t> keySetId;
+            readVector(reply, keySetId);
+            keySetIds.push_back(keySetId);
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+        writeVector(data, keySetId);
+        status_t status = remote()->transact(REMOVE_OFFLINE_LICENSE, data, &reply);
+        if (status != OK) {
+            return status;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+            DrmPlugin::OfflineLicenseState *licenseState) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+        writeVector(data, keySetId);
+        status_t status = remote()->transact(GET_OFFLINE_LICENSE_STATE, data, &reply);
+        if (status != OK) {
+            *licenseState = DrmPlugin::OfflineLicenseState::kOfflineLicenseStateUnknown;
+            return status;
+        }
+        *licenseState = static_cast<DrmPlugin::OfflineLicenseState>(reply.readInt32());
+        return reply.readInt32();
+    }
+
     virtual status_t getPropertyString(String8 const &name, String8 &value) const {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -980,6 +1029,45 @@
             return OK;
         }
 
+        case GET_OFFLINE_LICENSE_KEYSET_IDS:
+        {
+            CHECK_INTERFACE(IDrm, data, reply);
+            List<Vector<uint8_t> > keySetIds;
+            status_t result = getOfflineLicenseKeySetIds(keySetIds);
+            size_t count = keySetIds.size();
+            reply->writeInt32(count);
+            List<Vector<uint8_t> >::iterator iter = keySetIds.begin();
+            while(iter != keySetIds.end()) {
+                size_t size = iter->size();
+                reply->writeInt32(size);
+                reply->write(iter->array(), iter->size());
+                iter++;
+            }
+            reply->writeInt32(result);
+            return OK;
+        }
+
+        case REMOVE_OFFLINE_LICENSE:
+        {
+            CHECK_INTERFACE(IDrm, data, reply);
+            Vector<uint8_t> keySetId;
+            readVector(data, keySetId);
+            reply->writeInt32(removeOfflineLicense(keySetId));
+            return OK;
+        }
+
+        case GET_OFFLINE_LICENSE_STATE:
+        {
+            CHECK_INTERFACE(IDrm, data, reply);
+            Vector<uint8_t> keySetId;
+            readVector(data, keySetId);
+            DrmPlugin::OfflineLicenseState state;
+            status_t result = getOfflineLicenseState(keySetId, &state);
+            reply->writeInt32(static_cast<DrmPlugin::OfflineLicenseState>(state));
+            reply->writeInt32(result);
+            return OK;
+        }
+
         case GET_PROPERTY_STRING:
         {
             CHECK_INTERFACE(IDrm, data, reply);
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index 66c906f..dcd59b7 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -17,6 +17,7 @@
     shared_libs: [
       "android.hardware.drm@1.0",
       "android.hardware.drm@1.1",
+      "android.hardware.drm@1.2",
       "libbinder",
       "libhidlbase",
       "liblog",
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h
index ea1aea6..c357caa 100644
--- a/include/soundtrigger/ISoundTrigger.h
+++ b/include/soundtrigger/ISoundTrigger.h
@@ -40,8 +40,7 @@
     virtual status_t startRecognition(sound_model_handle_t handle,
                                       const sp<IMemory>& dataMemory) = 0;
     virtual status_t stopRecognition(sound_model_handle_t handle) = 0;
-    virtual status_t getModelState(sound_model_handle_t handle,
-                                   sp<IMemory>& eventMemory) = 0;
+    virtual status_t getModelState(sound_model_handle_t handle) = 0;
 
 };
 
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index dcf9ce8..2e2ff7a 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -52,7 +52,7 @@
 
             status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory);
             status_t stopRecognition(sound_model_handle_t handle);
-            status_t getModelState(sound_model_handle_t handle, sp<IMemory>& eventMemory);
+            status_t getModelState(sound_model_handle_t handle);
 
             // BpSoundTriggerClient
             virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
index de8f120..8819f87 100644
--- a/media/img_utils/include/img_utils/DngUtils.h
+++ b/media/img_utils/include/img_utils/DngUtils.h
@@ -49,6 +49,7 @@
             CFA_RGGB,
             CFA_BGGR,
             CFA_GBRG,
+            CFA_NONE,
         };
 
         OpcodeListBuilder();
@@ -89,7 +90,6 @@
                                                 CfaLayout cfa,
                                                 const float* lensShadingMap);
 
-
         /**
          * Add a GainMap opcode with the given fields.  The mapGains array
          * must have mapPointsV * mapPointsH * mapPlanes elements.
@@ -197,6 +197,33 @@
 
         status_t addOpcodePreamble(uint32_t opcodeId);
 
+    private:
+        /**
+         * Add Bayer GainMap opcode(s) for the given metadata parameters.
+         * CFA layout must match the layout of the shading map passed into the
+         * lensShadingMap parameter.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        status_t addBayerGainMapsForMetadata(uint32_t lsmWidth,
+                                                uint32_t lsmHeight,
+                                                uint32_t activeAreaWidth,
+                                                uint32_t activeAreaHeight,
+                                                CfaLayout cfa,
+                                                const float* lensShadingMap);
+
+        /**
+         * Add Bayer GainMap opcode(s) for the given metadata parameters.
+         * CFA layout must match the layout of the shading map passed into the
+         * lensShadingMap parameter.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        status_t addMonochromeGainMapsForMetadata(uint32_t lsmWidth,
+                                                uint32_t lsmHeight,
+                                                uint32_t activeAreaWidth,
+                                                uint32_t activeAreaHeight,
+                                                const float* lensShadingMap);
 };
 
 } /*namespace img_utils*/
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index 9ac7e2a..9304f53 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -60,34 +60,36 @@
                                                    uint32_t activeAreaRight,
                                                    CfaLayout cfa,
                                                    const float* lensShadingMap) {
+    status_t err = OK;
     uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft;
     uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop;
-    double spacingV = 1.0 / std::max(1u, lsmHeight - 1);
-    double spacingH = 1.0 / std::max(1u, lsmWidth - 1);
 
-    std::vector<float> redMapVector(lsmWidth * lsmHeight);
-    float *redMap = redMapVector.data();
-
-    std::vector<float> greenEvenMapVector(lsmWidth * lsmHeight);
-    float *greenEvenMap = greenEvenMapVector.data();
-
-    std::vector<float> greenOddMapVector(lsmWidth * lsmHeight);
-    float *greenOddMap = greenOddMapVector.data();
-
-    std::vector<float> blueMapVector(lsmWidth * lsmHeight);
-    float *blueMap = blueMapVector.data();
-
-    size_t lsmMapSize = lsmWidth * lsmHeight * 4;
-
-    // Split lens shading map channels into separate arrays
-    size_t j = 0;
-    for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
-        redMap[j] = lensShadingMap[i + LSM_R_IND];
-        greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND];
-        greenOddMap[j] = lensShadingMap[i + LSM_GO_IND];
-        blueMap[j] = lensShadingMap[i + LSM_B_IND];
+    switch (cfa) {
+        case CFA_RGGB:
+        case CFA_GRBG:
+        case CFA_GBRG:
+        case CFA_BGGR:
+            err = addBayerGainMapsForMetadata(lsmWidth, lsmHeight, activeAreaWidth,
+                    activeAreaHeight, cfa, lensShadingMap);
+            break;
+        case CFA_NONE:
+            err = addMonochromeGainMapsForMetadata(lsmWidth, lsmHeight, activeAreaWidth,
+                    activeAreaHeight, lensShadingMap);
+            break;
+        default:
+            ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa);
+            err = BAD_VALUE;
+            break;
     }
+    return err;
+}
 
+status_t OpcodeListBuilder::addBayerGainMapsForMetadata(uint32_t lsmWidth,
+                                                   uint32_t lsmHeight,
+                                                   uint32_t activeAreaWidth,
+                                                   uint32_t activeAreaHeight,
+                                                   CfaLayout cfa,
+                                                   const float* lensShadingMap) {
     uint32_t redTop = 0;
     uint32_t redLeft = 0;
     uint32_t greenEvenTop = 0;
@@ -143,6 +145,32 @@
             return BAD_VALUE;
     }
 
+    std::vector<float> redMapVector(lsmWidth * lsmHeight);
+    float *redMap = redMapVector.data();
+
+    std::vector<float> greenEvenMapVector(lsmWidth * lsmHeight);
+    float *greenEvenMap = greenEvenMapVector.data();
+
+    std::vector<float> greenOddMapVector(lsmWidth * lsmHeight);
+    float *greenOddMap = greenOddMapVector.data();
+
+    std::vector<float> blueMapVector(lsmWidth * lsmHeight);
+    float *blueMap = blueMapVector.data();
+
+    double spacingV = 1.0 / std::max(1u, lsmHeight - 1);
+    double spacingH = 1.0 / std::max(1u, lsmWidth - 1);
+
+    size_t lsmMapSize = lsmWidth * lsmHeight * 4;
+
+    // Split lens shading map channels into separate arrays
+    size_t j = 0;
+    for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
+        redMap[j] = lensShadingMap[i + LSM_R_IND];
+        greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND];
+        greenOddMap[j] = lensShadingMap[i + LSM_GO_IND];
+        blueMap[j] = lensShadingMap[i + LSM_B_IND];
+    }
+
     status_t err = addGainMap(/*top*/redTop,
                               /*left*/redLeft,
                               /*bottom*/activeAreaHeight - 1,
@@ -216,6 +244,46 @@
     return err;
 }
 
+status_t OpcodeListBuilder::addMonochromeGainMapsForMetadata(uint32_t lsmWidth,
+                                                   uint32_t lsmHeight,
+                                                   uint32_t activeAreaWidth,
+                                                   uint32_t activeAreaHeight,
+                                                   const float* lensShadingMap) {
+    std::vector<float> mapVector(lsmWidth * lsmHeight);
+    float *map = mapVector.data();
+
+    double spacingV = 1.0 / std::max(1u, lsmHeight - 1);
+    double spacingH = 1.0 / std::max(1u, lsmWidth - 1);
+
+    size_t lsmMapSize = lsmWidth * lsmHeight * 4;
+
+    // Split lens shading map channels into separate arrays
+    size_t j = 0;
+    for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
+        map[j] = lensShadingMap[i];
+    }
+
+    status_t err = addGainMap(/*top*/0,
+                              /*left*/0,
+                              /*bottom*/activeAreaHeight - 1,
+                              /*right*/activeAreaWidth - 1,
+                              /*plane*/0,
+                              /*planes*/1,
+                              /*rowPitch*/1,
+                              /*colPitch*/1,
+                              /*mapPointsV*/lsmHeight,
+                              /*mapPointsH*/lsmWidth,
+                              /*mapSpacingV*/spacingV,
+                              /*mapSpacingH*/spacingH,
+                              /*mapOriginV*/0,
+                              /*mapOriginH*/0,
+                              /*mapPlanes*/1,
+                              /*mapGains*/map);
+    if (err != OK) return err;
+
+    return err;
+}
+
 status_t OpcodeListBuilder::addGainMap(uint32_t top,
                                        uint32_t left,
                                        uint32_t bottom,
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index f267f76..3302982 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -23,6 +23,8 @@
 #include <android/hardware/drm/1.0/IDrmPluginListener.h>
 #include <android/hardware/drm/1.1/IDrmFactory.h>
 #include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.2/IDrmPlugin.h>
 
 #include <media/MediaAnalyticsItem.h>
 #include <mediadrm/DrmMetrics.h>
@@ -36,6 +38,7 @@
 using drm::V1_0::IDrmPlugin;
 using drm::V1_0::IDrmPluginListener;
 using drm::V1_0::KeyStatus;
+using drm::V1_2::OfflineLicenseState;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
@@ -113,6 +116,11 @@
     virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
             DrmPlugin::SecurityLevel *level) const;
 
+    virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
+    virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
+    virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+            DrmPlugin::OfflineLicenseState *licenseState) const;
+
     virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
     virtual status_t getPropertyByteArray(String8 const &name,
                                           Vector<uint8_t> &value ) const;
@@ -182,6 +190,7 @@
     const Vector<sp<IDrmFactory>> mFactories;
     sp<IDrmPlugin> mPlugin;
     sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+    sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
     String8 mAppPackageName;
 
     // Mutable to allow modification within GetPropertyByteArray.
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index 8e9eb3a..49166c6 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -75,8 +75,8 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey) = 0;
 
-    virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
-    virtual status_t getSecureStopIds(List<Vector<uint8_t> > &secureStopIds) = 0;
+    virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops) = 0;
+    virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) = 0;
     virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0;
 
     virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
@@ -91,6 +91,11 @@
     virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
             DrmPlugin::SecurityLevel *level) const = 0;
 
+    virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const = 0;
+    virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId) = 0;
+    virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+            DrmPlugin::OfflineLicenseState *licenseState) const = 0;
+
     virtual status_t getPropertyString(String8 const &name, String8 &value) const = 0;
     virtual status_t getPropertyByteArray(String8 const &name,
                                           Vector<uint8_t> &value) const = 0;
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index f7e8a9d..3040c2d 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -60,7 +60,7 @@
 }
 
 MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-        const jobject attributes, std::vector<jobject>& routingDelegatesBackup)
+        const jobject attributes)
     : mCallback(nullptr),
       mCallbackCookie(nullptr),
       mCallbackData(nullptr),
@@ -77,20 +77,12 @@
       mFlags(AUDIO_OUTPUT_FLAG_NONE) {
     ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
 
-    if (mAttributes != nullptr) {
-        mAttributes->~JObjectHolder();
-    }
     if (attributes != nullptr) {
         mAttributes = new JObjectHolder(attributes);
     }
 
     setMinBufferCount();
     mRoutingDelegates.clear();
-    for (auto routingDelegate : routingDelegatesBackup) {
-        mRoutingDelegates.push_back(std::pair<jobject, jobject>(
-                JAudioTrack::getListener(routingDelegate), routingDelegate));
-    }
-    routingDelegatesBackup.clear();
 }
 
 MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
@@ -251,11 +243,8 @@
 
 void MediaPlayer2AudioOutput::setAudioAttributes(const jobject attributes) {
     Mutex::Autolock lock(mLock);
-    if (mAttributes != nullptr) {
-        mAttributes->~JObjectHolder();
-    }
     if (attributes != nullptr) {
-        mAttributes = new JObjectHolder(attributes);
+        sp<JObjectHolder> x = new JObjectHolder(attributes);
     }
 }
 
@@ -564,15 +553,6 @@
     return NO_ERROR;
 }
 
-void MediaPlayer2AudioOutput::copyAudioDeviceCallback(
-        std::vector<jobject>& routingDelegateTarget) {
-    ALOGV("copyAudioDeviceCallback");
-    for (std::vector<std::pair<jobject, jobject>>::iterator it = mRoutingDelegates.begin();
-            it != mRoutingDelegates.end(); it++) {
-        routingDelegateTarget.push_back(it->second);
-    }
-}
-
 // static
 void MediaPlayer2AudioOutput::CallbackWrapper(
         int event, void *cookie, void *info) {
@@ -650,6 +630,11 @@
     return mSessionId;
 }
 
+void MediaPlayer2AudioOutput::setSessionId(const audio_session_t id) {
+    Mutex::Autolock lock(mLock);
+    mSessionId = id;
+}
+
 uint32_t MediaPlayer2AudioOutput::getSampleRate() const {
     Mutex::Autolock lock(mLock);
     if (mJAudioTrack == 0) {
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index decd9f9..fc020ca 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -41,8 +41,7 @@
     MediaPlayer2AudioOutput(audio_session_t sessionId,
                             uid_t uid,
                             int pid,
-                            const jobject attributes,
-                            std::vector<jobject>& routingDelegatesBackup);
+                            const jobject attributes);
     virtual ~MediaPlayer2AudioOutput();
 
     virtual bool ready() const {
@@ -59,6 +58,7 @@
     virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
     virtual status_t getFramesWritten(uint32_t *frameswritten) const;
     virtual audio_session_t getSessionId() const;
+    virtual void setSessionId(const audio_session_t id);
     virtual uint32_t getSampleRate() const;
     virtual int64_t getBufferDurationInUs() const;
 
@@ -99,7 +99,6 @@
     virtual jobject getRoutedDevice();
     virtual status_t addAudioDeviceCallback(jobject routingDelegate);
     virtual status_t removeAudioDeviceCallback(jobject listener);
-    virtual void copyAudioDeviceCallback(std::vector<jobject>& routingDelegateTarget);
 
 private:
     static void setMinBufferCount();
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 0aaab7b..d881813 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -26,7 +26,6 @@
 #include <mediaplayer2/MediaPlayer2Types.h>
 #include <mediaplayer2/JObjectHolder.h>
 
-#include <vector>
 #include <jni.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
@@ -154,7 +153,6 @@
     audio_session_t             mAudioSessionId;
     sp<JObjectHolder>           mAudioAttributes;
     float                       mSendLevel;
-    std::vector<jobject>        mRoutingDelegates;
     sp<ANativeWindowWrapper>    mConnectedWindow;
 };
 
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 07442a1..04a6f68 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -258,6 +258,8 @@
     // TODO: get pid and uid from JAVA
     mPid = IPCThreadState::self()->getCallingPid();
     mUid = IPCThreadState::self()->getCallingUid();
+
+    mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid, mPid, NULL /*attributes*/);
 }
 
 MediaPlayer2::~MediaPlayer2() {
@@ -352,14 +354,7 @@
 
         clear_l();
 
-        if (mAudioOutput != NULL) {
-            mAudioOutput->copyAudioDeviceCallback(mRoutingDelegates);
-        }
-
         player->setListener(new proxyListener(this));
-        mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
-                mPid, mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL,
-                mRoutingDelegates);
         player->setAudioSink(mAudioOutput);
 
         err = player->setDataSource(dsd);
@@ -911,6 +906,9 @@
         AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
         mAudioSessionId = sessionId;
     }
+    if (mAudioOutput != NULL && mAudioSessionId != mAudioOutput->getSessionId()) {
+        mAudioOutput->setSessionId(sessionId);
+    }
     return NO_ERROR;
 }
 
@@ -1184,7 +1182,6 @@
     Mutex::Autolock _l(mLock);
     if (mAudioOutput == NULL) {
         ALOGV("addAudioDeviceCallback: player not init");
-        mRoutingDelegates.push_back(routingDelegate);
         return NO_INIT;
     }
     return mAudioOutput->addAudioDeviceCallback(routingDelegate);
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index e86b68a..4749a8b 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -11,6 +11,7 @@
         "libutils",
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
     ],
 
     compile_multilib: "32",
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 5eb5ba6..17507cd 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -407,7 +407,7 @@
             return;
         }
         mSpeed = speed;
-        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
+        if (mMediaPlayer != null && mMediaPlayer.getState() == MediaPlayer2.PLAYER_STATE_PLAYING) {
             applySpeed();
         }
         updatePlaybackState();
@@ -1341,7 +1341,7 @@
                 if (isRemotePlayback()) {
                     mRoutePlayer.onPause();
                     mCurrentState = STATE_PAUSED;
-                } else if (mMediaPlayer.isPlaying()) {
+                } else if (mMediaPlayer.getState() == MediaPlayer2.PLAYER_STATE_PLAYING) {
                     mMediaPlayer.pause();
                     mCurrentState = STATE_PAUSED;
                     updatePlaybackState();
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e69ce1f..d45be62 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -209,6 +209,14 @@
     proxyBinder->pingForUserUpdate();
 }
 
+void CameraService::broadcastTorchModeStatus(const String8& cameraId, TorchModeStatus status) {
+    Mutex::Autolock lock(mStatusListenerLock);
+
+    for (auto& i : mListenerList) {
+        i->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
+    }
+}
+
 CameraService::~CameraService() {
     VendorTagDescriptor::clearGlobalVendorTagDescriptor();
     mUidPolicy->unregisterSelf();
@@ -247,6 +255,8 @@
     if (mFlashlight->hasFlashUnit(id)) {
         Mutex::Autolock al(mTorchStatusMutex);
         mTorchStatusMap.add(id, TorchModeStatus::AVAILABLE_OFF);
+
+        broadcastTorchModeStatus(id, TorchModeStatus::AVAILABLE_OFF);
     }
 
     updateCameraNumAndIds();
@@ -399,12 +409,7 @@
         }
     }
 
-    {
-        Mutex::Autolock lock(mStatusListenerLock);
-        for (auto& i : mListenerList) {
-            i->onTorchStatusChanged(mapToInterface(newStatus), String16{cameraId});
-        }
-    }
+    broadcastTorchModeStatus(cameraId, newStatus);
 }
 
 Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 80d9ef4..064863f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -857,6 +857,8 @@
     static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
     static void pingCameraServiceProxy();
 
+    void broadcastTorchModeStatus(const String8& cameraId,
+            hardware::camera::common::V1_0::TorchModeStatus status);
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index a94e886..2542ab2 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -425,6 +425,102 @@
     }
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
+    status_t res = OK;
+    auto& c = mCameraCharacteristics;
+
+    // Override static metadata for MONOCHROME camera with older device version
+    if (mVersion.get_major() == 3 && mVersion.get_minor() < 5) {
+        camera_metadata_entry cap = c.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+        for (size_t i = 0; i < cap.count; i++) {
+            if (cap.data.u8[i] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+                // ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+                uint8_t cfa = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO;
+                res = c.update(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, &cfa, 1);
+                if (res != OK) {
+                    ALOGE("%s: Failed to update COLOR_FILTER_ARRANGEMENT: %s (%d)",
+                          __FUNCTION__, strerror(-res), res);
+                    return res;
+                }
+
+                // ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS
+                const std::vector<uint32_t> sKeys = {
+                        ANDROID_SENSOR_REFERENCE_ILLUMINANT1,
+                        ANDROID_SENSOR_REFERENCE_ILLUMINANT2,
+                        ANDROID_SENSOR_CALIBRATION_TRANSFORM1,
+                        ANDROID_SENSOR_CALIBRATION_TRANSFORM2,
+                        ANDROID_SENSOR_COLOR_TRANSFORM1,
+                        ANDROID_SENSOR_COLOR_TRANSFORM2,
+                        ANDROID_SENSOR_FORWARD_MATRIX1,
+                        ANDROID_SENSOR_FORWARD_MATRIX2,
+                };
+                res = removeAvailableKeys(c, sKeys,
+                        ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+                if (res != OK) {
+                    ALOGE("%s: Failed to update REQUEST_AVAILABLE_CHARACTERISTICS_KEYS: %s (%d)",
+                            __FUNCTION__, strerror(-res), res);
+                    return res;
+                }
+
+                // ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS
+                const std::vector<uint32_t> reqKeys = {
+                        ANDROID_COLOR_CORRECTION_MODE,
+                        ANDROID_COLOR_CORRECTION_TRANSFORM,
+                        ANDROID_COLOR_CORRECTION_GAINS,
+                };
+                res = removeAvailableKeys(c, reqKeys, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+                if (res != OK) {
+                    ALOGE("%s: Failed to update REQUEST_AVAILABLE_REQUEST_KEYS: %s (%d)",
+                            __FUNCTION__, strerror(-res), res);
+                    return res;
+                }
+
+                // ANDROID_REQUEST_AVAILABLE_RESULT_KEYS
+                const std::vector<uint32_t> resKeys = {
+                        ANDROID_SENSOR_GREEN_SPLIT,
+                        ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
+                        ANDROID_COLOR_CORRECTION_MODE,
+                        ANDROID_COLOR_CORRECTION_TRANSFORM,
+                        ANDROID_COLOR_CORRECTION_GAINS,
+                };
+                res = removeAvailableKeys(c, resKeys, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
+                if (res != OK) {
+                    ALOGE("%s: Failed to update REQUEST_AVAILABLE_RESULT_KEYS: %s (%d)",
+                            __FUNCTION__, strerror(-res), res);
+                    return res;
+                }
+
+                // ANDROID_SENSOR_BLACK_LEVEL_PATTERN
+                camera_metadata_entry blEntry = c.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+                for (size_t j = 1; j < blEntry.count; j++) {
+                    blEntry.data.i32[j] = blEntry.data.i32[0];
+                }
+            }
+        }
+    }
+    return res;
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::removeAvailableKeys(
+        CameraMetadata& c, const std::vector<uint32_t>& keys, uint32_t keyTag) {
+    status_t res = OK;
+
+    camera_metadata_entry keysEntry = c.find(keyTag);
+    if (keysEntry.count == 0) {
+        ALOGE("%s: Failed to find tag %u: %s (%d)", __FUNCTION__, keyTag, strerror(-res), res);
+        return res;
+    }
+    std::vector<int32_t> vKeys;
+    vKeys.reserve(keysEntry.count);
+    for (size_t i = 0; i < keysEntry.count; i++) {
+        if (std::find(keys.begin(), keys.end(), keysEntry.data.i32[i]) == keys.end()) {
+            vKeys.push_back(keysEntry.data.i32[i]);
+        }
+    }
+    res = c.update(keyTag, vKeys.data(), vKeys.size());
+    return res;
+}
+
 bool CameraProviderManager::isLogicalCamera(const std::string& id,
         std::vector<std::string>* physicalCameraIds) {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -1131,6 +1227,12 @@
                 __FUNCTION__, mId.c_str(), CameraProviderManager::statusToString(status), status);
         return;
     }
+    status_t res = fixupMonochromeTags();
+    if (OK != res) {
+        ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return;
+    }
     camera_metadata_entry flashAvailable =
             mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
     if (flashAvailable.count == 1 &&
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 9016747..c506d35 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -385,6 +385,9 @@
             CameraMetadata mCameraCharacteristics;
             std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
             void queryPhysicalCameraIds();
+            status_t fixupMonochromeTags();
+            status_t removeAvailableKeys(CameraMetadata& c, const std::vector<uint32_t>& keys,
+                    uint32_t keyTag);
         };
 
     private:
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 7d41256..58471b9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -79,7 +79,8 @@
         mNextReprocessShutterFrameNumber(0),
         mListener(NULL),
         mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID),
-        mLastTemplateId(-1)
+        mLastTemplateId(-1),
+        mNeedFixupMonochromeTags(false)
 {
     ATRACE_CALL();
     ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
@@ -188,6 +189,28 @@
         mTagMonitor.parseTagsToMonitor(String8(monitorTags));
     }
 
+    // Metadata tags needs fixup for monochrome camera device version less
+    // than 3.5.
+    hardware::hidl_version maxVersion{0,0};
+    res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
+    if (res != OK) {
+        ALOGE("%s: Error in getting camera device version id: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+    int deviceVersion = HARDWARE_DEVICE_API_VERSION(
+            maxVersion.get_major(), maxVersion.get_minor());
+
+    bool isMonochrome = false;
+    camera_metadata_entry_t entry = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    for (size_t i = 0; i < entry.count; i++) {
+        uint8_t capability = entry.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+            isMonochrome = true;
+        }
+    }
+    mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
+
     return initializeCommonLocked();
 }
 
@@ -224,6 +247,17 @@
             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
     }
 
+    if (mUseHalBufManager) {
+        res = mRequestBufferSM.initialize(mStatusTracker);
+        if (res != OK) {
+            SET_ERR_L("Unable to start request buffer state machine: %s (%d)",
+                    strerror(-res), res);
+            mInterface->close();
+            mStatusTracker.clear();
+            return res;
+        }
+    }
+
     /** Start up request queue thread */
     mRequestThread = new RequestThread(
             this, mStatusTracker, mInterface, sessionParamKeys, mUseHalBufManager);
@@ -951,6 +985,13 @@
         return hardware::Void();
     }
 
+    if (bufReqs.size() > mOutputStreams.size()) {
+        ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
+                __FUNCTION__, bufReqs.size(), mOutputStreams.size());
+        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+        return hardware::Void();
+    }
+
     // Check for repeated streamId
     for (const auto& bufReq : bufReqs) {
         if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
@@ -962,19 +1003,10 @@
         streamIds.add(bufReq.streamId);
     }
 
-    // TODO: check we are not configuring streams. If so return FAILED_CONFIGURING
-    // Probably need to hook CameraDeviceClient::beginConfigure and figure something
-    // out for API1 client... maybe grab mLock and check mNeedConfig but then we will
-    // need to wait until mLock is released...
-    // _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
-    // return hardware::Void();
-
-    // TODO: here we start accessing mOutputStreams, might need mLock, but that
-    //       might block incoming API calls. Not sure how bad is it.
-    if (bufReqs.size() > mOutputStreams.size()) {
-        ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
-                __FUNCTION__, bufReqs.size(), mOutputStreams.size());
-        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+    if (!mRequestBufferSM.startRequestBuffer()) {
+        ALOGE("%s: request buffer disallowed while camera service is configuring",
+                __FUNCTION__);
+        _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
         return hardware::Void();
     }
 
@@ -991,6 +1023,7 @@
             ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
             hardware::hidl_vec<StreamBufferRet> emptyBufRets;
             _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
+            mRequestBufferSM.endRequestBuffer();
             return hardware::Void();
         }
 
@@ -1074,15 +1107,20 @@
                             __FUNCTION__, streamId, strerror(-res), res);
                 }
             }
+            for (size_t b = 0; b < numAllocatedBuffers; b++) {
+                camera3_stream_buffer_t& sb = streamBuffers[b];
+                sb.acquire_fence = -1;
+                sb.status = CAMERA3_BUFFER_STATUS_ERROR;
+            }
             returnOutputBuffers(streamBuffers.data(), numAllocatedBuffers, 0);
         }
     }
-    // End of mOutputStreams access
 
     _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
             oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
                              BufferRequestStatus::FAILED_UNKNOWN,
             bufRets);
+    mRequestBufferSM.endRequestBuffer();
     return hardware::Void();
 }
 
@@ -1734,7 +1772,8 @@
     } else if (isShared) {
         newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
                 width, height, format, consumerUsage, dataSpace, rotation,
-                mTimestampOffset, physicalCameraId, streamSetId);
+                mTimestampOffset, physicalCameraId, streamSetId,
+                mUseHalBufManager);
     } else if (consumers.size() == 0 && hasDeferredConsumer) {
         newStream = new Camera3OutputStream(mNextStreamId,
                 width, height, format, consumerUsage, dataSpace, rotation,
@@ -2132,6 +2171,15 @@
 
     mStatusWaiters++;
 
+    // Notify HAL to start draining. We need to notify the HalInterface layer
+    // even when the device is already IDLE, so HalInterface can reject incoming
+    // requestStreamBuffers call.
+    if (!active && mUseHalBufManager) {
+        auto streamIds = mOutputStreams.getStreamIds();
+        mRequestThread->signalPipelineDrain(streamIds);
+        mRequestBufferSM.onWaitUntilIdle();
+    }
+
     bool stateSeen = false;
     do {
         if (active == (mStatus == STATUS_ACTIVE)) {
@@ -2139,12 +2187,6 @@
             break;
         }
 
-        // Notify HAL to start draining
-        if (!active && mUseHalBufManager) {
-            auto streamIds = mOutputStreams.getStreamIds();
-            mRequestThread->signalPipelineDrain(streamIds);
-        }
-
         res = mStatusChanged.waitRelative(mLock, timeout);
         if (res != OK) break;
 
@@ -2889,6 +2931,10 @@
         return rc;
     }
 
+    if (mDummyStreamId == NO_STREAM) {
+        mRequestBufferSM.onStreamsConfigured();
+    }
+
     return OK;
 }
 
@@ -3013,13 +3059,14 @@
         int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
         bool hasAppCallback, nsecs_t maxExpectedDuration,
         std::set<String8>& physicalCameraIds, bool isStillCapture,
-        bool isZslCapture) {
+        bool isZslCapture, const SurfaceMap& outputSurfaces) {
     ATRACE_CALL();
     Mutex::Autolock l(mInFlightLock);
 
     ssize_t res;
     res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
-            hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture));
+            hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture,
+            outputSurfaces));
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
@@ -3037,18 +3084,55 @@
 
 void Camera3Device::returnOutputBuffers(
         const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
-        nsecs_t timestamp, bool timestampIncreasing) {
+        nsecs_t timestamp, bool timestampIncreasing,
+        const SurfaceMap& outputSurfaces,
+        const CaptureResultExtras &inResultExtras) {
 
     for (size_t i = 0; i < numBuffers; i++)
     {
-        Camera3Stream *stream = Camera3Stream::cast(outputBuffers[i].stream);
-        status_t res = stream->returnBuffer(outputBuffers[i], timestamp, timestampIncreasing);
+        Camera3StreamInterface *stream = Camera3Stream::cast(outputBuffers[i].stream);
+        int streamId = stream->getId();
+        const auto& it = outputSurfaces.find(streamId);
+        status_t res = OK;
+        if (it != outputSurfaces.end()) {
+            res = stream->returnBuffer(
+                    outputBuffers[i], timestamp, timestampIncreasing, it->second);
+        } else {
+            res = stream->returnBuffer(
+                    outputBuffers[i], timestamp, timestampIncreasing);
+        }
+
         // Note: stream may be deallocated at this point, if this buffer was
         // the last reference to it.
         if (res != OK) {
             ALOGE("Can't return buffer to its stream: %s (%d)",
                 strerror(-res), res);
         }
+
+        // Long processing consumers can cause returnBuffer timeout for shared stream
+        // If that happens, cancel the buffer and send a buffer error to client
+        if (it != outputSurfaces.end() && res == TIMED_OUT &&
+                outputBuffers[i].status == CAMERA3_BUFFER_STATUS_OK) {
+            // cancel the buffer
+            camera3_stream_buffer_t sb = outputBuffers[i];
+            sb.status = CAMERA3_BUFFER_STATUS_ERROR;
+            stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing);
+
+            // notify client buffer error
+            sp<NotificationListener> listener;
+            {
+                Mutex::Autolock l(mOutputLock);
+                listener = mListener.promote();
+            }
+
+            if (listener != nullptr) {
+                CaptureResultExtras extras = inResultExtras;
+                extras.errorStreamId = streamId;
+                listener->notifyError(
+                        hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER,
+                        extras);
+            }
+        }
     }
 }
 
@@ -3059,6 +3143,7 @@
 
     // Indicate idle inFlightMap to the status tracker
     if (mInFlightMap.size() == 0) {
+        mRequestBufferSM.onInflightMapEmpty();
         // Hold a separate dedicated tracker lock to prevent race with disconnect and also
         // avoid a deadlock during reprocess requests.
         Mutex::Autolock l(mTrackerLock);
@@ -3106,7 +3191,8 @@
         assert(request.requestStatus != OK ||
                request.pendingOutputBuffers.size() == 0);
         returnOutputBuffers(request.pendingOutputBuffers.array(),
-            request.pendingOutputBuffers.size(), 0);
+            request.pendingOutputBuffers.size(), 0, /*timestampIncreasing*/true,
+            request.outputSurfaces, request.resultExtras);
 
         removeInFlightMapEntryLocked(idx);
         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
@@ -3130,7 +3216,9 @@
         for (size_t idx = 0; idx < mInFlightMap.size(); idx++) {
             const InFlightRequest &request = mInFlightMap.valueAt(idx);
             returnOutputBuffers(request.pendingOutputBuffers.array(),
-                request.pendingOutputBuffers.size(), 0);
+                request.pendingOutputBuffers.size(), 0,
+                /*timestampIncreasing*/true, request.outputSurfaces,
+                request.resultExtras);
         }
         mInFlightMap.clear();
         mExpectedInflightDuration = 0;
@@ -3258,6 +3346,13 @@
     captureResult.mResultExtras = resultExtras;
     captureResult.mMetadata = partialResult;
 
+    // Fix up result metadata for monochrome camera.
+    status_t res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
+    if (res != OK) {
+        SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+        return;
+    }
+
     insertResultLocked(&captureResult, frameNumber);
 }
 
@@ -3329,6 +3424,21 @@
                 frameNumber, strerror(res), res);
         return;
     }
+    // Fix up result metadata for monochrome camera.
+    res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
+    if (res != OK) {
+        SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+        return;
+    }
+    for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+        String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+        res = fixupMonochromeTags(mPhysicalDeviceInfoMap.at(cameraId8.c_str()),
+                physicalMetadata.mPhysicalCameraMetadata);
+        if (res != OK) {
+            SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+            return;
+        }
+    }
 
     mTagMonitor.monitorMetadata(TagMonitor::RESULT,
             frameNumber, timestamp.data.i64[0], captureResult.mMetadata);
@@ -3488,7 +3598,8 @@
         } else {
             bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
             returnOutputBuffers(result->output_buffers,
-                result->num_output_buffers, shutterTimestamp, timestampIncreasing);
+                result->num_output_buffers, shutterTimestamp, timestampIncreasing,
+                request.outputSurfaces, request.resultExtras);
         }
 
         if (result->result != NULL && !isPartialResult) {
@@ -3501,7 +3612,7 @@
             if (shutterTimestamp == 0) {
                 request.pendingMetadata = result->result;
                 request.collectedPartialResult = collectedPartialResult;
-           } else if (request.hasCallback) {
+            } else if (request.hasCallback) {
                 CameraMetadata metadata;
                 metadata = result->result;
                 sendCaptureResult(metadata, request.resultExtras,
@@ -3621,6 +3732,9 @@
                         // In case of missing result check whether the buffers
                         // returned. If they returned, then remove inflight
                         // request.
+                        // TODO: should we call this for ERROR_CAMERA_REQUEST as well?
+                        //       otherwise we are depending on HAL to send the buffers back after
+                        //       calling notifyError. Not sure if that's in the spec.
                         removeInFlightRequestIfReadyLocked(idx);
                     }
                 } else {
@@ -3696,7 +3810,8 @@
             }
             bool timestampIncreasing = !(r.zslCapture || r.hasInputBuffer);
             returnOutputBuffers(r.pendingOutputBuffers.array(),
-                r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing);
+                    r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing,
+                    r.outputSurfaces, r.resultExtras);
             r.pendingOutputBuffers.clear();
 
             removeInFlightRequestIfReadyLocked(idx);
@@ -5097,6 +5212,13 @@
     nsecs_t tRequestEnd = systemTime(SYSTEM_TIME_MONOTONIC);
     mRequestLatency.add(tRequestStart, tRequestEnd);
 
+    if (submitRequestSuccess) {
+        sp<Camera3Device> parent = mParent.promote();
+        if (parent != nullptr) {
+            parent->mRequestBufferSM.onRequestSubmitted();
+        }
+    }
+
     if (useFlushLock) {
         mFlushLock.unlock();
     }
@@ -5241,8 +5363,11 @@
         }
         nsecs_t waitDuration = kBaseGetBufferWait + parent->getExpectedInFlightDuration();
 
+        SurfaceMap uniqueSurfaceIdMap;
         for (size_t j = 0; j < captureRequest->mOutputStreams.size(); j++) {
-            sp<Camera3OutputStreamInterface> outputStream = captureRequest->mOutputStreams.editItemAt(j);
+            sp<Camera3OutputStreamInterface> outputStream =
+                    captureRequest->mOutputStreams.editItemAt(j);
+            int streamId = outputStream->getId();
 
             // Prepare video buffers for high speed recording on the first video request.
             if (mPrepareVideoStream && outputStream->isVideoStream()) {
@@ -5261,6 +5386,20 @@
                 }
             }
 
+            std::vector<size_t> uniqueSurfaceIds;
+            res = outputStream->getUniqueSurfaceIds(
+                    captureRequest->mOutputSurfaces[streamId],
+                    &uniqueSurfaceIds);
+            // INVALID_OPERATION is normal output for streams not supporting surfaceIds
+            if (res != OK && res != INVALID_OPERATION) {
+                ALOGE("%s: failed to query stream %d unique surface IDs",
+                        __FUNCTION__, streamId);
+                return res;
+            }
+            if (res == OK) {
+                uniqueSurfaceIdMap.insert({streamId, std::move(uniqueSurfaceIds)});
+            }
+
             if (mUseHalBufManager) {
                 // HAL will request buffer through requestStreamBuffer API
                 camera3_stream_buffer_t& buffer = outputBuffers->editItemAt(j);
@@ -5272,7 +5411,7 @@
             } else {
                 res = outputStream->getBuffer(&outputBuffers->editItemAt(j),
                         waitDuration,
-                        captureRequest->mOutputSurfaces[outputStream->getId()]);
+                        captureRequest->mOutputSurfaces[streamId]);
                 if (res != OK) {
                     // Can't get output buffer from gralloc queue - this could be due to
                     // abandoned queue or other consumer misbehavior, so not a fatal
@@ -5326,7 +5465,9 @@
                 /*hasInput*/halRequest->input_buffer != NULL,
                 hasCallback,
                 calculateMaxExpectedDuration(halRequest->settings),
-                requestedPhysicalCameras, isStillCapture, isZslCapture);
+                requestedPhysicalCameras, isStillCapture, isZslCapture,
+                (mUseHalBufManager) ? uniqueSurfaceIdMap :
+                                      SurfaceMap{});
         ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
                ", burstId = %" PRId32 ".",
                 __FUNCTION__,
@@ -5402,7 +5543,7 @@
             if (s.first == streamId) {
                 const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
                 if (it != s.second.end()) {
-                  return true;
+                    return true;
                 }
             }
         }
@@ -5413,7 +5554,7 @@
             if (s.first == streamId) {
                 const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
                 if (it != s.second.end()) {
-                  return true;
+                    return true;
                 }
             }
         }
@@ -5430,7 +5571,8 @@
 
     Mutex::Autolock pl(mPauseLock);
     if (mPaused) {
-        return mInterface->signalPipelineDrain(streamIds);
+        mInterface->signalPipelineDrain(streamIds);
+        return;
     }
     // If request thread is still busy, wait until paused then notify HAL
     mNotifyPipelineDrain = true;
@@ -5619,6 +5761,10 @@
                     mNotifyPipelineDrain = false;
                     mStreamIdsToBeDrained.clear();
                 }
+                sp<Camera3Device> parent = mParent.promote();
+                if (parent != nullptr) {
+                    parent->mRequestBufferSM.onRequestThreadPaused();
+                }
             }
             // Stop waiting for now and let thread management happen
             return NULL;
@@ -5708,6 +5854,10 @@
                 mNotifyPipelineDrain = false;
                 mStreamIdsToBeDrained.clear();
             }
+            sp<Camera3Device> parent = mParent.promote();
+            if (parent != nullptr) {
+                parent->mRequestBufferSM.onRequestThreadPaused();
+            }
         }
 
         res = mDoPauseSignal.waitRelative(mPauseLock, kRequestTimeout);
@@ -6163,4 +6313,176 @@
     return true;
 }
 
+status_t Camera3Device::RequestBufferStateMachine::initialize(
+        sp<camera3::StatusTracker> statusTracker) {
+    if (statusTracker == nullptr) {
+        ALOGE("%s: statusTracker is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    std::lock_guard<std::mutex> lock(mLock);
+    mStatusTracker = statusTracker;
+    mRequestBufferStatusId = statusTracker->addComponent();
+    return OK;
+}
+
+bool Camera3Device::RequestBufferStateMachine::startRequestBuffer() {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mStatus == RB_STATUS_READY) {
+        mRequestBufferOngoing = true;
+        return true;
+    }
+    return false;
+}
+
+void Camera3Device::RequestBufferStateMachine::endRequestBuffer() {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (!mRequestBufferOngoing) {
+        ALOGE("%s called without a successful startRequestBuffer call first!", __FUNCTION__);
+        return;
+    }
+    mRequestBufferOngoing = false;
+    if (mStatus == RB_STATUS_PENDING_STOP) {
+        checkSwitchToStopLocked();
+    }
+}
+
+void Camera3Device::RequestBufferStateMachine::onStreamsConfigured() {
+    std::lock_guard<std::mutex> lock(mLock);
+    RequestBufferState oldStatus = mStatus;
+    mStatus = RB_STATUS_READY;
+    if (oldStatus != RB_STATUS_READY) {
+        notifyTrackerLocked(/*active*/true);
+    }
+    return;
+}
+
+void Camera3Device::RequestBufferStateMachine::onRequestSubmitted() {
+    std::lock_guard<std::mutex> lock(mLock);
+    mRequestThreadPaused = false;
+    mInflightMapEmpty = false;
+    if (mStatus == RB_STATUS_STOPPED) {
+        mStatus = RB_STATUS_READY;
+        notifyTrackerLocked(/*active*/true);
+    }
+    return;
+}
+
+void Camera3Device::RequestBufferStateMachine::onRequestThreadPaused() {
+    std::lock_guard<std::mutex> lock(mLock);
+    mRequestThreadPaused = true;
+    if (mStatus == RB_STATUS_PENDING_STOP) {
+        checkSwitchToStopLocked();
+    }
+    return;
+}
+
+void Camera3Device::RequestBufferStateMachine::onInflightMapEmpty() {
+    std::lock_guard<std::mutex> lock(mLock);
+    mInflightMapEmpty = true;
+    if (mStatus == RB_STATUS_PENDING_STOP) {
+        checkSwitchToStopLocked();
+    }
+    return;
+}
+
+void Camera3Device::RequestBufferStateMachine::onWaitUntilIdle() {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (!checkSwitchToStopLocked()) {
+        mStatus = RB_STATUS_PENDING_STOP;
+    }
+    return;
+}
+
+void Camera3Device::RequestBufferStateMachine::notifyTrackerLocked(bool active) {
+    sp<StatusTracker> statusTracker = mStatusTracker.promote();
+    if (statusTracker != nullptr) {
+        if (active) {
+            statusTracker->markComponentActive(mRequestBufferStatusId);
+        } else {
+            statusTracker->markComponentIdle(mRequestBufferStatusId, Fence::NO_FENCE);
+        }
+    }
+}
+
+bool Camera3Device::RequestBufferStateMachine::checkSwitchToStopLocked() {
+    if (mInflightMapEmpty && mRequestThreadPaused && !mRequestBufferOngoing) {
+        mStatus = RB_STATUS_STOPPED;
+        notifyTrackerLocked(/*active*/false);
+        return true;
+    }
+    return false;
+}
+
+status_t Camera3Device::fixupMonochromeTags(const CameraMetadata& deviceInfo,
+        CameraMetadata& resultMetadata) {
+    status_t res = OK;
+    if (!mNeedFixupMonochromeTags) {
+        return res;
+    }
+
+    // Remove tags that are not applicable to monochrome camera.
+    int32_t tagsToRemove[] = {
+           ANDROID_SENSOR_GREEN_SPLIT,
+           ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
+           ANDROID_COLOR_CORRECTION_MODE,
+           ANDROID_COLOR_CORRECTION_TRANSFORM,
+           ANDROID_COLOR_CORRECTION_GAINS,
+    };
+    for (auto tag : tagsToRemove) {
+        res = resultMetadata.erase(tag);
+        if (res != OK) {
+            ALOGE("%s: Failed to remove tag %d for monochrome camera", __FUNCTION__, tag);
+            return res;
+        }
+    }
+
+    // ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL
+    camera_metadata_entry blEntry = resultMetadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+    for (size_t i = 1; i < blEntry.count; i++) {
+        blEntry.data.f[i] = blEntry.data.f[0];
+    }
+
+    // ANDROID_SENSOR_NOISE_PROFILE
+    camera_metadata_entry npEntry = resultMetadata.find(ANDROID_SENSOR_NOISE_PROFILE);
+    if (npEntry.count > 0 && npEntry.count % 2 == 0) {
+        double np[] = {npEntry.data.d[0], npEntry.data.d[1]};
+        res = resultMetadata.update(ANDROID_SENSOR_NOISE_PROFILE, np, 2);
+        if (res != OK) {
+             ALOGE("%s: Failed to update SENSOR_NOISE_PROFILE: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+    }
+
+    // ANDROID_STATISTICS_LENS_SHADING_MAP
+    camera_metadata_ro_entry lsSizeEntry = deviceInfo.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+    camera_metadata_entry lsEntry = resultMetadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+    if (lsSizeEntry.count == 2 && lsEntry.count > 0
+            && (int32_t)lsEntry.count == 4 * lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]) {
+        for (int32_t i = 0; i < lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]; i++) {
+            lsEntry.data.f[4*i+1] = lsEntry.data.f[4*i];
+            lsEntry.data.f[4*i+2] = lsEntry.data.f[4*i];
+            lsEntry.data.f[4*i+3] = lsEntry.data.f[4*i];
+        }
+    }
+
+    // ANDROID_TONEMAP_CURVE_BLUE
+    // ANDROID_TONEMAP_CURVE_GREEN
+    // ANDROID_TONEMAP_CURVE_RED
+    camera_metadata_entry tcbEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_BLUE);
+    camera_metadata_entry tcgEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_GREEN);
+    camera_metadata_entry tcrEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_RED);
+    if (tcbEntry.count > 0
+            && tcbEntry.count == tcgEntry.count
+            && tcbEntry.count == tcrEntry.count) {
+        for (size_t i = 0; i < tcbEntry.count; i++) {
+            tcbEntry.data.f[i] = tcrEntry.data.f[i];
+            tcgEntry.data.f[i] = tcrEntry.data.f[i];
+        }
+    }
+
+    return res;
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 5c0f570..35b9d6d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1031,6 +1031,9 @@
         // Indicates a ZSL capture request
         bool zslCapture;
 
+        // What shared surfaces an output should go to
+        SurfaceMap outputSurfaces;
+
         // Default constructor needed by KeyedVector
         InFlightRequest() :
                 shutterTimestamp(0),
@@ -1049,7 +1052,8 @@
         InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
                 bool hasAppCallback, nsecs_t maxDuration,
                 const std::set<String8>& physicalCameraIdSet, bool isStillCapture,
-                bool isZslCapture) :
+                bool isZslCapture,
+                const SurfaceMap& outSurfaces = SurfaceMap{}) :
                 shutterTimestamp(0),
                 sensorTimestamp(0),
                 requestStatus(OK),
@@ -1062,7 +1066,8 @@
                 skipResultMetadata(false),
                 physicalCameraIds(physicalCameraIdSet),
                 stillCapture(isStillCapture),
-                zslCapture(isZslCapture) {
+                zslCapture(isZslCapture),
+                outputSurfaces(outSurfaces) {
         }
     };
 
@@ -1079,7 +1084,8 @@
     status_t registerInFlight(uint32_t frameNumber,
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
             bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
-            bool isStillCapture, bool isZslCapture);
+            bool isStillCapture, bool isZslCapture,
+            const SurfaceMap& outputSurfaces);
 
     /**
      * Returns the maximum expected time it'll take for all currently in-flight
@@ -1189,7 +1195,11 @@
 
     // helper function to return the output buffers to the streams.
     void returnOutputBuffers(const camera3_stream_buffer_t *outputBuffers,
-            size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true);
+            size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true,
+            // The following arguments are only meant for surface sharing use case
+            const SurfaceMap& outputSurfaces = SurfaceMap{},
+            // Used to send buffer error callback when failing to return buffer
+            const CaptureResultExtras &resultExtras = CaptureResultExtras{});
 
     // Send a partial capture result.
     void sendPartialCaptureResult(const camera_metadata_t * partialResult,
@@ -1249,12 +1259,84 @@
     // b/79972865
     Mutex mTrackerLock;
 
-    // Whether HAL request buffers through requestStreamBuffer API
+    // Whether HAL request buffers through requestStreamBuffers API
     bool mUseHalBufManager = false;
 
     // Lock to ensure requestStreamBuffers() callbacks are serialized
     std::mutex mRequestBufferInterfaceLock;
 
+    // The state machine to control when requestStreamBuffers should allow
+    // HAL to request buffers.
+    enum RequestBufferState {
+        /**
+         * This is the initial state.
+         * requestStreamBuffers call will return FAILED_CONFIGURING in this state.
+         * Will switch to RB_STATUS_READY after a successful configureStreams or
+         * processCaptureRequest call.
+         */
+        RB_STATUS_STOPPED,
+
+        /**
+         * requestStreamBuffers call will proceed in this state.
+         * When device is asked to stay idle via waitUntilStateThenRelock() call:
+         *     - Switch to RB_STATUS_STOPPED if there is no inflight requests and
+         *       request thread is paused.
+         *     - Switch to RB_STATUS_PENDING_STOP otherwise
+         */
+        RB_STATUS_READY,
+
+        /**
+         * requestStreamBuffers call will proceed in this state.
+         * Switch to RB_STATUS_STOPPED when all inflight requests are fulfilled
+         * and request thread is paused
+         */
+        RB_STATUS_PENDING_STOP,
+    };
+
+    class RequestBufferStateMachine {
+      public:
+        status_t initialize(sp<camera3::StatusTracker> statusTracker);
+
+        // Return if the state machine currently allows for requestBuffers
+        // If the state allows for it, mRequestBufferOngoing will be set to true
+        // and caller must call endRequestBuffer() later to unset the flag
+        bool startRequestBuffer();
+        void endRequestBuffer();
+
+        // Events triggered by application API call
+        void onStreamsConfigured();
+        void onWaitUntilIdle();
+
+        // Events usually triggered by hwBinder processCaptureResult callback thread
+        // But can also be triggered on request thread for failed request, or on
+        // hwbinder notify callback thread for shutter/error callbacks
+        void onInflightMapEmpty();
+
+        // Events triggered by RequestThread
+        void onRequestSubmitted();
+        void onRequestThreadPaused();
+
+      private:
+        void notifyTrackerLocked(bool active);
+
+        // Switch to STOPPED state and return true if all conditions allows for it.
+        // Otherwise do nothing and return false.
+        bool checkSwitchToStopLocked();
+
+        std::mutex mLock;
+        RequestBufferState mStatus = RB_STATUS_STOPPED;
+
+        bool mRequestThreadPaused = true;
+        bool mInflightMapEmpty = true;
+        bool mRequestBufferOngoing = false;
+
+        wp<camera3::StatusTracker> mStatusTracker;
+        int  mRequestBufferStatusId;
+    } mRequestBufferSM;
+
+    // Fix up result metadata for monochrome camera.
+    bool mNeedFixupMonochromeTags;
+    status_t fixupMonochromeTags(const CameraMetadata& deviceInfo, CameraMetadata& resultMetadata);
 }; // class Camera3Device
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index fb1ff77..b637160 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -48,7 +48,7 @@
 
 status_t Camera3DummyStream::returnBufferLocked(
         const camera3_stream_buffer &,
-        nsecs_t) {
+        nsecs_t, const std::vector<size_t>&) {
     ATRACE_CALL();
     ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
@@ -58,6 +58,7 @@
             const camera3_stream_buffer &,
             nsecs_t,
             bool,
+            const std::vector<size_t>&,
             /*out*/
             sp<Fence>*) {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 4627548..4b67ea5 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -87,6 +87,9 @@
      */
     virtual ssize_t getSurfaceId(const sp<Surface> &/*surface*/) { return 0; }
 
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>&,
+            /*out*/std::vector<size_t>*) { return INVALID_OPERATION; };
+
     /**
      * Update the stream output surfaces.
      */
@@ -104,6 +107,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut);
 
@@ -128,7 +132,7 @@
             const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp, const std::vector<size_t>& surface_ids);
 
     virtual status_t configureQueueLocked();
 
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 18b8c4d..2e909a0 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -219,7 +219,8 @@
 status_t Camera3IOStreamBase::returnAnyBufferLocked(
         const camera3_stream_buffer &buffer,
         nsecs_t timestamp,
-        bool output) {
+        bool output,
+        const std::vector<size_t>& surface_ids) {
     status_t res;
 
     // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be
@@ -235,7 +236,7 @@
     }
 
     sp<Fence> releaseFence;
-    res = returnBufferCheckedLocked(buffer, timestamp, output,
+    res = returnBufferCheckedLocked(buffer, timestamp, output, surface_ids,
                                     &releaseFence);
     // Res may be an error, but we still want to decrement our owned count
     // to enable clean shutdown. So we'll just return the error but otherwise
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 48e9bbf..750f64d 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -66,12 +66,14 @@
     status_t         returnAnyBufferLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
-            bool output);
+            bool output,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
 
     virtual status_t returnBufferCheckedLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut) = 0;
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 017d7be..fc83684 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -98,6 +98,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>&,
             /*out*/
             sp<Fence> *releaseFenceOut) {
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 0732464..97a627a 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -62,6 +62,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut);
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index ecbcf76..219cc24 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -187,16 +187,17 @@
 }
 
 status_t Camera3OutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence) {
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>&) {
     return consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
 }
 
 status_t Camera3OutputStream::returnBufferLocked(
         const camera3_stream_buffer &buffer,
-        nsecs_t timestamp) {
+        nsecs_t timestamp, const std::vector<size_t>& surface_ids) {
     ATRACE_CALL();
 
-    status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true);
+    status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true, surface_ids);
 
     if (res != OK) {
         return res;
@@ -212,6 +213,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut) {
 
@@ -281,7 +283,7 @@
             return res;
         }
 
-        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence);
+        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error queueing buffer to native window: "
                   "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 6f36f92..410905d 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -190,6 +190,9 @@
      */
     virtual ssize_t getSurfaceId(const sp<Surface> &/*surface*/) { return 0; }
 
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>&,
+            /*out*/std::vector<size_t>*) { return INVALID_OPERATION; };
+
     /**
      * Update the stream output surfaces.
      */
@@ -213,6 +216,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut);
 
@@ -285,10 +289,11 @@
 
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp, const std::vector<size_t>& surface_ids);
 
     virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence);
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>& surface_ids);
 
     virtual status_t configureQueueLocked();
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index a711a6d..2bde949 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -67,6 +67,18 @@
     virtual ssize_t getSurfaceId(const sp<Surface> &surface) = 0;
 
     /**
+     * Query the unique surface IDs of current surfaceIds.
+     * When passing unique surface IDs in returnBuffer(), if the
+     * surfaceId has been removed from the stream, the output corresponding to
+     * the unique surface ID will be ignored and not delivered to client.
+     *
+     * Return INVALID_OPERATION if and only if the stream does not support
+     * surface sharing.
+     */
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>& surfaceIds,
+            /*out*/std::vector<size_t>* outUniqueIds) = 0;
+
+    /**
      * Update the stream output surfaces.
      */
     virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 1c13950..e3b74d7 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "Camera3-SharedOuStrm"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
 #include "Camera3SharedOutputStream.h"
 
 namespace android {
@@ -28,16 +32,17 @@
         uint64_t consumerUsage, android_dataspace dataSpace,
         camera3_stream_rotation_t rotation,
         nsecs_t timestampOffset, const String8& physicalCameraId,
-        int setId) :
+        int setId, bool useHalBufManager) :
         Camera3OutputStream(id, CAMERA3_STREAM_OUTPUT, width, height,
                             format, dataSpace, rotation, physicalCameraId,
-                            consumerUsage, timestampOffset, setId) {
+                            consumerUsage, timestampOffset, setId),
+        mUseHalBufManager(useHalBufManager) {
     size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
     if (surfaces.size() > consumerCount) {
         ALOGE("%s: Trying to add more consumers than the maximum ", __func__);
     }
     for (size_t i = 0; i < consumerCount; i++) {
-        mSurfaces[i] = surfaces[i];
+        mSurfaceUniqueIds[i] = std::make_pair(surfaces[i], mNextUniqueSurfaceId++);
     }
 }
 
@@ -48,15 +53,15 @@
 status_t Camera3SharedOutputStream::connectStreamSplitterLocked() {
     status_t res = OK;
 
-    mStreamSplitter = new Camera3StreamSplitter();
+    mStreamSplitter = new Camera3StreamSplitter(mUseHalBufManager);
 
     uint64_t usage;
     getEndpointUsage(&usage);
 
     std::unordered_map<size_t, sp<Surface>> initialSurfaces;
     for (size_t i = 0; i < kMaxOutputs; i++) {
-        if (mSurfaces[i] != nullptr) {
-            initialSurfaces.emplace(i, mSurfaces[i]);
+        if (mSurfaceUniqueIds[i].first != nullptr) {
+            initialSurfaces.emplace(i, mSurfaceUniqueIds[i].first);
         }
     }
 
@@ -71,6 +76,31 @@
     return res;
 }
 
+status_t Camera3SharedOutputStream::attachBufferToSplitterLocked(
+        ANativeWindowBuffer* anb,
+        const std::vector<size_t>& surface_ids) {
+    status_t res = OK;
+
+    // Attach the buffer to the splitter output queues. This could block if
+    // the output queue doesn't have any empty slot. So unlock during the course
+    // of attachBufferToOutputs.
+    sp<Camera3StreamSplitter> splitter = mStreamSplitter;
+    mLock.unlock();
+    res = splitter->attachBufferToOutputs(anb, surface_ids);
+    mLock.lock();
+    if (res != OK) {
+        ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+        // let prepareNextBuffer handle the error.)
+        if (res == NO_INIT && mState == STATE_CONFIGURED) {
+            mState = STATE_ABANDONED;
+        }
+    }
+    return res;
+}
+
+
 status_t Camera3SharedOutputStream::notifyBufferReleased(ANativeWindowBuffer *anwBuffer) {
     Mutex::Autolock l(mLock);
     status_t res = OK;
@@ -89,7 +119,7 @@
         return true;
     }
 
-    return (mSurfaces[surface_id] == nullptr);
+    return (mSurfaceUniqueIds[surface_id].first == nullptr);
 }
 
 status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
@@ -112,7 +142,7 @@
             return NO_MEMORY;
         }
 
-        mSurfaces[id] = surface;
+        mSurfaceUniqueIds[id] = std::make_pair(surface, mNextUniqueSurfaceId++);
 
         // Only call addOutput if the splitter has been connected.
         if (mStreamSplitter != nullptr) {
@@ -128,7 +158,7 @@
 }
 
 status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffer,
-        const std::vector<size_t>& surface_ids) {
+        const std::vector<size_t>& surfaceIds) {
     ANativeWindowBuffer* anb;
     int fenceFd = -1;
 
@@ -138,27 +168,11 @@
         return res;
     }
 
-    // TODO: need to refactor this to support requestStreamBuffers API
-    // Need to wait until processCaptureResult to decide the source buffer
-    // to attach to output...
-
-    // Attach the buffer to the splitter output queues. This could block if
-    // the output queue doesn't have any empty slot. So unlock during the course
-    // of attachBufferToOutputs.
-    sp<Camera3StreamSplitter> splitter = mStreamSplitter;
-    mLock.unlock();
-    res = splitter->attachBufferToOutputs(anb, surface_ids);
-    mLock.lock();
-    if (res != OK) {
-        ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
-        // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
-        // let prepareNextBuffer handle the error.)
-        if (res == NO_INIT && mState == STATE_CONFIGURED) {
-            mState = STATE_ABANDONED;
+    if (!mUseHalBufManager) {
+        res = attachBufferToSplitterLocked(anb, surfaceIds);
+        if (res != OK) {
+            return res;
         }
-
-        return res;
     }
 
     /**
@@ -172,8 +186,38 @@
 }
 
 status_t Camera3SharedOutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence) {
-    status_t res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>& uniqueSurfaceIds) {
+    status_t res = OK;
+    if (mUseHalBufManager) {
+        if (uniqueSurfaceIds.size() == 0) {
+            ALOGE("%s: uniqueSurfaceIds must not be empty!", __FUNCTION__);
+            return BAD_VALUE;
+        }
+        Mutex::Autolock l(mLock);
+        std::vector<size_t> surfaceIds;
+        for (const auto& uniqueId : uniqueSurfaceIds) {
+            bool uniqueIdFound = false;
+            for (size_t i = 0; i < kMaxOutputs; i++) {
+                if (mSurfaceUniqueIds[i].second == uniqueId) {
+                    surfaceIds.push_back(i);
+                    uniqueIdFound = true;
+                    break;
+                }
+            }
+            if (!uniqueIdFound) {
+                ALOGV("%s: unknown unique surface ID %zu for stream %d: "
+                        "output might have been removed.",
+                        __FUNCTION__, uniqueId, mId);
+            }
+        }
+        res = attachBufferToSplitterLocked(buffer, surfaceIds);
+        if (res != OK) {
+            return res;
+        }
+    }
+
+    res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
 
     // After queuing buffer to the internal consumer queue, check whether the buffer is
     // successfully queued to the output queues.
@@ -232,8 +276,8 @@
         *usage = getPresetConsumerUsage();
 
         for (size_t id = 0; id < kMaxOutputs; id++) {
-            if (mSurfaces[id] != nullptr) {
-                res = getEndpointUsageForSurface(&u, mSurfaces[id]);
+            if (mSurfaceUniqueIds[id].first != nullptr) {
+                res = getEndpointUsageForSurface(&u, mSurfaceUniqueIds[id].first);
                 *usage |= u;
             }
         }
@@ -249,7 +293,7 @@
 ssize_t Camera3SharedOutputStream::getNextSurfaceIdLocked() {
     ssize_t id = -1;
     for (size_t i = 0; i < kMaxOutputs; i++) {
-        if (mSurfaces[i] == nullptr) {
+        if (mSurfaceUniqueIds[i].first == nullptr) {
             id = i;
             break;
         }
@@ -262,7 +306,7 @@
     Mutex::Autolock l(mLock);
     ssize_t id = -1;
     for (size_t i = 0; i < kMaxOutputs; i++) {
-        if (mSurfaces[i] == surface) {
+        if (mSurfaceUniqueIds[i].first == surface) {
             id = i;
             break;
         }
@@ -271,6 +315,26 @@
     return id;
 }
 
+status_t Camera3SharedOutputStream::getUniqueSurfaceIds(
+        const std::vector<size_t>& surfaceIds,
+        /*out*/std::vector<size_t>* outUniqueIds) {
+    Mutex::Autolock l(mLock);
+    if (outUniqueIds == nullptr || surfaceIds.size() > kMaxOutputs) {
+        return BAD_VALUE;
+    }
+
+    outUniqueIds->clear();
+    outUniqueIds->reserve(surfaceIds.size());
+
+    for (const auto& surfaceId : surfaceIds) {
+        if (surfaceId >= kMaxOutputs) {
+            return BAD_VALUE;
+        }
+        outUniqueIds->push_back(mSurfaceUniqueIds[surfaceId].second);
+    }
+    return OK;
+}
+
 status_t Camera3SharedOutputStream::revertPartialUpdateLocked(
         const KeyedVector<sp<Surface>, size_t> &removedSurfaces,
         const KeyedVector<sp<Surface>, size_t> &attachedSurfaces) {
@@ -284,7 +348,7 @@
                 return UNKNOWN_ERROR;
             }
         }
-        mSurfaces[index] = nullptr;
+        mSurfaceUniqueIds[index] = std::make_pair(nullptr, mNextUniqueSurfaceId++);
     }
 
     for (size_t i = 0; i < removedSurfaces.size(); i++) {
@@ -295,7 +359,8 @@
                 return UNKNOWN_ERROR;
             }
         }
-        mSurfaces[index] = removedSurfaces.keyAt(i);
+        mSurfaceUniqueIds[index] = std::make_pair(
+                removedSurfaces.keyAt(i), mNextUniqueSurfaceId++);
     }
 
     return ret;
@@ -347,8 +412,8 @@
 
             }
         }
-        mSurfaces[it] = nullptr;
-        removedSurfaces.add(mSurfaces[it], it);
+        removedSurfaces.add(mSurfaceUniqueIds[it].first, it);
+        mSurfaceUniqueIds[it] = std::make_pair(nullptr, mNextUniqueSurfaceId++);
     }
 
     //Next add the new outputs
@@ -373,7 +438,7 @@
                 return ret;
             }
         }
-        mSurfaces[surfaceId] = it;
+        mSurfaceUniqueIds[surfaceId] = std::make_pair(it, mNextUniqueSurfaceId++);
         outputMap->add(it, surfaceId);
     }
 
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 02b1c09..b5e37c2 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA3_SHARED_OUTPUT_STREAM_H
 #define ANDROID_SERVERS_CAMERA3_SHARED_OUTPUT_STREAM_H
 
+#include <array>
 #include "Camera3StreamSplitter.h"
 #include "Camera3OutputStream.h"
 
@@ -37,7 +38,8 @@
             uint64_t consumerUsage, android_dataspace dataSpace,
             camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
             const String8& physicalCameraId,
-            int setId = CAMERA3_STREAM_SET_ID_INVALID);
+            int setId = CAMERA3_STREAM_SET_ID_INVALID,
+            bool useHalBufManager = false);
 
     virtual ~Camera3SharedOutputStream();
 
@@ -49,6 +51,15 @@
 
     virtual ssize_t getSurfaceId(const sp<Surface> &surface);
 
+    /**
+     * Query the unique surface IDs of current surfaceIds.
+     * When passing unique surface IDs in returnBuffer(), if the
+     * surfaceId has been removed from the stream, the output corresponding to
+     * the unique surface ID will be ignored and not delivered to client.
+     */
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>& surfaceIds,
+            /*out*/std::vector<size_t>* outUniqueIds) override;
+
     virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
             const std::vector<OutputStreamInfo> &outputInfo,
             const std::vector<size_t> &removedSurfaceIds,
@@ -58,8 +69,17 @@
 
     static const size_t kMaxOutputs = 4;
 
-    // Map surfaceId -> output surfaces
-    sp<Surface> mSurfaces[kMaxOutputs];
+    // Whether HAL is in control for buffer management. Surface sharing behavior
+    // depends on this flag.
+    const bool mUseHalBufManager;
+
+    // Pair of an output Surface and its unique ID
+    typedef std::pair<sp<Surface>, size_t> SurfaceUniqueId;
+
+    // Map surfaceId -> (output surface, unique surface ID)
+    std::array<SurfaceUniqueId, kMaxOutputs> mSurfaceUniqueIds;
+
+    size_t mNextUniqueSurfaceId = 0;
 
     ssize_t getNextSurfaceIdLocked();
 
@@ -78,13 +98,24 @@
     status_t connectStreamSplitterLocked();
 
     /**
+     * Attach the output buffer to stream splitter.
+     * When camera service is doing buffer management, this method will be called
+     * before the buffer is handed out to HAL in request thread.
+     * When HAL is doing buffer management, this method will be called when
+     * the buffer is returned from HAL in hwbinder callback thread.
+     */
+    status_t attachBufferToSplitterLocked(ANativeWindowBuffer* anb,
+            const std::vector<size_t>& surface_ids);
+
+    /**
      * Internal Camera3Stream interface
      */
     virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
             const std::vector<size_t>& surface_ids);
 
     virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence);
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>& uniqueSurfaceIds);
 
     virtual status_t configureQueueLocked();
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 0a30a97..24d1c1b 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -655,7 +655,8 @@
 }
 
 status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
-        nsecs_t timestamp, bool timestampIncreasing) {
+        nsecs_t timestamp, bool timestampIncreasing,
+         const std::vector<size_t>& surface_ids) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
@@ -684,7 +685,7 @@
      *
      * Do this for getBuffer as well.
      */
-    status_t res = returnBufferLocked(b, timestamp);
+    status_t res = returnBufferLocked(b, timestamp, surface_ids);
     if (res == OK) {
         fireBufferListenersLocked(b, /*acquired*/false, /*output*/true);
     }
@@ -843,7 +844,7 @@
     return INVALID_OPERATION;
 }
 status_t Camera3Stream::returnBufferLocked(const camera3_stream_buffer &,
-                                           nsecs_t) {
+                                           nsecs_t, const std::vector<size_t>&) {
     ALOGE("%s: This type of stream does not support output", __FUNCTION__);
     return INVALID_OPERATION;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index e29c3e0..ddba9f6 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -322,11 +322,17 @@
     /**
      * Return a buffer to the stream after use by the HAL.
      *
+     * Multiple surfaces could share the same HAL stream, but a request may
+     * be only for a subset of surfaces. In this case, the
+     * Camera3StreamInterface object needs the surface ID information to attach
+     * buffers for those surfaces.
+     *
      * This method may only be called for buffers provided by getBuffer().
      * For bidirectional streams, this method applies to the output-side buffers
      */
     status_t         returnBuffer(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp, bool timestampIncreasing);
+            nsecs_t timestamp, bool timestampIncreasing,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
@@ -478,7 +484,8 @@
     virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
             const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
     virtual status_t returnInputBufferLocked(
             const camera3_stream_buffer &buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 866b722..a84720b 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -248,11 +248,18 @@
     /**
      * Return a buffer to the stream after use by the HAL.
      *
+     * Multiple surfaces could share the same HAL stream, but a request may
+     * be only for a subset of surfaces. In this case, the
+     * Camera3StreamInterface object needs the surface ID information to attach
+     * buffers for those surfaces. For the case of single surface for a HAL
+     * stream, surface_ids parameter has no effect.
+     *
      * This method may only be called for buffers provided by getBuffer().
      * For bidirectional streams, this method applies to the output-side buffers
      */
     virtual status_t returnBuffer(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp, bool timestampIncreasing = true) = 0;
+            nsecs_t timestamp, bool timestampIncreasing = true,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>()) = 0;
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 6d08842..2b5debf 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -152,6 +152,8 @@
     SP_LOGV("%s: Disconnected", __FUNCTION__);
 }
 
+Camera3StreamSplitter::Camera3StreamSplitter(bool useHalBufManager) :
+        mUseHalBufManager(useHalBufManager) {}
 
 Camera3StreamSplitter::~Camera3StreamSplitter() {
     disconnect();
@@ -241,7 +243,9 @@
     uint64_t usage = 0;
     res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(outputQueue.get()), &usage);
     if (!(usage & (GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE))) {
-        outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
+        nsecs_t timeout = mUseHalBufManager ?
+                kHalBufMgrDequeueBufferTimeout : kNormalDequeueBufferTimeout;
+        outputQueue->setDequeueTimeout(timeout);
     }
 
     res = gbp->allowAllocation(false);
@@ -436,8 +440,9 @@
         res = gbp->attachBuffer(&slot, gb);
         mMutex.lock();
         if (res != OK) {
-            SP_LOGE("%s: Cannot acquireBuffer from GraphicBufferProducer %p: %s (%d)",
+            SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)",
                     __FUNCTION__, gbp.get(), strerror(-res), res);
+            // TODO: might need to detach/cleanup the already attached buffers before return?
             return res;
         }
         if ((slot < 0) || (slot > BufferQueue::NUM_BUFFER_SLOTS)) {
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 1eaf2bd..960f7aa 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -49,7 +49,7 @@
 public:
 
     // Constructor
-    Camera3StreamSplitter() = default;
+    Camera3StreamSplitter(bool useHalBufManager = false);
 
     // Connect to the stream splitter by creating buffer queue and connecting it
     // with output surfaces.
@@ -226,7 +226,10 @@
     android::PixelFormat mFormat = android::PIXEL_FORMAT_NONE;
     uint64_t mProducerUsage = 0;
 
-    static const nsecs_t kDequeueBufferTimeout   = s2ns(1); // 1 sec
+    // The attachBuffer call will happen on different thread according to mUseHalBufManager and have
+    // different timing constraint.
+    static const nsecs_t kNormalDequeueBufferTimeout    = s2ns(1);  // 1 sec
+    static const nsecs_t kHalBufMgrDequeueBufferTimeout = ms2ns(1); // 1 msec
 
     Mutex mMutex;
 
@@ -273,6 +276,8 @@
     size_t mAcquiredInputBuffers;
 
     String8 mConsumerName;
+
+    const bool mUseHalBufManager;
 };
 
 } // namespace android
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index e870965..227a29d 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -29,7 +29,8 @@
     libhidlmemory \
     libhidltransport \
     android.hardware.drm@1.0 \
-    android.hardware.drm@1.1
+    android.hardware.drm@1.1 \
+    android.hardware.drm@1.2
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index 0f9aa15..1d37a8e 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -356,8 +356,7 @@
     return hidlReturn;
 }
 
-int SoundTriggerHalHidl::getModelState(sound_model_handle_t handle,
-                                       struct sound_trigger_recognition_event** event)
+int SoundTriggerHalHidl::getModelState(sound_model_handle_t handle)
 {
     sp<ISoundTriggerHw> soundtrigger = getService();
     if (soundtrigger == 0) {
@@ -377,24 +376,13 @@
     }
 
     int ret = NO_ERROR;
-    Return<void> hidlReturn;
+    Return<int32_t> hidlReturn(0);
     {
         AutoMutex lock(mHalLock);
-        hidlReturn = soundtrigger_2_2->getModelState(
-            model->mHalHandle,
-            [&](int r, const V2_0_ISoundTriggerHwCallback::RecognitionEvent& halEvent) {
-              ret = r;
-              if (ret != 0) {
-                  ALOGE("getModelState returned error code %d", ret);
-              } else {
-                  *event = convertRecognitionEventFromHal(&halEvent);
-              }
-            });
+        hidlReturn = soundtrigger_2_2->getModelState(model->mHalHandle);
     }
     if (!hidlReturn.isOk()) {
         ALOGE("getModelState error %s", hidlReturn.description().c_str());
-        free(*event);
-        *event = nullptr;
         ret = FAILED_TRANSACTION;
     }
     return ret;
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
index 3f4bec3..fb9e39e 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -96,12 +96,12 @@
         virtual int stopAllRecognitions();
 
         /* Get the current state of a given model.
-         * Returns 0 or an error code. If successful it also sets indicated the event pointer
-         * and expectes that the caller will free the memory.
+         * Returns 0 or an error code. If successful the state will be returned asynchronously
+         * via a recognition event in the callback method that was registered in the
+         * startRecognition() method.
          * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
          */
-        virtual int getModelState(sound_model_handle_t handle,
-                                  struct sound_trigger_recognition_event** event);
+        virtual int getModelState(sound_model_handle_t handle);
 
         // ISoundTriggerHwCallback
         virtual ::android::hardware::Return<void> recognitionCallback(
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
index 076ca23..0183ece 100644
--- a/services/soundtrigger/SoundTriggerHalInterface.h
+++ b/services/soundtrigger/SoundTriggerHalInterface.h
@@ -72,12 +72,12 @@
         virtual int stopAllRecognitions() = 0;
 
         /* Get the current state of a given model.
-         * Returns 0 or an error code. If successful it also sets indicated the event pointer
-         * and expectes that the caller will free the memory.
+         * Returns 0 or an error code. If successful the state will be returned asynchronously
+         * via a recognition event in the callback method that was registered in the
+         * startRecognition() method.
          * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
          */
-        virtual int getModelState(sound_model_handle_t handle,
-                                  struct sound_trigger_recognition_event** event) = 0;
+        virtual int getModelState(sound_model_handle_t handle) = 0;
 
 protected:
         SoundTriggerHalInterface() {}
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 79e9e88..7915068 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -717,8 +717,7 @@
     return NO_ERROR;
 }
 
-status_t SoundTriggerHwService::Module::getModelState(sound_model_handle_t handle,
-                                                      sp<IMemory>& eventMemory)
+status_t SoundTriggerHwService::Module::getModelState(sound_model_handle_t handle)
 {
     ALOGV("getModelState() model handle %d", handle);
     if (mHalInterface == 0) {
@@ -734,21 +733,7 @@
         return INVALID_OPERATION;
     }
 
-    if (model->mType != SOUND_MODEL_TYPE_GENERIC) {
-        return BAD_VALUE;
-    }
-
-    struct sound_trigger_recognition_event* event = nullptr;
-    status_t status = mHalInterface->getModelState(handle, &event);
-    if (status == NO_ERROR) {
-        sp<SoundTriggerHwService> service;
-        service = mService.promote();
-        if (service != 0) {
-            eventMemory = service->prepareRecognitionEvent(event);
-        }
-        free(event);
-    }
-    return status;
+    return mHalInterface->getModelState(handle);
 }
 
 void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
@@ -784,7 +769,10 @@
             }
 
             recognitionEvent->capture_session = model->mCaptureSession;
-            model->mState = Model::STATE_IDLE;
+            // Don't reset the model state if this recognition event is a get-state response
+            if (recognitionEvent->status != RECOGNITION_STATUS_GET_STATE_RESPONSE) {
+                model->mState = Model::STATE_IDLE;
+            }
             clients.add(model->mModuleClient);
         }
     } break;
@@ -1052,8 +1040,7 @@
     return module->stopRecognition(handle);
 }
 
-status_t SoundTriggerHwService::ModuleClient::getModelState(sound_model_handle_t handle,
-                                                            sp<IMemory>& eventMemory)
+status_t SoundTriggerHwService::ModuleClient::getModelState(sound_model_handle_t handle)
 {
     ALOGV("getModelState() model handle %d", handle);
     if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
@@ -1065,7 +1052,7 @@
     if (module == 0) {
         return NO_INIT;
     }
-    return module->getModelState(handle, eventMemory);
+    return module->getModelState(handle);
 }
 
 void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active)
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index c222cd9..4258ec0 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -122,8 +122,7 @@
        virtual status_t startRecognition(sound_model_handle_t handle,
                                          const sp<IMemory>& dataMemory);
        virtual status_t stopRecognition(sound_model_handle_t handle);
-       virtual status_t getModelState(sound_model_handle_t handle,
-                                      sp<IMemory>& eventMemory);
+       virtual status_t getModelState(sound_model_handle_t handle);
 
        sp<SoundTriggerHalInterface> halInterface() const { return mHalInterface; }
        struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
@@ -171,8 +170,7 @@
        virtual status_t startRecognition(sound_model_handle_t handle,
                                          const sp<IMemory>& dataMemory);
        virtual status_t stopRecognition(sound_model_handle_t handle);
-       virtual status_t getModelState(sound_model_handle_t handle,
-                                      sp<IMemory>& eventMemory);
+       virtual status_t getModelState(sound_model_handle_t handle);
 
        virtual status_t dump(int fd, const Vector<String16>& args);
 
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
index 32882f1..f5b4b59 100644
--- a/soundtrigger/ISoundTrigger.cpp
+++ b/soundtrigger/ISoundTrigger.cpp
@@ -114,8 +114,7 @@
         return status;
     }
 
-    virtual status_t getModelState(sound_model_handle_t handle,
-                                   sp<IMemory>& eventMemory)
+    virtual status_t getModelState(sound_model_handle_t handle)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
@@ -123,9 +122,6 @@
         status_t status = remote()->transact(GET_MODEL_STATE, data, &reply);
         if (status == NO_ERROR) {
             status = (status_t)reply.readInt32();
-            if (status == NO_ERROR) {
-                eventMemory = interface_cast<IMemory>(reply.readStrongBinder());
-            }
         }
         return status;
     }
@@ -192,14 +188,7 @@
             status_t status = UNKNOWN_ERROR;
             status_t ret = data.read(&handle, sizeof(sound_model_handle_t));
             if (ret == NO_ERROR) {
-                sp<IMemory> eventMemory;
-                status = getModelState(handle, eventMemory);
-                if (eventMemory != NULL) {
-                    ret = reply->writeStrongBinder(
-                        IInterface::asBinder(eventMemory));
-                } else {
-                    ret = NO_MEMORY;
-                }
+                status = getModelState(handle);
             }
             reply->writeInt32(status);
             return ret;
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index bb0650f..d1eb367 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -188,14 +188,13 @@
     return mISoundTrigger->stopRecognition(handle);
 }
 
-status_t SoundTrigger::getModelState(sound_model_handle_t handle,
-                                     sp<IMemory>& eventMemory)
+status_t SoundTrigger::getModelState(sound_model_handle_t handle)
 {
     Mutex::Autolock _l(mLock);
     if (mISoundTrigger == 0) {
         return NO_INIT;
     }
-    return mISoundTrigger->getModelState(handle, eventMemory);
+    return mISoundTrigger->getModelState(handle);
 }
 
 // BpSoundTriggerClient