Merge "audiohal: Check for EINTR and retry when waiting for EventFlag"
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
index 1548e64..f0a0db0 100644
--- a/camera/cameraserver/Android.mk
+++ b/camera/cameraserver/Android.mk
@@ -25,6 +25,7 @@
 	libutils \
 	libui \
 	libbinder \
+	libhidltransport \
 	android.hardware.camera.common@1.0 \
 	android.hardware.camera.provider@2.4 \
 	android.hardware.camera.device@1.0 \
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
index f4be468..3972436 100644
--- a/camera/cameraserver/main_cameraserver.cpp
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -17,8 +17,8 @@
 #define LOG_TAG "cameraserver"
 //#define LOG_NDEBUG 0
 
-// from LOCAL_C_INCLUDES
 #include "CameraService.h"
+#include <hidl/HidlTransportSupport.h>
 
 using namespace android;
 
@@ -26,6 +26,9 @@
 {
     signal(SIGPIPE, SIG_IGN);
 
+    // Set 3 threads for HIDL calls
+    hardware::configureRpcThreadpool(3, /*willjoin*/ false);
+
     sp<ProcessState> proc(ProcessState::self());
     sp<IServiceManager> sm = defaultServiceManager();
     ALOGI("ServiceManager: %p", sm.get());
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index ad70470..ff5e5d3 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -12,7 +12,6 @@
         libjpeg libgui libcutils liblog \
         libhidlmemory \
         android.hardware.media.omx@1.0 \
-        android.hardware.media.omx@1.0-utils \
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index ffa09eb..4d8dd3c 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -65,7 +65,7 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
-#include <omx/hal/1.0/utils/WOmx.h>
+#include <media/omx/1.0/WOmx.h>
 
 using namespace android;
 
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 7176582..a57fafa 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -7,13 +7,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_AIDL_INCLUDES := \
-    frameworks/base/media/java
+    frameworks/av/drm/libmediadrm/aidl
 
 LOCAL_SRC_FILES := \
-    ../../../base/media/java/android/media/ICas.aidl \
-    ../../../base/media/java/android/media/ICasListener.aidl \
-    ../../../base/media/java/android/media/IDescrambler.aidl \
-    ../../../base/media/java/android/media/IMediaCasService.aidl \
+    aidl/android/media/ICas.aidl \
+    aidl/android/media/ICasListener.aidl \
+    aidl/android/media/IDescrambler.aidl \
+    aidl/android/media/IMediaCasService.aidl \
 
 LOCAL_SRC_FILES += \
     CasImpl.cpp \
diff --git a/drm/libmediadrm/aidl/android/media/ICas.aidl b/drm/libmediadrm/aidl/android/media/ICas.aidl
new file mode 100644
index 0000000..6b2ce4a
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/ICas.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.MediaCas;
+
+/** @hide */
+interface ICas {
+    void setPrivateData(in byte[] pvtData);
+    byte[] openSession(int program_number);
+    byte[] openSessionForStream(int program_number, int elementary_PID);
+    void closeSession(in byte[] sessionId);
+    void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+    void processEcm(in byte[] sessionId, in MediaCas.ParcelableCasData ecm);
+    void processEmm(in MediaCas.ParcelableCasData emm);
+    void sendEvent(int event, int arg, in @nullable byte[] eventData);
+    void provision(String provisionString);
+    void refreshEntitlements(int refreshType, in @nullable byte[] refreshData);
+    void release();
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/ICasListener.aidl b/drm/libmediadrm/aidl/android/media/ICasListener.aidl
new file mode 100644
index 0000000..01a5abc
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/ICasListener.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/** @hide */
+interface ICasListener {
+    void onEvent(int event, int arg, in @nullable byte[] data);
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl b/drm/libmediadrm/aidl/android/media/IDescrambler.aidl
new file mode 100644
index 0000000..fdf99eb
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/IDescrambler.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.MediaDescrambler;
+
+/** @hide */
+interface IDescrambler {
+    void setMediaCasSession(in byte[] sessionId);
+    boolean requiresSecureDecoderComponent(String mime);
+    int descramble(in MediaDescrambler.DescrambleInfo descrambleInfo);
+    void release();
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl b/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl
new file mode 100644
index 0000000..44f6825
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.IDescrambler;
+import android.media.ICas;
+import android.media.ICasListener;
+import android.media.MediaCas;
+
+/** @hide */
+interface IMediaCasService {
+    MediaCas.ParcelableCasPluginDescriptor[] enumeratePlugins();
+    boolean isSystemIdSupported(int CA_system_id);
+    ICas createPlugin(int CA_system_id, ICasListener listener);
+    boolean isDescramblerSupported(int CA_system_id);
+    IDescrambler createDescrambler(int CA_system_id);
+}
+
diff --git a/drm/libmediadrm/aidl/android/media/MediaCas.aidl b/drm/libmediadrm/aidl/android/media/MediaCas.aidl
new file mode 100644
index 0000000..cb8d0c6
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/MediaCas.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/** @hide */
+parcelable MediaCas.ParcelableCasPluginDescriptor cpp_header "media/MediaCasDefs.h";
+
+/** @hide */
+parcelable MediaCas.ParcelableCasData cpp_header "media/MediaCasDefs.h";
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl b/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl
new file mode 100644
index 0000000..e789244
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/** @hide */
+parcelable MediaDescrambler.DescrambleInfo cpp_header "media/MediaCasDefs.h";
\ No newline at end of file
diff --git a/media/libstagefright/omx/hal/1.0/utils/Conversion.h b/include/media/omx/1.0/Conversion.h
similarity index 99%
rename from media/libstagefright/omx/hal/1.0/utils/Conversion.h
rename to include/media/omx/1.0/Conversion.h
index c4876ac..ee83713 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Conversion.h
+++ b/include/media/omx/1.0/Conversion.h
@@ -29,12 +29,12 @@
 #include <binder/Binder.h>
 #include <binder/Status.h>
 #include <ui/FenceTime.h>
-#include <media/OMXFenceParcelable.h>
 #include <cutils/native_handle.h>
 #include <gui/IGraphicBufferProducer.h>
 
+#include <media/OMXFenceParcelable.h>
 #include <media/OMXBuffer.h>
-#include <VideoAPI.h>
+#include <media/hardware/VideoAPI.h>
 
 #include <android/hidl/memory/1.0/IMemory.h>
 #include <android/hardware/media/omx/1.0/types.h>
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h b/include/media/omx/1.0/WGraphicBufferSource.h
similarity index 99%
rename from media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
rename to include/media/omx/1.0/WGraphicBufferSource.h
index 1090d52..7c80c2e 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
+++ b/include/media/omx/1.0/WGraphicBufferSource.h
@@ -20,8 +20,8 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <media/IOMX.h>
 #include <binder/Binder.h>
+#include <media/IOMX.h>
 
 #include <android/hardware/graphics/common/1.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmx.h b/include/media/omx/1.0/WOmx.h
similarity index 97%
rename from media/libstagefright/omx/hal/1.0/utils/WOmx.h
rename to include/media/omx/1.0/WOmx.h
index 7860f46..4aaf470 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmx.h
+++ b/include/media/omx/1.0/WOmx.h
@@ -20,7 +20,7 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include "../../../../include/OMXNodeInstance.h"
+#include <media/IOMX.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
 
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h b/include/media/omx/1.0/WOmxBufferProducer.h
similarity index 100%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
rename to include/media/omx/1.0/WOmxBufferProducer.h
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h b/include/media/omx/1.0/WOmxBufferSource.h
similarity index 98%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
rename to include/media/omx/1.0/WOmxBufferSource.h
index 086f648..86322da 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
+++ b/include/media/omx/1.0/WOmxBufferSource.h
@@ -21,7 +21,7 @@
 #include <hidl/Status.h>
 
 #include <binder/Binder.h>
-#include <media/OMXFenceParcelable.h>
+#include <OMXFenceParcelable.h>
 
 #include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <android/BnOMXBufferSource.h>
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h b/include/media/omx/1.0/WOmxNode.h
similarity index 96%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
rename to include/media/omx/1.0/WOmxNode.h
index 46dfb49..3176a65 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
+++ b/include/media/omx/1.0/WOmxNode.h
@@ -20,9 +20,9 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include <binder/HalToken.h>
 #include <utils/Errors.h>
-
-#include "../../../../include/OMXNodeInstance.h"
+#include <media/IOMX.h>
 
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -59,9 +59,8 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxNode : public BnOMXNode {
-    sp<IOmxNode> mBase;
-    LWOmxNode(sp<IOmxNode> const& base);
+struct LWOmxNode : public H2BConverter<IOmxNode, IOMXNode, BnOMXNode> {
+    LWOmxNode(sp<IOmxNode> const& base) : CBase(base) {}
     status_t freeNode() override;
     status_t sendCommand(
             OMX_COMMANDTYPE cmd, OMX_S32 param) override;
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h b/include/media/omx/1.0/WOmxObserver.h
similarity index 100%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
rename to include/media/omx/1.0/WOmxObserver.h
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h b/include/media/omx/1.0/WOmxProducerListener.h
similarity index 100%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
rename to include/media/omx/1.0/WOmxProducerListener.h
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 26cd4b5..5b06b73 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -315,6 +315,10 @@
             WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
             [&] (const WriteStatus& writeStatus) {
                 *written = writeStatus.reply.written;
+                // Diagnostics of the cause of b/35813113.
+                ALOGE_IF(*written > bytes,
+                        "hal reports more bytes written than asked for: %lld > %lld",
+                        (long long)*written, (long long)bytes);
             });
 }
 
@@ -328,8 +332,8 @@
     if (data != nullptr) {
         size_t availableToWrite = mDataMQ->availableToWrite();
         if (dataSize > availableToWrite) {
-            ALOGW("truncating write data from %d to %d due to insufficient data queue space",
-                    (int32_t)dataSize, (int32_t)availableToWrite);
+            ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
+                    (long long)dataSize, (long long)availableToWrite);
             dataSize = availableToWrite;
         }
         if (!mDataMQ->write(data, dataSize)) {
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index eac532b..c057cf5 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -55,15 +55,36 @@
     OMXBuffer.cpp \
     Visualizer.cpp \
     StringArray.cpp \
+    omx/1.0/WGraphicBufferSource.cpp \
+    omx/1.0/WOmx.cpp \
+    omx/1.0/WOmxBufferProducer.cpp \
+    omx/1.0/WOmxBufferSource.cpp \
+    omx/1.0/WOmxNode.cpp \
+    omx/1.0/WOmxObserver.cpp \
+    omx/1.0/WOmxProducerListener.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
         libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
         libcamera_client libstagefright_foundation \
         libgui libdl libaudioutils libaudioclient \
         libmedia_helper libmediadrm \
+        libbase \
         libhidlbase \
+        libhidltransport \
+        libhwbinder \
+        libhidlmemory \
+        android.hidl.base@1.0 \
+        android.hidl.memory@1.0 \
+        android.hardware.graphics.common@1.0 \
+        android.hardware.media@1.0 \
+        android.hardware.media.omx@1.0 \
 
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox libmediadrm
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
+        libbinder \
+        libsonivox \
+        libmediadrm \
+        android.hardware.media.omx@1.0 \
+        android.hidl.memory@1.0 \
 
 # for memory heap analysis
 LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
@@ -76,8 +97,9 @@
     $(TOP)/system/libhidl/base/include \
     $(TOP)/frameworks/native/include/media/openmax \
     $(TOP)/frameworks/av/include/media/ \
-    $(TOP)/frameworks/av/media/libstagefright \
     $(TOP)/frameworks/av/media/libmedia/aidl \
+    $(TOP)/frameworks/av/include \
+    $(TOP)/frameworks/native/include \
     $(call include-path-for, audio-utils)
 
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 7df3b65..31c85af 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -55,8 +55,16 @@
         data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
         data.writeInt64(offset);
         data.writeInt64(size);
-        remote()->transact(READ_AT, data, &reply);
-        return reply.readInt64();
+        status_t err = remote()->transact(READ_AT, data, &reply);
+        if (err != OK) {
+            return err;
+        }
+        int64_t value = 0;
+        err = reply.readInt64(&value);
+        if (err != OK) {
+            return err;
+        }
+        return (ssize_t)value;
     }
 
     virtual status_t getSize(off64_t* size) {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 67939b2..223ca6b 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -29,6 +29,7 @@
 #include <utils/NativeHandle.h>
 #include <gui/IGraphicBufferProducer.h>
 
+#include <omx/1.0/WOmxNode.h>
 #include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
 
@@ -448,8 +449,115 @@
     }
 };
 
+using ::android::hardware::media::omx::V1_0::utils::LWOmxNode;
+class HpOMXNode : public HpInterface<BpOMXNode, LWOmxNode> {
+public:
+    HpOMXNode(const sp<IBinder>& base) : PBase(base) {}
+
+    virtual status_t freeNode() {
+        return mBase->freeNode();
+    }
+
+    virtual status_t sendCommand(
+            OMX_COMMANDTYPE cmd, OMX_S32 param) {
+        return mBase->sendCommand(cmd, param);
+    }
+
+    virtual status_t getParameter(
+            OMX_INDEXTYPE index, void *params, size_t size) {
+        return mBase->getParameter(index, params, size);
+    }
+
+    virtual status_t setParameter(
+            OMX_INDEXTYPE index, const void *params, size_t size) {
+        return mBase->setParameter(index, params, size);
+    }
+
+    virtual status_t getConfig(
+            OMX_INDEXTYPE index, void *params, size_t size) {
+        return mBase->getConfig(index, params, size);
+    }
+
+    virtual status_t setConfig(
+            OMX_INDEXTYPE index, const void *params, size_t size) {
+        return mBase->setConfig(index, params, size);
+    }
+
+    virtual status_t setPortMode(
+            OMX_U32 port_index, IOMX::PortMode mode) {
+        return mBase->setPortMode(port_index, mode);
+    }
+
+    virtual status_t prepareForAdaptivePlayback(
+            OMX_U32 portIndex, OMX_BOOL enable,
+            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
+        return mBase->prepareForAdaptivePlayback(
+                portIndex, enable, maxFrameWidth, maxFrameHeight);
+    }
+
+    virtual status_t configureVideoTunnelMode(
+            OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
+        return mBase->configureVideoTunnelMode(
+                portIndex, tunneled, audioHwSync, sidebandHandle);
+    }
+
+    virtual status_t getGraphicBufferUsage(
+            OMX_U32 port_index, OMX_U32* usage) {
+        return mBase->getGraphicBufferUsage(port_index, usage);
+    }
+
+    virtual status_t setInputSurface(
+            const sp<IOMXBufferSource> &bufferSource) {
+        return mBase->setInputSurface(bufferSource);
+    }
+
+    virtual status_t allocateSecureBuffer(
+            OMX_U32 port_index, size_t size, buffer_id *buffer,
+            void **buffer_data, sp<NativeHandle> *native_handle) {
+        return mBase->allocateSecureBuffer(
+                port_index, size, buffer, buffer_data, native_handle);
+    }
+
+    virtual status_t useBuffer(
+            OMX_U32 port_index, const OMXBuffer &omxBuf, buffer_id *buffer) {
+        return mBase->useBuffer(port_index, omxBuf, buffer);
+    }
+
+    virtual status_t freeBuffer(
+            OMX_U32 port_index, buffer_id buffer) {
+        return mBase->freeBuffer(port_index, buffer);
+    }
+
+    virtual status_t fillBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd = -1) {
+        return mBase->fillBuffer(buffer, omxBuf, fenceFd);
+    }
+
+    virtual status_t emptyBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd = -1) {
+        return mBase->emptyBuffer(buffer, omxBuf, flags, timestamp, fenceFd);
+    }
+
+    virtual status_t getExtensionIndex(
+            const char *parameter_name,
+            OMX_INDEXTYPE *index) {
+        return mBase->getExtensionIndex(parameter_name, index);
+    }
+
+    virtual status_t dispatchMessage(const omx_message &msg) {
+        return mBase->dispatchMessage(msg);
+    }
+
+    // TODO: this is temporary, will be removed when quirks move to OMX side
+    virtual status_t setQuirks(OMX_U32 quirks) {
+        return mBase->setQuirks(quirks);
+    }
+};
+
 IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
-IMPLEMENT_META_INTERFACE(OMXNode, "android.hardware.IOMXNode");
+IMPLEMENT_HYBRID_META_INTERFACE(OMXNode, IOmxNode, "android.hardware.IOMXNode");
 
 ////////////////////////////////////////////////////////////////////////////////
 
diff --git a/media/libmedia/include/IMediaCodecService.h b/media/libmedia/include/IMediaCodecService.h
index 984a0fd..da3c5a03 100644
--- a/media/libmedia/include/IMediaCodecService.h
+++ b/media/libmedia/include/IMediaCodecService.h
@@ -21,7 +21,7 @@
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
 #include <media/IDataSource.h>
-#include <include/OMX.h>
+#include <media/IOMX.h>
 
 namespace android {
 
diff --git a/media/libmedia/include/IOMX.h b/media/libmedia/include/IOMX.h
index 39b9ad4..b4fc04c 100644
--- a/media/libmedia/include/IOMX.h
+++ b/media/libmedia/include/IOMX.h
@@ -19,6 +19,7 @@
 #define ANDROID_IOMX_H_
 
 #include <binder/IInterface.h>
+#include <binder/HalToken.h>
 #include <utils/List.h>
 #include <utils/String8.h>
 #include <cutils/native_handle.h>
@@ -26,6 +27,7 @@
 #include <list>
 
 #include <media/hardware/MetadataBufferType.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
 
 #include <OMX_Core.h>
 #include <OMX_Video.h>
@@ -42,6 +44,8 @@
 class OMXBuffer;
 struct omx_message;
 
+using hardware::media::omx::V1_0::IOmxNode;
+
 class IOMX : public IInterface {
 public:
     DECLARE_META_INTERFACE(OMX);
@@ -83,7 +87,7 @@
 
 class IOMXNode : public IInterface {
 public:
-    DECLARE_META_INTERFACE(OMXNode);
+    DECLARE_HYBRID_META_INTERFACE(OMXNode, IOmxNode);
 
     typedef IOMX::buffer_id buffer_id;
 
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
similarity index 93%
rename from media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
rename to media/libmedia/omx/1.0/WGraphicBufferSource.cpp
index 0ba6060..247c540 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
+++ b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
@@ -16,9 +16,9 @@
 
 #include <stagefright/foundation/ColorUtils.h>
 
-#include "WGraphicBufferSource.h"
-#include "WOmxNode.h"
-#include "Conversion.h"
+#include <media/omx/1.0/WGraphicBufferSource.h>
+#include <media/omx/1.0/WOmxNode.h>
+#include <media/omx/1.0/Conversion.h>
 
 namespace android {
 namespace hardware {
@@ -36,8 +36,10 @@
 
 ::android::binder::Status LWGraphicBufferSource::configure(
         const sp<IOMXNode>& omxNode, int32_t dataSpace) {
+    sp<IOmxNode> hOmxNode = omxNode->getHalInterface();
     return toBinderStatus(mBase->configure(
-            new TWOmxNode(omxNode), toHardwareDataspace(dataSpace)));
+            hOmxNode == nullptr ? new TWOmxNode(omxNode) : hOmxNode,
+            toHardwareDataspace(dataSpace)));
 }
 
 ::android::binder::Status LWGraphicBufferSource::setSuspend(
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmx.cpp b/media/libmedia/omx/1.0/WOmx.cpp
similarity index 93%
rename from media/libstagefright/omx/hal/1.0/utils/WOmx.cpp
rename to media/libmedia/omx/1.0/WOmx.cpp
index 00f40cd..39871f8 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmx.cpp
+++ b/media/libmedia/omx/1.0/WOmx.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include "WOmx.h"
-#include "WOmxNode.h"
-#include "WOmxObserver.h"
-#include "WOmxBufferProducer.h"
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
+#include <media/omx/1.0/WOmx.h>
+#include <media/omx/1.0/WOmxNode.h>
+#include <media/omx/1.0/WOmxObserver.h>
+#include <media/omx/1.0/WOmxBufferProducer.h>
+#include <media/omx/1.0/WGraphicBufferSource.h>
+#include <media/omx/1.0/Conversion.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp b/media/libmedia/omx/1.0/WOmxBufferProducer.cpp
similarity index 88%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
rename to media/libmedia/omx/1.0/WOmxBufferProducer.cpp
index e9a93b9..03499f2 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
+++ b/media/libmedia/omx/1.0/WOmxBufferProducer.cpp
@@ -16,11 +16,11 @@
 
 #define LOG_TAG "WOmxBufferProducer-utils"
 
-#include <android-base/logging.h>
+#include <utils/Log.h>
 
-#include "WOmxBufferProducer.h"
-#include "WOmxProducerListener.h"
-#include "Conversion.h"
+#include <media/omx/1.0/WOmxBufferProducer.h>
+#include <media/omx/1.0/WOmxProducerListener.h>
+#include <media/omx/1.0/Conversion.h>
 
 namespace android {
 namespace hardware {
@@ -72,8 +72,7 @@
 
     native_handle_t* nh = nullptr;
     if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
-        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
-                "Invalid output fence";
+        ALOGE("TWOmxBufferProducer::dequeueBuffer - Invalid output fence");
         _hidl_cb(toStatus(status),
                  static_cast<int32_t>(slot),
                  tFence,
@@ -82,8 +81,7 @@
     }
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
-        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
-                "Invalid output timestamps";
+        ALOGE("TWOmxBufferProducer::dequeueBuffer - Invalid output timestamps");
         _hidl_cb(toStatus(status),
                  static_cast<int32_t>(slot),
                  tFence,
@@ -120,16 +118,14 @@
     hidl_handle tFence;
 
     if (outBuffer == nullptr) {
-        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
-                "Invalid output buffer";
+        ALOGE("TWOmxBufferProducer::detachNextBuffer - Invalid output buffer");
         _hidl_cb(toStatus(status), tBuffer, tFence);
         return Void();
     }
     wrapAs(&tBuffer, *outBuffer);
     native_handle_t* nh = nullptr;
     if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
-        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
-                "Invalid output fence";
+        ALOGE("TWOmxBufferProducer::detachNextBuffer - Invalid output fence");
         _hidl_cb(toStatus(status), tBuffer, tFence);
         return Void();
     }
@@ -145,8 +141,8 @@
     int outSlot;
     sp<GraphicBuffer> lBuffer = new GraphicBuffer();
     if (!convertTo(lBuffer.get(), buffer)) {
-        LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
-                "Invalid input native window buffer";
+        ALOGE("TWOmxBufferProducer::attachBuffer - "
+                "Invalid input native window buffer");
         _hidl_cb(toStatus(BAD_VALUE), -1);
         return Void();
     }
@@ -166,8 +162,7 @@
             NATIVE_WINDOW_SCALING_MODE_FREEZE,
             0, ::android::Fence::NO_FENCE);
     if (!convertTo(&lInput, input)) {
-        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
-                "Invalid input";
+        ALOGE("TWOmxBufferProducer::queueBuffer - Invalid input");
         _hidl_cb(toStatus(BAD_VALUE), tOutput);
         return Void();
     }
@@ -177,8 +172,7 @@
 
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
-                "Invalid output";
+        ALOGE("TWOmxBufferProducer::queueBuffer - Invalid output");
         _hidl_cb(toStatus(BAD_VALUE), tOutput);
         return Void();
     }
@@ -196,8 +190,7 @@
         int32_t slot, const hidl_handle& fence) {
     sp<Fence> lFence = new Fence();
     if (!convertTo(lFence.get(), fence)) {
-        LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
-                "Invalid input fence";
+        ALOGE("TWOmxBufferProducer::cancelBuffer - Invalid input fence");
         return toStatus(BAD_VALUE);
     }
     return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
@@ -224,8 +217,7 @@
     QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        LOG(ERROR) << "TWOmxBufferProducer::connect - "
-                "Invalid output";
+        ALOGE("TWOmxBufferProducer::connect - Invalid output");
         _hidl_cb(toStatus(status), tOutput);
         return Void();
     }
@@ -300,8 +292,8 @@
     hidl_handle tOutFence;
     native_handle_t* nh = nullptr;
     if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
-        LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
-                "Invalid output fence";
+        ALOGE("TWOmxBufferProducer::getLastQueuedBuffer - "
+                "Invalid output fence");
         _hidl_cb(toStatus(status),
                 tOutBuffer,
                 tOutFence,
@@ -323,8 +315,8 @@
     FrameEventHistoryDelta tDelta;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tDelta, &nhAA, lDelta)) {
-        LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
-                "Invalid output frame timestamps";
+        ALOGE("TWOmxBufferProducer::getFrameTimestamps - "
+                "Invalid output frame timestamps");
         _hidl_cb(tDelta);
         return Void();
     }
@@ -392,13 +384,13 @@
                 fnStatus = toStatusT(status);
                 *slot = tSlot;
                 if (!convertTo(fence->get(), tFence)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
-                            "Invalid output fence";
+                    ALOGE("LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output fence");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (outTimestamps && !convertTo(outTimestamps, tTs)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
-                            "Invalid output timestamps";
+                    ALOGE("LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output timestamps");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -421,13 +413,13 @@
                     hidl_handle const& tFence) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(outFence->get(), tFence)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
-                            "Invalid output fence";
+                    ALOGE("LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output fence");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (!convertTo(outBuffer->get(), tBuffer)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
-                            "Invalid output buffer";
+                    ALOGE("LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output buffer");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -454,8 +446,7 @@
     IOmxBufferProducer::QueueBufferInput tInput;
     native_handle_t* nh;
     if (!wrapAs(&tInput, &nh, input)) {
-        LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
-                "Invalid input";
+        ALOGE("LWOmxBufferProducer::queueBuffer - Invalid input");
         return BAD_VALUE;
     }
     status_t fnStatus;
@@ -465,8 +456,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
-                            "Invalid output";
+                    ALOGE("LWOmxBufferProducer::queueBuffer - "
+                            "Invalid output");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -478,8 +469,7 @@
     hidl_handle tFence;
     native_handle_t* nh = nullptr;
     if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
-        LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
-                "Invalid input fence";
+        ALOGE("LWOmxBufferProducer::cancelBuffer - Invalid input fence");
         return BAD_VALUE;
     }
 
@@ -513,8 +503,7 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::connect - "
-                            "Invalid output";
+                    ALOGE("LWOmxBufferProducer::connect - Invalid output");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -579,14 +568,14 @@
                 fnStatus = toStatusT(status);
                 *outBuffer = new GraphicBuffer();
                 if (!convertTo(outBuffer->get(), buffer)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
-                            "Invalid output buffer";
+                    ALOGE("LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output buffer");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 *outFence = new Fence();
                 if (!convertTo(outFence->get(), fence)) {
-                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
-                            "Invalid output fence";
+                    ALOGE("LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output fence");
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 std::copy(transformMatrix.data(),
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp b/media/libmedia/omx/1.0/WOmxBufferSource.cpp
similarity index 96%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
rename to media/libmedia/omx/1.0/WOmxBufferSource.cpp
index fe565e6..7cca5bd 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
+++ b/media/libmedia/omx/1.0/WOmxBufferSource.cpp
@@ -16,8 +16,8 @@
 
 #include <utils/String8.h>
 
-#include "WOmxBufferSource.h"
-#include "Conversion.h"
+#include <media/omx/1.0/WOmxBufferSource.h>
+#include <media/omx/1.0/Conversion.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp b/media/libmedia/omx/1.0/WOmxNode.cpp
similarity index 98%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
rename to media/libmedia/omx/1.0/WOmxNode.cpp
index df191c7..b5186b5 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
+++ b/media/libmedia/omx/1.0/WOmxNode.cpp
@@ -16,9 +16,9 @@
 
 #include <algorithm>
 
-#include "WOmxNode.h"
-#include "WOmxBufferSource.h"
-#include "Conversion.h"
+#include <media/omx/1.0/WOmxNode.h>
+#include <media/omx/1.0/WOmxBufferSource.h>
+#include <media/omx/1.0/Conversion.h>
 
 namespace android {
 namespace hardware {
@@ -30,9 +30,6 @@
 using ::android::hardware::Void;
 
 // LWOmxNode
-LWOmxNode::LWOmxNode(sp<IOmxNode> const& base) : mBase(base) {
-}
-
 status_t LWOmxNode::freeNode() {
     return toStatusT(mBase->freeNode());
 }
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp b/media/libmedia/omx/1.0/WOmxObserver.cpp
similarity index 92%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
rename to media/libmedia/omx/1.0/WOmxObserver.cpp
index 05ec37e..fa0407f 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
+++ b/media/libmedia/omx/1.0/WOmxObserver.cpp
@@ -18,12 +18,12 @@
 
 #include <vector>
 
-#include <android-base/logging.h>
+#include <utils/Log.h>
 #include <cutils/native_handle.h>
 #include <binder/Binder.h>
 
-#include "WOmxObserver.h"
-#include "Conversion.h"
+#include <media/omx/1.0/WOmxObserver.h>
+#include <media/omx/1.0/Conversion.h>
 
 namespace android {
 namespace hardware {
@@ -47,7 +47,7 @@
     }
     auto transResult = mBase->onMessages(tMessages);
     if (!transResult.isOk()) {
-        LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
+        ALOGE("LWOmxObserver::onMessages - Transaction failed");
     }
     for (auto& handle : handles) {
         native_handle_close(handle);
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp b/media/libmedia/omx/1.0/WOmxProducerListener.cpp
similarity index 96%
rename from media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp
rename to media/libmedia/omx/1.0/WOmxProducerListener.cpp
index 80b0f71..3ee381f 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp
+++ b/media/libmedia/omx/1.0/WOmxProducerListener.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "WOmxProducerListener.h"
+#include <media/omx/1.0/WOmxProducerListener.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 05e6201..ad4c223 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -258,7 +258,11 @@
 }
 
 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
-    return mLiveSession->seekTo(seekTimeUs, mode);
+    if (mLiveSession->isSeekable()) {
+        return mLiveSession->seekTo(seekTimeUs, mode);
+    } else {
+        return INVALID_OPERATION;
+    }
 }
 
 void NuPlayer::HTTPLiveSource::pollForRawData(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index abea5bc..3b2a8a1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -206,9 +206,11 @@
 
 status_t NuPlayerDriver::getDefaultBufferingSettings(BufferingSettings* buffering) {
     ALOGV("getDefaultBufferingSettings(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-    if (mState == STATE_IDLE) {
-        return INVALID_OPERATION;
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mState == STATE_IDLE) {
+            return INVALID_OPERATION;
+        }
     }
 
     return mPlayer->getDefaultBufferingSettings(buffering);
@@ -216,9 +218,11 @@
 
 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
     ALOGV("setBufferingSettings(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-    if (mState == STATE_IDLE) {
-        return INVALID_OPERATION;
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mState == STATE_IDLE) {
+            return INVALID_OPERATION;
+        }
     }
 
     return mPlayer->setBufferingSettings(buffering);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 78f28ae..81eecaf 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -45,6 +45,7 @@
 #include <media/stagefright/SurfaceUtils.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/OMXBuffer.h>
+#include <media/omx/1.0/WOmxNode.h>
 
 #include <hidlmemory/mapping.h>
 
@@ -63,7 +64,6 @@
 
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
-#include "omx/hal/1.0/utils/WOmxNode.h"
 
 namespace android {
 
@@ -6133,10 +6133,7 @@
     if (mDeathNotifier != NULL) {
         if (mCodec->mOMXNode != NULL) {
             if (mCodec->getTrebleFlag()) {
-                auto tOmxNode =
-                        (static_cast<
-                        ::android::hardware::media::omx::V1_0::utils::
-                        LWOmxNode*>(mCodec->mOMXNode.get()))->mBase;
+                auto tOmxNode = mCodec->mOMXNode->getHalInterface();
                 tOmxNode->unlinkToDeath(mDeathNotifier);
             } else {
                 sp<IBinder> binder = IInterface::asBinder(mCodec->mOMXNode);
@@ -6304,8 +6301,7 @@
 
     mDeathNotifier = new DeathNotifier(notify);
     if (mCodec->getTrebleFlag()) {
-        auto tOmxNode = (static_cast<::android::hardware::media::omx::V1_0::
-                utils::LWOmxNode*>(omxNode.get()))->mBase;
+        auto tOmxNode = omxNode->getHalInterface();
         if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
             mDeathNotifier.clear();
         }
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 296394b..259e134 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -20,6 +20,7 @@
 
 #include <numeric>
 
+#include <android/media/IDescrambler.h>
 #include <binder/MemoryDealer.h>
 #include <media/openmax/OMX_Core.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -33,7 +34,8 @@
 #include "include/SharedMemoryBuffer.h"
 
 namespace android {
-
+using binder::Status;
+using MediaDescrambler::DescrambleInfo;
 using BufferInfo = ACodecBufferChannel::BufferInfo;
 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
 
@@ -92,7 +94,7 @@
         const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
         AString *errorDetailMsg) {
-    if (mCrypto == nullptr) {
+    if (!hasCryptoOrDescrambler()) {
         return -ENOSYS;
     }
     std::shared_ptr<const std::vector<const BufferInfo>> array(
@@ -116,9 +118,47 @@
         destination.mType = ICrypto::kDestinationTypeSharedMemory;
         destination.mSharedMemory = mDecryptDestination;
     }
-    ssize_t result = mCrypto->decrypt(key, iv, mode, pattern,
-            it->mSharedEncryptedBuffer, it->mClientBuffer->offset(),
-            subSamples, numSubSamples, destination, errorDetailMsg);
+
+    ssize_t result = -1;
+    if (mCrypto != NULL) {
+        result = mCrypto->decrypt(key, iv, mode, pattern,
+                    it->mSharedEncryptedBuffer, it->mClientBuffer->offset(),
+                    subSamples, numSubSamples, destination, errorDetailMsg);
+    } else {
+        DescrambleInfo descrambleInfo;
+        descrambleInfo.dstType = destination.mType ==
+                ICrypto::kDestinationTypeSharedMemory ?
+                DescrambleInfo::kDestinationTypeVmPointer :
+                DescrambleInfo::kDestinationTypeNativeHandle;
+        descrambleInfo.scramblingControl = key != NULL ?
+                (DescramblerPlugin::ScramblingControl)key[0] :
+                DescramblerPlugin::kScrambling_Unscrambled;
+        descrambleInfo.numSubSamples = numSubSamples;
+        descrambleInfo.subSamples = (DescramblerPlugin::SubSample *)subSamples;
+        descrambleInfo.srcMem = it->mSharedEncryptedBuffer;
+        descrambleInfo.srcOffset = 0;
+        descrambleInfo.dstPtr = NULL;
+        descrambleInfo.dstOffset = 0;
+
+        int32_t descrambleResult = -1;
+        Status status = mDescrambler->descramble(descrambleInfo, &descrambleResult);
+
+        if (status.isOk()) {
+            result = descrambleResult;
+        }
+
+        if (result < 0) {
+            ALOGE("descramble failed, exceptionCode=%d, err=%d, result=%zd",
+                    status.exceptionCode(), status.transactionError(), result);
+        } else {
+            ALOGV("descramble succeeded, result=%zd", result);
+        }
+
+        if (result > 0 && destination.mType == ICrypto::kDestinationTypeSharedMemory) {
+            memcpy(destination.mSharedMemory->pointer(),
+                    (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
+        }
+    }
 
     if (result < 0) {
         return result;
@@ -212,8 +252,7 @@
 }
 
 void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
-    bool secure = (mCrypto != nullptr);
-    if (secure) {
+    if (hasCryptoOrDescrambler()) {
         size_t totalSize = std::accumulate(
                 array.begin(), array.end(), 0u,
                 [alignment = MemoryDealer::getAllocationAlignment()]
@@ -232,7 +271,7 @@
     std::vector<const BufferInfo> inputBuffers;
     for (const BufferAndId &elem : array) {
         sp<IMemory> sharedEncryptedBuffer;
-        if (secure) {
+        if (hasCryptoOrDescrambler()) {
             sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
         }
         inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 140ceb1..18cfc0e 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -120,7 +120,6 @@
         android.hidl.allocator@1.0 \
         android.hidl.memory@1.0 \
         android.hardware.media.omx@1.0 \
-        android.hardware.media.omx@1.0-utils \
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
 
@@ -131,7 +130,8 @@
 LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
 endif
 
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_MODULE:= libstagefright
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 70916dc..a017737 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -72,6 +72,7 @@
                 Vector<SidxEntry> &sidx,
                 const Trex *trex,
                 off64_t firstMoofOffset);
+    virtual status_t init();
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -2175,7 +2176,10 @@
             *offset += chunk_size;
 
             if (underQTMetaPath(mPath, 3)) {
-                parseQTMetaKey(data_offset, chunk_data_size);
+                status_t err = parseQTMetaKey(data_offset, chunk_data_size);
+                if (err != OK) {
+                    return err;
+                }
             }
             break;
         }
@@ -2334,7 +2338,10 @@
 
         case FOURCC('s', 'i', 'd', 'x'):
         {
-            parseSegmentIndex(data_offset, chunk_data_size);
+            status_t err = parseSegmentIndex(data_offset, chunk_data_size);
+            if (err != OK) {
+                return err;
+            }
             *offset += chunk_size;
             return UNKNOWN_ERROR; // stop parsing after sidx
         }
@@ -2382,7 +2389,10 @@
             // check if we're parsing 'ilst' for meta keys
             // if so, treat type as a number (key-id).
             if (underQTMetaPath(mPath, 3)) {
-                parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
+                status_t err = parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
+                if (err != OK) {
+                    return err;
+                }
             }
 
             *offset += chunk_size;
@@ -3302,9 +3312,13 @@
         }
     }
 
-    return new MPEG4Source(this,
+    sp<MPEG4Source> source =  new MPEG4Source(this,
             track->meta, mDataSource, track->timescale, track->sampleTable,
             mSidxEntries, trex, mMoofOffset);
+    if (source->init() != OK) {
+        return NULL;
+    }
+    return source;
 }
 
 // static
@@ -3701,6 +3715,7 @@
       mTrex(trex),
       mFirstMoofOffset(firstMoofOffset),
       mCurrentMoofOffset(firstMoofOffset),
+      mNextMoofOffset(-1),
       mCurrentTime(0),
       mCurrentSampleInfoAllocSize(0),
       mCurrentSampleInfoSizes(NULL),
@@ -3765,10 +3780,14 @@
 
     CHECK(format->findInt32(kKeyTrackID, &mTrackId));
 
+}
+
+status_t MPEG4Source::init() {
     if (mFirstMoofOffset != 0) {
         off64_t offset = mFirstMoofOffset;
-        parseChunk(&offset);
+        return parseChunk(&offset);
     }
+    return OK;
 }
 
 MPEG4Source::~MPEG4Source() {
@@ -3899,9 +3918,30 @@
                     }
                     chunk_size = ntohl(hdr[0]);
                     chunk_type = ntohl(hdr[1]);
+                    if (chunk_size == 1) {
+                        // ISO/IEC 14496-12:2012, 8.8.4 Movie Fragment Box, moof is a Box
+                        // which is defined in 4.2 Object Structure.
+                        // When chunk_size==1, 8 bytes follows as "largesize".
+                        if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
+                            return ERROR_IO;
+                        }
+                        chunk_size = ntoh64(chunk_size);
+                        if (chunk_size < 16) {
+                            // The smallest valid chunk is 16 bytes long in this case.
+                            return ERROR_MALFORMED;
+                        }
+                    } else if (chunk_size == 0) {
+                        // next box extends to end of file.
+                    } else if (chunk_size < 8) {
+                        // The smallest valid chunk is 8 bytes long in this case.
+                        return ERROR_MALFORMED;
+                    }
+
                     if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
                         mNextMoofOffset = *offset;
                         break;
+                    } else if (chunk_size == 0) {
+                        break;
                     }
                     *offset += chunk_size;
                 }
@@ -4785,17 +4825,25 @@
                 totalOffset += se->mSize;
             }
             mCurrentMoofOffset = totalOffset;
+            mNextMoofOffset = -1;
             mCurrentSamples.clear();
             mCurrentSampleIndex = 0;
-            parseChunk(&totalOffset);
+            status_t err = parseChunk(&totalOffset);
+            if (err != OK) {
+                return err;
+            }
             mCurrentTime = totalTime * mTimescale / 1000000ll;
         } else {
             // without sidx boxes, we can only seek to 0
             mCurrentMoofOffset = mFirstMoofOffset;
+            mNextMoofOffset = -1;
             mCurrentSamples.clear();
             mCurrentSampleIndex = 0;
             off64_t tmp = mCurrentMoofOffset;
-            parseChunk(&tmp);
+            status_t err = parseChunk(&tmp);
+            if (err != OK) {
+                return err;
+            }
             mCurrentTime = 0;
         }
 
@@ -4824,7 +4872,10 @@
             mCurrentMoofOffset = nextMoof;
             mCurrentSamples.clear();
             mCurrentSampleIndex = 0;
-            parseChunk(&nextMoof);
+            status_t err = parseChunk(&nextMoof);
+            if (err != OK) {
+                return err;
+            }
             if (mCurrentSampleIndex >= mCurrentSamples.size()) {
                 return ERROR_END_OF_STREAM;
             }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index d46ef3c..cafedba 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -3669,11 +3669,19 @@
 
     mOwner->beginBox("ctts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    uint32_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
+    int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
     mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
         // entries are <count, ctts> pairs; adjust only ctts
         uint32_t duration = htonl(value[1]); // back to host byte order
-        value[1] = htonl(duration - delta);
+        // Prevent overflow and underflow
+        if (delta > duration) {
+            duration = 0;
+        } else if (delta < 0 && UINT32_MAX + delta < duration) {
+            duration = UINT32_MAX;
+        } else {
+            duration -= delta;
+        }
+        value[1] = htonl(duration);
     });
     mCttsTableEntries->write(mOwner);
     mOwner->endBox();  // ctts
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 6674e2c..8728b6f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2012,6 +2012,7 @@
             }
 
             mDescrambler = static_cast<IDescrambler *>(descrambler);
+            mBufferChannel->setDescrambler(mDescrambler);
 
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -2033,7 +2034,6 @@
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             status_t err = OK;
-            sp<Surface> surface;
 
             switch (mState) {
                 case CONFIGURED:
@@ -2718,7 +2718,7 @@
     CryptoPlugin::Pattern pattern;
 
     if (msg->findSize("size", &size)) {
-        if (mCrypto != NULL) {
+        if (hasCryptoOrDescrambler()) {
             ss.mNumBytesOfClearData = size;
             ss.mNumBytesOfEncryptedData = 0;
 
@@ -2730,7 +2730,9 @@
             pattern.mSkipBlocks = 0;
         }
     } else {
-        if (mCrypto == NULL) {
+        if (!hasCryptoOrDescrambler()) {
+            ALOGE("[%s] queuing secure buffer without mCrypto or mDescrambler!",
+                    mComponentName.c_str());
             return -EINVAL;
         }
 
@@ -2779,7 +2781,7 @@
 
     sp<MediaCodecBuffer> buffer = info->mData;
     status_t err = OK;
-    if (mCrypto != NULL) {
+    if (hasCryptoOrDescrambler()) {
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index b77ee1d..1706221 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -28,9 +28,9 @@
 #include <media/IMediaCodecService.h>
 #include <media/stagefright/OMXClient.h>
 
-#include "include/OMX.h"
+#include <media/IOMX.h>
 
-#include "omx/hal/1.0/utils/WOmx.h"
+#include <media/omx/1.0/WOmx.h>
 
 namespace android {
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ec02fb9..e8c46e3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -610,6 +610,22 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (meta->findData(kKeyCas, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        msg->setBuffer("cas", buffer);
+        memcpy(buffer->data(), data, size);
+    }
+
+    if (!strncasecmp("video/scrambled", mime, 15)
+            || !strncasecmp("audio/scrambled", mime, 15)) {
+
+        *format = msg;
+        return OK;
+    }
+
     int64_t durationUs;
     if (meta->findInt64(kKeyDuration, &durationUs)) {
         msg->setInt64("durationUs", durationUs);
@@ -759,9 +775,6 @@
         msg->setInt32("frame-rate", fps);
     }
 
-    uint32_t type;
-    const void *data;
-    size_t size;
     if (meta->findData(kKeyAVCC, &type, &data, &size)) {
         // Parse the AVCDecoderConfigurationRecord
 
diff --git a/media/libstagefright/codecs/aacenc/src/dyn_bits.c b/media/libstagefright/codecs/aacenc/src/dyn_bits.c
index 4d763d0..e75b48f 100644
--- a/media/libstagefright/codecs/aacenc/src/dyn_bits.c
+++ b/media/libstagefright/codecs/aacenc/src/dyn_bits.c
@@ -20,6 +20,10 @@
 
 *******************************************************************************/
 
+#define LOG_TAG "NoiselessCoder"
+
+#include "log/log.h"
+
 #include "aac_rom.h"
 #include "dyn_bits.h"
 #include "bit_cnt.h"
@@ -296,6 +300,9 @@
     case SHORT_WINDOW:
       sideInfoTab = sideInfoTabShort;
       break;
+    default:
+      ALOGE("invalid blockType: %d", blockType);
+      return;
   }
 
 
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index 1e82727..1e7a4cc 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -17,7 +17,8 @@
         libyuv_static \
 
 LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_MODULE:= libstagefright_color_conversion
 
diff --git a/media/libstagefright/filters/Android.mk b/media/libstagefright/filters/Android.mk
index 07b2eb8..d4ecfcc 100644
--- a/media/libstagefright/filters/Android.mk
+++ b/media/libstagefright/filters/Android.mk
@@ -29,4 +29,7 @@
 
 LOCAL_MODULE:= libstagefright_mediafilter
 
+LOCAL_SANITIZE := cfi
+LOCAL_SANITIZE_DIAG := cfi
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 19ada73..827703e 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -5,7 +5,8 @@
 	ID3.cpp
 
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SHARED_LIBRARIES := libmedia
 
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index ce9bd3c..02468c1 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -126,6 +126,10 @@
     // the caller has given up the reference, so that access is also safe.
     std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
     std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
+
+    bool hasCryptoOrDescrambler() {
+        return mCrypto != NULL || mDescrambler != NULL;
+    }
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/CodecBase.h b/media/libstagefright/include/CodecBase.h
index cfbaea4..845146d 100644
--- a/media/libstagefright/include/CodecBase.h
+++ b/media/libstagefright/include/CodecBase.h
@@ -35,9 +35,10 @@
 #include <utils/NativeHandle.h>
 
 #include <system/graphics.h>
+#include <android/media/IDescrambler.h>
 
 namespace android {
-
+using namespace media;
 class BufferChannelBase;
 class BufferProducerWrapper;
 class MediaCodecBuffer;
@@ -259,6 +260,10 @@
         mCrypto = crypto;
     }
 
+    inline void setDescrambler(const sp<IDescrambler> &descrambler) {
+        mDescrambler = descrambler;
+    }
+
     /**
      * Queue an input buffer into the buffer channel.
      *
@@ -317,6 +322,7 @@
 protected:
     std::unique_ptr<CodecBase::BufferCallback> mCallback;
     sp<ICrypto> mCrypto;
+    sp<IDescrambler> mDescrambler;
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index ef55620..2a75298f 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -45,6 +45,8 @@
 
     virtual sp<MetaData> getMetaData();
 
+    virtual status_t setMediaCas(const sp<ICas> &cas) override;
+
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG2TSExtractor"; }
 
@@ -70,7 +72,10 @@
 
     off64_t mOffset;
 
+    static bool isScrambledFormat(const sp<MetaData> &format);
+
     void init();
+    void addSource(const sp<AnotherPacketSource> &impl);
     // Try to feed more data from source to parser.
     // |isInit| means this function is called inside init(). This is a signal to
     // save SyncEvent so that init() can add SyncPoint after it updates |mSourceImpls|.
diff --git a/media/libstagefright/include/MediaCodec.h b/media/libstagefright/include/MediaCodec.h
index fd3ff26..30454dc 100644
--- a/media/libstagefright/include/MediaCodec.h
+++ b/media/libstagefright/include/MediaCodec.h
@@ -401,6 +401,10 @@
     status_t connectToSurface(const sp<Surface> &surface);
     status_t disconnectFromSurface();
 
+    bool hasCryptoOrDescrambler() {
+        return mCrypto != NULL || mDescrambler != NULL;
+    }
+
     void postActivityNotificationIfPossible();
 
     void onInputBufferAvailable();
diff --git a/media/libstagefright/include/MetaData.h b/media/libstagefright/include/MetaData.h
index 6ba7b32..214f4ff 100644
--- a/media/libstagefright/include/MetaData.h
+++ b/media/libstagefright/include/MetaData.h
@@ -176,6 +176,7 @@
     kKeyCryptoDefaultIVSize = 'cryS',  // int32_t
 
     kKeyPssh              = 'pssh',  // raw data
+    kKeyCas               = ' cas',
 
     // Please see MediaFormat.KEY_IS_AUTOSELECT.
     kKeyTrackIsAutoselect = 'auto', // bool (int32_t)
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 7dd0863..7de5dbe 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -10,7 +10,8 @@
         $(TOP)/frameworks/av/media/libstagefright/include \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SHARED_LIBRARIES := libmedia
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 4975d9a..47caf61 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -17,13 +17,14 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ATSParser"
 #include <utils/Log.h>
-
 #include "ATSParser.h"
-
 #include "AnotherPacketSource.h"
+#include "CasManager.h"
 #include "ESQueue.h"
 #include "include/avc_utils.h"
 
+#include <android/media/IDescrambler.h>
+#include <binder/MemoryDealer.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -40,6 +41,8 @@
 #include <inttypes.h>
 
 namespace android {
+using binder::Status;
+using MediaDescrambler::DescrambleInfo;
 
 // I want the expression "y" evaluated even if verbose logging is off.
 #define MY_LOGV(x, y) \
@@ -60,6 +63,8 @@
     bool parsePID(
             unsigned pid, unsigned continuity_counter,
             unsigned payload_unit_start_indicator,
+            unsigned transport_scrambling_control,
+            unsigned random_access_indicator,
             ABitReader *br, status_t *err, SyncEvent *event);
 
     void signalDiscontinuity(
@@ -90,14 +95,21 @@
         return mParser->mFlags;
     }
 
+    sp<CasManager> casManager() const {
+        return mParser->mCasManager;
+    }
+
     uint64_t firstPTS() const {
         return mFirstPTS;
     }
 
+    void updateCasSessions();
+
 private:
     struct StreamInfo {
         unsigned mType;
         unsigned mPID;
+        int32_t mCASystemId;
     };
 
     ATSParser *mParser;
@@ -110,6 +122,8 @@
 
     status_t parseProgramMap(ABitReader *br);
     int64_t recoverPTS(uint64_t PTS_33bit);
+    bool findCADescriptor(
+            ABitReader *br, unsigned infoLength, CADescriptor *caDescriptor);
     bool switchPIDs(const Vector<StreamInfo> &infos);
 
     DISALLOW_EVIL_CONSTRUCTORS(Program);
@@ -119,18 +133,25 @@
     Stream(Program *program,
            unsigned elementaryPID,
            unsigned streamType,
-           unsigned PCR_PID);
+           unsigned PCR_PID,
+           int32_t CA_system_ID);
 
     unsigned type() const { return mStreamType; }
     unsigned pid() const { return mElementaryPID; }
     void setPID(unsigned pid) { mElementaryPID = pid; }
 
+    void setCasSession(
+            const sp<IDescrambler> &descrambler,
+            const std::vector<uint8_t> &sessionId);
+
     // Parse the payload and set event when PES with a sync frame is detected.
     // This method knows when a PES starts; so record mPesStartOffsets in that
     // case.
     status_t parse(
             unsigned continuity_counter,
             unsigned payload_unit_start_indicator,
+            unsigned transport_scrambling_control,
+            unsigned random_access_indicator,
             ABitReader *br,
             SyncEvent *event);
 
@@ -150,6 +171,11 @@
     virtual ~Stream();
 
 private:
+    struct SubSampleInfo {
+        size_t subSampleSize;
+        unsigned transport_scrambling_mode;
+        unsigned random_access_indicator;
+    };
     Program *mProgram;
     unsigned mElementaryPID;
     unsigned mStreamType;
@@ -166,10 +192,26 @@
 
     ElementaryStreamQueue *mQueue;
 
+    bool mScrambled;
+    sp<IMemory> mMem;
+    sp<MemoryDealer> mDealer;
+    sp<ABuffer> mDescrambledBuffer;
+    List<SubSampleInfo> mSubSamples;
+    sp<IDescrambler> mDescrambler;
+
     // Flush accumulated payload if necessary --- i.e. at EOS or at the start of
     // another payload. event is set if the flushed payload is PES with a sync
     // frame.
     status_t flush(SyncEvent *event);
+
+    // Flush accumulated payload for scrambled streams if necessary --- i.e. at
+    // EOS or at the start of another payload. event is set if the flushed
+    // payload is PES with a sync frame.
+    status_t flushScrambled(SyncEvent *event);
+
+    // Check if a PES packet is scrambled at PES level.
+    uint32_t getPesScramblingControl(ABitReader *br, int32_t *pesOffset);
+
     // Strip and parse PES headers and pass remaining payload into onPayload
     // with parsed metadata. event is set if the PES contains a sync frame.
     status_t parsePES(ABitReader *br, SyncEvent *event);
@@ -179,7 +221,13 @@
     // and timestamp of the packet.
     void onPayloadData(
             unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
-            const uint8_t *data, size_t size, SyncEvent *event);
+            unsigned PES_scrambling_control,
+            const uint8_t *data, size_t size,
+            int32_t payloadOffset, SyncEvent *event);
+
+    // Ensure internal buffers can hold specified size, and will re-allocate
+    // as needed.
+    void ensureBufferCapacity(size_t size);
 
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
@@ -254,6 +302,8 @@
 bool ATSParser::Program::parsePID(
         unsigned pid, unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
         ABitReader *br, status_t *err, SyncEvent *event) {
     *err = OK;
 
@@ -263,7 +313,11 @@
     }
 
     *err = mStreams.editValueAt(index)->parse(
-            continuity_counter, payload_unit_start_indicator, br, event);
+            continuity_counter,
+            payload_unit_start_indicator,
+            transport_scrambling_control,
+            random_access_indicator,
+            br, event);
 
     return true;
 }
@@ -359,6 +413,38 @@
     return success;
 }
 
+bool ATSParser::Program::findCADescriptor(
+        ABitReader *br, unsigned infoLength,
+        ATSParser::CADescriptor *caDescriptor) {
+    bool found = false;
+    while (infoLength > 2) {
+        unsigned descriptor_tag = br->getBits(8);
+        ALOGV("      tag = 0x%02x", descriptor_tag);
+
+        unsigned descriptor_length = br->getBits(8);
+        ALOGV("      len = %u", descriptor_length);
+
+        infoLength -= 2;
+        if (descriptor_length > infoLength) {
+            break;
+        }
+        if (descriptor_tag == 9 && descriptor_length >= 4) {
+            found = true;
+            caDescriptor->mSystemID = br->getBits(16);
+            caDescriptor->mPID = br->getBits(16) & 0x1fff;
+            infoLength -= 4;
+            caDescriptor->mPrivateData.assign(
+                    br->data(), br->data() + descriptor_length - 4);
+            break;
+        } else {
+            infoLength -= descriptor_length;
+            br->skipBits(descriptor_length * 8);
+        }
+    }
+    br->skipBits(infoLength * 8);
+    return found;
+}
+
 status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
     unsigned table_id = br->getBits(8);
     ALOGV("  table_id = %u", table_id);
@@ -395,7 +481,13 @@
     unsigned program_info_length = br->getBits(12);
     ALOGV("  program_info_length = %u", program_info_length);
 
-    br->skipBits(program_info_length * 8);  // skip descriptors
+    // descriptors
+    CADescriptor programCA;
+    bool hasProgramCA = findCADescriptor(br, program_info_length, &programCA);
+    if (hasProgramCA && !mParser->mCasManager->addProgram(
+            mProgramNumber, programCA)) {
+        return ERROR_MALFORMED;
+    }
 
     Vector<StreamInfo> infos;
 
@@ -419,28 +511,17 @@
         unsigned ES_info_length = br->getBits(12);
         ALOGV("    ES_info_length = %u", ES_info_length);
 
-#if 0
-        br->skipBits(ES_info_length * 8);  // skip descriptors
-#else
-        unsigned info_bytes_remaining = ES_info_length;
-        while (info_bytes_remaining >= 2) {
-            MY_LOGV("      tag = 0x%02x", br->getBits(8));
-
-            unsigned descLength = br->getBits(8);
-            ALOGV("      len = %u", descLength);
-
-            if (info_bytes_remaining < descLength) {
-                return ERROR_MALFORMED;
-            }
-            br->skipBits(descLength * 8);
-
-            info_bytes_remaining -= descLength + 2;
+        CADescriptor streamCA;
+        bool hasStreamCA = findCADescriptor(br, ES_info_length, &streamCA);
+        if (hasStreamCA && !mParser->mCasManager->addStream(
+                mProgramNumber, elementaryPID, streamCA)) {
+            return ERROR_MALFORMED;
         }
-#endif
-
         StreamInfo info;
         info.mType = streamType;
         info.mPID = elementaryPID;
+        info.mCASystemId = hasProgramCA ? programCA.mSystemID :
+                           hasStreamCA ? streamCA.mSystemID  : -1;
         infos.push(info);
 
         infoBytesRemaining -= 5 + ES_info_length;
@@ -490,19 +571,29 @@
         }
     }
 
+    bool isAddingScrambledStream = false;
     for (size_t i = 0; i < infos.size(); ++i) {
         StreamInfo &info = infos.editItemAt(i);
 
+        if (mParser->mCasManager->isCAPid(info.mPID)) {
+            // skip CA streams (EMM/ECM)
+            continue;
+        }
         ssize_t index = mStreams.indexOfKey(info.mPID);
 
         if (index < 0) {
             sp<Stream> stream = new Stream(
-                    this, info.mPID, info.mType, PCR_PID);
+                    this, info.mPID, info.mType, PCR_PID, info.mCASystemId);
 
+            isAddingScrambledStream |= info.mCASystemId >= 0;
             mStreams.add(info.mPID, stream);
         }
     }
 
+    if (isAddingScrambledStream) {
+        ALOGI("Receiving scrambled streams without descrambler!");
+        return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED;
+    }
     return OK;
 }
 
@@ -586,13 +677,27 @@
     return timeUs;
 }
 
+void ATSParser::Program::updateCasSessions() {
+    for (size_t i = 0; i < mStreams.size(); ++i) {
+        sp<Stream> &stream = mStreams.editValueAt(i);
+        sp<IDescrambler> descrambler;
+        std::vector<uint8_t> sessionId;
+        if (mParser->mCasManager->getCasSession(
+                mProgramNumber, stream->pid(), &descrambler, &sessionId)) {
+            stream->setCasSession(descrambler, sessionId);
+        }
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
+static const size_t kInitialStreamBufferSize = 192 * 1024;
 
 ATSParser::Stream::Stream(
         Program *program,
         unsigned elementaryPID,
         unsigned streamType,
-        unsigned PCR_PID)
+        unsigned PCR_PID,
+        int32_t CA_system_ID)
     : mProgram(program),
       mElementaryPID(elementaryPID),
       mStreamType(streamType),
@@ -601,54 +706,71 @@
       mPayloadStarted(false),
       mEOSReached(false),
       mPrevPTS(0),
-      mQueue(NULL) {
+      mQueue(NULL),
+      mScrambled(CA_system_ID >= 0) {
+    ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d",
+            elementaryPID, streamType, mScrambled);
+
+    uint32_t flags = (isVideo() && mScrambled) ?
+            ElementaryStreamQueue::kFlag_ScrambledData : 0;
+
+    ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;
+
     switch (mStreamType) {
         case STREAMTYPE_H264:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::H264,
-                    (mProgram->parserFlags() & ALIGNED_VIDEO_DATA)
-                        ? ElementaryStreamQueue::kFlag_AlignedData : 0);
+            mode = ElementaryStreamQueue::H264;
+            flags |= (mProgram->parserFlags() & ALIGNED_VIDEO_DATA) ?
+                    ElementaryStreamQueue::kFlag_AlignedData : 0;
             break;
+
         case STREAMTYPE_MPEG2_AUDIO_ADTS:
-            mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC);
+            mode = ElementaryStreamQueue::AAC;
             break;
+
         case STREAMTYPE_MPEG1_AUDIO:
         case STREAMTYPE_MPEG2_AUDIO:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::MPEG_AUDIO);
+            mode = ElementaryStreamQueue::MPEG_AUDIO;
             break;
 
         case STREAMTYPE_MPEG1_VIDEO:
         case STREAMTYPE_MPEG2_VIDEO:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::MPEG_VIDEO);
+            mode = ElementaryStreamQueue::MPEG_VIDEO;
             break;
 
         case STREAMTYPE_MPEG4_VIDEO:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::MPEG4_VIDEO);
+            mode = ElementaryStreamQueue::MPEG4_VIDEO;
             break;
 
         case STREAMTYPE_LPCM_AC3:
         case STREAMTYPE_AC3:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::AC3);
+            mode = ElementaryStreamQueue::AC3;
             break;
 
         case STREAMTYPE_METADATA:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::METADATA);
+            mode = ElementaryStreamQueue::METADATA;
             break;
 
         default:
-            break;
+            ALOGE("stream PID 0x%02x has invalid stream type 0x%02x",
+                    elementaryPID, streamType);
+            return;
     }
 
-    ALOGV("new stream PID 0x%02x, type 0x%02x", elementaryPID, streamType);
+    mQueue = new ElementaryStreamQueue(mode, flags);
 
     if (mQueue != NULL) {
-        mBuffer = new ABuffer(192 * 1024);
-        mBuffer->setRange(0, 0);
+        ensureBufferCapacity(kInitialStreamBufferSize);
+
+        if (mScrambled && (isAudio() || isVideo())) {
+            // Set initial format to scrambled
+            sp<MetaData> meta = new MetaData();
+            meta->setCString(kKeyMIMEType,
+                    isAudio() ? MEDIA_MIMETYPE_AUDIO_SCRAMBLED
+                              : MEDIA_MIMETYPE_VIDEO_SCRAMBLED);
+            // for DrmInitData
+            meta->setData(kKeyCas, 0, &CA_system_ID, sizeof(CA_system_ID));
+            mSource = new AnotherPacketSource(meta);
+        }
     }
 }
 
@@ -657,10 +779,57 @@
     mQueue = NULL;
 }
 
+void ATSParser::Stream::ensureBufferCapacity(size_t neededSize) {
+    if (mBuffer != NULL && mBuffer->capacity() >= neededSize) {
+        return;
+    }
+
+    ALOGV("ensureBufferCapacity: current size %zu, new size %zu, scrambled %d",
+            mBuffer == NULL ? 0 : mBuffer->capacity(), neededSize, mScrambled);
+
+    sp<ABuffer> newBuffer, newScrambledBuffer;
+    sp<IMemory> newMem;
+    sp<MemoryDealer> newDealer;
+    if (mScrambled) {
+        size_t alignment = MemoryDealer::getAllocationAlignment();
+        neededSize = (neededSize + (alignment - 1)) & ~(alignment - 1);
+        // Align to multiples of 64K.
+        neededSize = (neededSize + 65535) & ~65535;
+        newDealer = new MemoryDealer(neededSize, "ATSParser");
+        newMem = newDealer->allocate(neededSize);
+        newScrambledBuffer = new ABuffer(newMem->pointer(), newMem->size());
+
+        if (mDescrambledBuffer != NULL) {
+            memcpy(newScrambledBuffer->data(),
+                    mDescrambledBuffer->data(), mDescrambledBuffer->size());
+            newScrambledBuffer->setRange(0, mDescrambledBuffer->size());
+        } else {
+            newScrambledBuffer->setRange(0, 0);
+        }
+        mMem = newMem;
+        mDealer = newDealer;
+        mDescrambledBuffer = newScrambledBuffer;
+    } else {
+        // Align to multiples of 64K.
+        neededSize = (neededSize + 65535) & ~65535;
+    }
+
+    newBuffer = new ABuffer(neededSize);
+    if (mBuffer != NULL) {
+        memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
+        newBuffer->setRange(0, mBuffer->size());
+    } else {
+        newBuffer->setRange(0, 0);
+    }
+    mBuffer = newBuffer;
+}
+
 status_t ATSParser::Stream::parse(
         unsigned continuity_counter,
-        unsigned payload_unit_start_indicator, ABitReader *br,
-        SyncEvent *event) {
+        unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
+        ABitReader *br, SyncEvent *event) {
     if (mQueue == NULL) {
         return OK;
     }
@@ -672,6 +841,7 @@
         mPayloadStarted = false;
         mPesStartOffsets.clear();
         mBuffer->setRange(0, 0);
+        mSubSamples.clear();
         mExpectedContinuityCounter = -1;
 
 #if 0
@@ -725,21 +895,16 @@
     }
 
     size_t neededSize = mBuffer->size() + payloadSizeBits / 8;
-    if (mBuffer->capacity() < neededSize) {
-        // Increment in multiples of 64K.
-        neededSize = (neededSize + 65535) & ~65535;
-
-        ALOGI("resizing buffer to %zu bytes", neededSize);
-
-        sp<ABuffer> newBuffer = new ABuffer(neededSize);
-        memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
-        newBuffer->setRange(0, mBuffer->size());
-        mBuffer = newBuffer;
-    }
+    ensureBufferCapacity(neededSize);
 
     memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
     mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
 
+    if (mScrambled) {
+        mSubSamples.push_back({payloadSizeBits / 8,
+                 transport_scrambling_control, random_access_indicator});
+    }
+
     return OK;
 }
 
@@ -789,6 +954,7 @@
     mPesStartOffsets.clear();
     mEOSReached = false;
     mBuffer->setRange(0, 0);
+    mSubSamples.clear();
 
     bool clearFormat = false;
     if (isAudio()) {
@@ -817,7 +983,15 @@
     }
 
     if (mSource != NULL) {
-        mSource->queueDiscontinuity(type, extra, true);
+        sp<MetaData> meta = mSource->getFormat();
+        const char* mime;
+        if (clearFormat && meta != NULL && meta->findCString(kKeyMIMEType, &mime)
+                && (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_SCRAMBLED, 15)
+                 || !strncasecmp(mime, MEDIA_MIMETYPE_VIDEO_SCRAMBLED, 15))){
+            mSource->clear();
+        } else {
+            mSource->queueDiscontinuity(type, extra, true);
+        }
     }
 }
 
@@ -830,6 +1004,8 @@
 }
 
 status_t ATSParser::Stream::parsePES(ABitReader *br, SyncEvent *event) {
+    const uint8_t *basePtr = br->data();
+
     unsigned packet_startcode_prefix = br->getBits(24);
 
     ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -859,7 +1035,9 @@
             return ERROR_MALFORMED;
         }
 
-        MY_LOGV("PES_scrambling_control = %u", br->getBits(2));
+        unsigned PES_scrambling_control = br->getBits(2);
+        ALOGV("PES_scrambling_control = %u", PES_scrambling_control);
+
         MY_LOGV("PES_priority = %u", br->getBits(1));
         MY_LOGV("data_alignment_indicator = %u", br->getBits(1));
         MY_LOGV("copyright = %u", br->getBits(1));
@@ -992,6 +1170,7 @@
         br->skipBits(optional_bytes_remaining * 8);
 
         // ES data follows.
+        int32_t pesOffset = br->data() - basePtr;
 
         if (PES_packet_length != 0) {
             if (PES_packet_length < PES_header_data_length + 3) {
@@ -1009,21 +1188,26 @@
                 return ERROR_MALFORMED;
             }
 
+            ALOGV("There's %u bytes of payload, PES_packet_length=%u, offset=%d",
+                    dataLength, PES_packet_length, pesOffset);
+
             onPayloadData(
-                    PTS_DTS_flags, PTS, DTS, br->data(), dataLength, event);
+                    PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
+                    br->data(), dataLength, pesOffset, event);
 
             br->skipBits(dataLength * 8);
         } else {
             onPayloadData(
-                    PTS_DTS_flags, PTS, DTS,
-                    br->data(), br->numBitsLeft() / 8, event);
+                    PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
+                    br->data(), br->numBitsLeft() / 8, pesOffset, event);
 
             size_t payloadSizeBits = br->numBitsLeft();
             if (payloadSizeBits % 8 != 0u) {
                 return ERROR_MALFORMED;
             }
 
-            ALOGV("There's %zu bytes of payload.", payloadSizeBits / 8);
+            ALOGV("There's %zu bytes of payload, offset=%d",
+                    payloadSizeBits / 8, pesOffset);
         }
     } else if (stream_id == 0xbe) {  // padding_stream
         if (PES_packet_length == 0u) {
@@ -1040,6 +1224,200 @@
     return OK;
 }
 
+uint32_t ATSParser::Stream::getPesScramblingControl(
+        ABitReader *br, int32_t *pesOffset) {
+    unsigned packet_startcode_prefix = br->getBits(24);
+
+    ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
+
+    if (packet_startcode_prefix != 1) {
+        ALOGV("unit does not start with startcode.");
+        return 0;
+    }
+
+    if (br->numBitsLeft() < 48) {
+        return 0;
+    }
+
+    unsigned stream_id = br->getBits(8);
+    ALOGV("stream_id = 0x%02x", stream_id);
+
+    br->skipBits(16); // PES_packet_length
+
+    if (stream_id != 0xbc  // program_stream_map
+            && stream_id != 0xbe  // padding_stream
+            && stream_id != 0xbf  // private_stream_2
+            && stream_id != 0xf0  // ECM
+            && stream_id != 0xf1  // EMM
+            && stream_id != 0xff  // program_stream_directory
+            && stream_id != 0xf2  // DSMCC
+            && stream_id != 0xf8) {  // H.222.1 type E
+        if (br->getBits(2) != 2u) {
+            return 0;
+        }
+
+        unsigned PES_scrambling_control = br->getBits(2);
+        ALOGV("PES_scrambling_control = %u", PES_scrambling_control);
+
+        if (PES_scrambling_control == 0) {
+            return 0;
+        }
+
+        br->skipBits(12); // don't care
+
+        unsigned PES_header_data_length = br->getBits(8);
+        ALOGV("PES_header_data_length = %u", PES_header_data_length);
+
+        if (PES_header_data_length * 8 > br->numBitsLeft()) {
+            return 0;
+        }
+
+        *pesOffset = 9 + PES_header_data_length;
+        ALOGD("found PES_scrambling_control=%d, PES offset=%d",
+                PES_scrambling_control, *pesOffset);
+        return PES_scrambling_control;
+    }
+
+    return 0;
+}
+
+status_t ATSParser::Stream::flushScrambled(SyncEvent *event) {
+    if (mDescrambler == NULL) {
+        ALOGE("received scrambled packets without descrambler!");
+        return UNKNOWN_ERROR;
+    }
+
+    if (mDescrambledBuffer == NULL || mMem == NULL) {
+        ALOGE("received scrambled packets without shared memory!");
+
+        return UNKNOWN_ERROR;
+    }
+
+    int32_t pesOffset = 0;
+    int32_t descrambleSubSamples = 0, descrambleBytes = 0;
+    uint32_t tsScramblingControl = 0, pesScramblingControl = 0;
+
+    // First, go over subsamples to find TS-level scrambling key id, and
+    // calculate how many subsample we need to descramble (assuming we don't
+    // have PES-level scrambling).
+    for (auto it = mSubSamples.begin(); it != mSubSamples.end(); it++) {
+        if (it->transport_scrambling_mode != 0) {
+            // TODO: handle keyId change, use the first non-zero keyId for now.
+            if (tsScramblingControl == 0) {
+                tsScramblingControl = it->transport_scrambling_mode;
+            }
+        }
+        if (tsScramblingControl == 0 || descrambleSubSamples == 0
+                || !mQueue->isScrambled()) {
+            descrambleSubSamples++;
+            descrambleBytes += it->subSampleSize;
+        }
+    }
+    // If not scrambled at TS-level, check PES-level scrambling
+    if (tsScramblingControl == 0) {
+        ABitReader br(mBuffer->data(), mBuffer->size());
+        pesScramblingControl = getPesScramblingControl(&br, &pesOffset);
+        // If not scrambled at PES-level either, or scrambled at PES-level but
+        // requires output to remain scrambled, we don't need to descramble
+        // anything.
+        if (pesScramblingControl == 0 || mQueue->isScrambled()) {
+            descrambleSubSamples = 0;
+            descrambleBytes = 0;
+        }
+    }
+
+    uint32_t sctrl = tsScramblingControl != 0 ?
+            tsScramblingControl : pesScramblingControl;
+
+    // Perform the 1st pass descrambling if needed
+    if (descrambleBytes > 0) {
+        memcpy(mDescrambledBuffer->data(), mBuffer->data(), descrambleBytes);
+        mDescrambledBuffer->setRange(0, descrambleBytes);
+
+        sp<ABuffer> subSamples = new ABuffer(
+                sizeof(DescramblerPlugin::SubSample) * descrambleSubSamples);
+
+        DescrambleInfo info;
+        info.dstType = DescrambleInfo::kDestinationTypeVmPointer;
+        info.scramblingControl = (DescramblerPlugin::ScramblingControl)sctrl;
+        info.numSubSamples = descrambleSubSamples;
+        info.subSamples = (DescramblerPlugin::SubSample *)subSamples->data();
+        info.srcMem = mMem;
+        info.srcOffset = 0;
+        info.dstPtr = NULL; // in-place descrambling into srcMem
+        info.dstOffset = 0;
+
+        int32_t i = 0;
+        for (auto it = mSubSamples.begin();
+                it != mSubSamples.end() && i < descrambleSubSamples; it++, i++) {
+            if (it->transport_scrambling_mode != 0 || pesScramblingControl != 0) {
+                info.subSamples[i].mNumBytesOfClearData = 0;
+                info.subSamples[i].mNumBytesOfEncryptedData = it->subSampleSize;
+            } else {
+                info.subSamples[i].mNumBytesOfClearData = it->subSampleSize;
+                info.subSamples[i].mNumBytesOfEncryptedData = 0;
+            }
+        }
+        // If scrambled at PES-level, PES header should be skipped
+        if (pesScramblingControl != 0) {
+            info.srcOffset = info.dstOffset = pesOffset;
+            info.subSamples[0].mNumBytesOfEncryptedData -= pesOffset;
+        }
+
+        int32_t result;
+        Status status = mDescrambler->descramble(info, &result);
+
+        if (!status.isOk()) {
+            ALOGE("[stream %d] descramble failed, exceptionCode=%d",
+                    mElementaryPID, status.exceptionCode());
+            return UNKNOWN_ERROR;
+        }
+
+        ALOGV("[stream %d] descramble succeeded, %d bytes",
+                mElementaryPID, result);
+        memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
+    }
+
+    if (mQueue->isScrambled()) {
+        // Queue subSample info for scrambled queue
+        sp<ABuffer> clearSizesBuffer = new ABuffer(mSubSamples.size() * 4);
+        sp<ABuffer> encSizesBuffer = new ABuffer(mSubSamples.size() * 4);
+        int32_t *clearSizePtr = (int32_t*)clearSizesBuffer->data();
+        int32_t *encSizePtr = (int32_t*)encSizesBuffer->data();
+        int32_t isSync = 0;
+        int32_t i = 0;
+        for (auto it = mSubSamples.begin();
+                it != mSubSamples.end(); it++, i++) {
+            if ((it->transport_scrambling_mode == 0
+                    && pesScramblingControl == 0)
+                    || i < descrambleSubSamples) {
+                clearSizePtr[i] = it->subSampleSize;
+                encSizePtr[i] = 0;
+            } else {
+                clearSizePtr[i] = 0;
+                encSizePtr[i] = it->subSampleSize;
+            }
+            isSync |= it->random_access_indicator;
+        }
+        // Pass the original TS subsample size now. The PES header adjust
+        // will be applied when the scrambled AU is dequeued.
+        mQueue->appendScrambledData(
+                mBuffer->data(), mBuffer->size(), sctrl,
+                isSync, clearSizesBuffer, encSizesBuffer);
+    }
+
+    ABitReader br(mBuffer->data(), mBuffer->size());
+    status_t err = parsePES(&br, event);
+
+    if (err != OK) {
+        ALOGE("[stream %d] failed to parse descrambled PES, err=%d",
+                mElementaryPID, err);
+    }
+
+    return err;
+}
+
+
 status_t ATSParser::Stream::flush(SyncEvent *event) {
     if (mBuffer == NULL || mBuffer->size() == 0) {
         return OK;
@@ -1047,9 +1425,14 @@
 
     ALOGV("flushing stream 0x%04x size = %zu", mElementaryPID, mBuffer->size());
 
-    ABitReader br(mBuffer->data(), mBuffer->size());
-
-    status_t err = parsePES(&br, event);
+    status_t err = OK;
+    if (mScrambled) {
+        err = flushScrambled(event);
+        mSubSamples.clear();
+    } else {
+        ABitReader br(mBuffer->data(), mBuffer->size());
+        err = parsePES(&br, event);
+    }
 
     mBuffer->setRange(0, 0);
 
@@ -1058,7 +1441,9 @@
 
 void ATSParser::Stream::onPayloadData(
         unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
-        const uint8_t *data, size_t size, SyncEvent *event) {
+        unsigned PES_scrambling_control,
+        const uint8_t *data, size_t size,
+        int32_t payloadOffset, SyncEvent *event) {
 #if 0
     ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
           mStreamType,
@@ -1074,7 +1459,8 @@
         timeUs = mProgram->convertPTSToTimestamp(PTS);
     }
 
-    status_t err = mQueue->appendData(data, size, timeUs);
+    status_t err = mQueue->appendData(
+            data, size, timeUs, payloadOffset, PES_scrambling_control);
 
     if (mEOSReached) {
         mQueue->signalEOS();
@@ -1096,9 +1482,11 @@
 
                 const char *mime;
                 if (meta->findCString(kKeyMIMEType, &mime)
-                        && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
-                        && !IsIDR(accessUnit)) {
-                    continue;
+                        && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+                    int32_t sync = 0;
+                    if (!accessUnit->meta()->findInt32("isSync", &sync) || !sync) {
+                        continue;
+                    }
                 }
                 mSource = new AnotherPacketSource(meta);
                 mSource->queueAccessUnit(accessUnit);
@@ -1178,6 +1566,18 @@
     return NULL;
 }
 
+void ATSParser::Stream::setCasSession(
+        const sp<IDescrambler> &descrambler,
+        const std::vector<uint8_t> &sessionId) {
+    if (mSource != NULL && mDescrambler == NULL && descrambler != NULL) {
+        signalDiscontinuity(DISCONTINUITY_FORMAT_ONLY, NULL);
+        mDescrambler = descrambler;
+        if (mQueue->isScrambled()) {
+            mQueue->setCasSession(sessionId);
+        }
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ATSParser::ATSParser(uint32_t flags)
@@ -1189,6 +1589,7 @@
       mNumTSPacketsParsed(0),
       mNumPCRs(0) {
     mPSISections.add(0 /* PID */, new PSISection);
+    mCasManager = new CasManager();
 }
 
 ATSParser::~ATSParser() {
@@ -1205,6 +1606,17 @@
     return parseTS(&br, event);
 }
 
+status_t ATSParser::setMediaCas(const sp<ICas> &cas) {
+    status_t err = mCasManager->setMediaCas(cas);
+    if (err != OK) {
+        return err;
+    }
+    for (size_t i = 0; i < mPrograms.size(); ++i) {
+        mPrograms.editItemAt(i)->updateCasSessions();
+    }
+    return OK;
+}
+
 void ATSParser::signalDiscontinuity(
         DiscontinuityType type, const sp<AMessage> &extra) {
     int64_t mediaTimeUs;
@@ -1331,6 +1743,8 @@
         ABitReader *br, unsigned PID,
         unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
         SyncEvent *event) {
     ssize_t sectionIndex = mPSISections.indexOfKey(PID);
 
@@ -1402,7 +1816,10 @@
     for (size_t i = 0; i < mPrograms.size(); ++i) {
         status_t err;
         if (mPrograms.editItemAt(i)->parsePID(
-                    PID, continuity_counter, payload_unit_start_indicator,
+                    PID, continuity_counter,
+                    payload_unit_start_indicator,
+                    transport_scrambling_control,
+                    random_access_indicator,
                     br, &err, event)) {
             if (err != OK) {
                 return err;
@@ -1414,13 +1831,19 @@
     }
 
     if (!handled) {
+        handled = mCasManager->parsePID(br, PID);
+    }
+
+    if (!handled) {
         ALOGV("PID 0x%04x not handled.", PID);
     }
 
     return OK;
 }
 
-status_t ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) {
+status_t ATSParser::parseAdaptationField(
+        ABitReader *br, unsigned PID, unsigned *random_access_indicator) {
+    *random_access_indicator = 0;
     unsigned adaptation_field_length = br->getBits(8);
 
     if (adaptation_field_length > 0) {
@@ -1435,7 +1858,16 @@
             ALOGV("PID 0x%04x: discontinuity_indicator = 1 (!!!)", PID);
         }
 
-        br->skipBits(2);
+        *random_access_indicator = br->getBits(1);
+        if (*random_access_indicator) {
+            ALOGV("PID 0x%04x: random_access_indicator = 1", PID);
+        }
+
+        unsigned elementary_stream_priority_indicator = br->getBits(1);
+        if (elementary_stream_priority_indicator) {
+            ALOGV("PID 0x%04x: elementary_stream_priority_indicator = 1", PID);
+        }
+
         unsigned PCR_flag = br->getBits(1);
 
         size_t numBitsRead = 4;
@@ -1501,7 +1933,8 @@
     unsigned PID = br->getBits(13);
     ALOGV("PID = 0x%04x", PID);
 
-    MY_LOGV("transport_scrambling_control = %u", br->getBits(2));
+    unsigned transport_scrambling_control = br->getBits(2);
+    ALOGV("transport_scrambling_control = %u", transport_scrambling_control);
 
     unsigned adaptation_field_control = br->getBits(2);
     ALOGV("adaptation_field_control = %u", adaptation_field_control);
@@ -1513,13 +1946,17 @@
 
     status_t err = OK;
 
+    unsigned random_access_indicator = 0;
     if (adaptation_field_control == 2 || adaptation_field_control == 3) {
-        err = parseAdaptationField(br, PID);
+        err = parseAdaptationField(br, PID, &random_access_indicator);
     }
     if (err == OK) {
         if (adaptation_field_control == 1 || adaptation_field_control == 3) {
             err = parsePID(br, PID, continuity_counter,
-                    payload_unit_start_indicator, event);
+                    payload_unit_start_indicator,
+                    transport_scrambling_control,
+                    random_access_indicator,
+                    event);
         }
     }
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index faae6c9..4a88713 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -26,11 +26,17 @@
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
-
+namespace media {
+class ICas;
+class IDescrambler;
+};
+using namespace media;
 class ABitReader;
 struct ABuffer;
+struct AnotherPacketSource;
 
 struct ATSParser : public RefBase {
     enum DiscontinuityType {
@@ -100,6 +106,8 @@
 
     explicit ATSParser(uint32_t flags = 0);
 
+    status_t setMediaCas(const sp<ICas> &cas);
+
     // Feed a TS packet into the parser. uninitialized event with the start
     // offset of this TS packet goes in, and if the parser detects PES with
     // a sync frame, the event will be initiailzed with the start offset of the
@@ -150,6 +158,14 @@
     struct Program;
     struct Stream;
     struct PSISection;
+    struct CasManager;
+    struct CADescriptor {
+        int32_t mSystemID;
+        unsigned mPID;
+        std::vector<uint8_t> mPrivateData;
+    };
+
+    sp<CasManager> mCasManager;
 
     uint32_t mFlags;
     Vector<sp<Program> > mPrograms;
@@ -181,9 +197,13 @@
         ABitReader *br, unsigned PID,
         unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
         SyncEvent *event);
 
-    status_t parseAdaptationField(ABitReader *br, unsigned PID);
+    status_t parseAdaptationField(
+            ABitReader *br, unsigned PID, unsigned *random_access_indicator);
+
     // see feedTSPacket().
     status_t parseTS(ABitReader *br, SyncEvent *event);
 
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 92c386c..5140e66 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_SRC_FILES:=                 \
         AnotherPacketSource.cpp   \
         ATSParser.cpp             \
+        CasManager.cpp            \
         ESQueue.cpp               \
         MPEG2PSExtractor.cpp      \
         MPEG2TSExtractor.cpp      \
@@ -14,7 +15,8 @@
 	$(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SHARED_LIBRARIES := libmedia
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 548f44e..433b1fc 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -204,25 +204,53 @@
         }
 
         MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+        sp<MetaData> bufmeta = mediaBuffer->meta_data();
 
-        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+        bufmeta->setInt64(kKeyTime, timeUs);
 
         int32_t isSync;
         if (buffer->meta()->findInt32("isSync", &isSync)) {
-            mediaBuffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
+            bufmeta->setInt32(kKeyIsSyncFrame, isSync);
         }
 
         sp<ABuffer> sei;
         if (buffer->meta()->findBuffer("sei", &sei) && sei != NULL) {
-            mediaBuffer->meta_data()->setData(kKeySEI, 0, sei->data(), sei->size());
+            bufmeta->setData(kKeySEI, 0, sei->data(), sei->size());
         }
 
         sp<ABuffer> mpegUserData;
         if (buffer->meta()->findBuffer("mpegUserData", &mpegUserData) && mpegUserData != NULL) {
-            mediaBuffer->meta_data()->setData(
+            bufmeta->setData(
                     kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
         }
 
+        int32_t cryptoMode;
+        if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
+            int32_t cryptoKey;
+            sp<ABuffer> clearBytesBuffer, encBytesBuffer;
+
+            CHECK(buffer->meta()->findInt32("cryptoKey", &cryptoKey));
+            CHECK(buffer->meta()->findBuffer("clearBytes", &clearBytesBuffer)
+                    && clearBytesBuffer != NULL);
+            CHECK(buffer->meta()->findBuffer("encBytes", &encBytesBuffer)
+                    && encBytesBuffer != NULL);
+
+            bufmeta->setInt32(kKeyCryptoMode, cryptoMode);
+
+            uint8_t array[16] = {0};
+            bufmeta->setData(kKeyCryptoIV, 0, array, 16);
+
+            array[0] = (uint8_t) (cryptoKey & 0xff);
+            bufmeta->setData(kKeyCryptoKey, 0, array, 16);
+
+            bufmeta->setData(kKeyPlainSizes, 0,
+                    clearBytesBuffer->data(), clearBytesBuffer->size());
+
+            bufmeta->setData(kKeyEncryptedSizes, 0,
+                    encBytesBuffer->data(), encBytesBuffer->size());
+        }
+
+
         *out = mediaBuffer;
         return OK;
     }
diff --git a/media/libstagefright/mpeg2ts/CasManager.cpp b/media/libstagefright/mpeg2ts/CasManager.cpp
new file mode 100644
index 0000000..4e34a30
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/CasManager.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CasManager"
+#include "CasManager.h"
+
+#include <android/media/ICas.h>
+#include <android/media/IDescrambler.h>
+#include <android/media/IMediaCasService.h>
+#include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ABitReader.h>
+#include <utils/Log.h>
+
+namespace android {
+using binder::Status;
+
+struct ATSParser::CasManager::ProgramCasManager : public RefBase {
+    ProgramCasManager(unsigned programNumber, const CADescriptor &descriptor);
+    ProgramCasManager(unsigned programNumber);
+
+    bool addStream(unsigned elementaryPID, const CADescriptor &descriptor);
+
+    status_t setMediaCas(const sp<ICas> &cas, PidToSessionMap &sessionMap);
+
+    bool getCasSession(unsigned elementaryPID,
+            sp<IDescrambler> *descrambler, std::vector<uint8_t> *sessionId) const;
+
+    void closeAllSessions(const sp<ICas>& cas);
+
+private:
+    struct CasSession {
+        CasSession() {}
+        CasSession(const CADescriptor &descriptor) :
+            mCADescriptor(descriptor) {}
+
+        CADescriptor mCADescriptor;
+        std::vector<uint8_t> mSessionId;
+        sp<IDescrambler> mDescrambler;
+    };
+    status_t initSession(
+             const sp<ICas>& cas, PidToSessionMap &sessionMap,
+             CasSession *session, unsigned programNumber, unsigned elementaryPID);
+    void closeSession(const sp<ICas>& cas, const CasSession &casSession);
+
+    unsigned mProgramNumber;
+    bool mHasProgramCas;
+    CasSession mProgramCas;
+    KeyedVector<unsigned, CasSession> mStreamPidToCasMap;
+};
+
+ATSParser::CasManager::ProgramCasManager::ProgramCasManager(
+        unsigned programNumber, const CADescriptor &descriptor) :
+    mProgramNumber(programNumber),
+    mHasProgramCas(true),
+    mProgramCas(descriptor) {}
+
+ATSParser::CasManager::ProgramCasManager::ProgramCasManager(
+        unsigned programNumber) :
+    mProgramNumber(programNumber),
+    mHasProgramCas(false) {}
+
+bool ATSParser::CasManager::ProgramCasManager::addStream(
+        unsigned elementaryPID, const CADescriptor &descriptor) {
+    ssize_t index = mStreamPidToCasMap.indexOfKey(elementaryPID);
+    if (index >= 0) {
+        return false;
+    }
+    ALOGV("addStream: program=%d, elementaryPID=%d, CA_system_ID=0x%x",
+            mProgramNumber, elementaryPID, descriptor.mSystemID);
+    mStreamPidToCasMap.add(elementaryPID, CasSession(descriptor));
+    return true;
+}
+
+status_t ATSParser::CasManager::ProgramCasManager::setMediaCas(
+        const sp<ICas> &cas, PidToSessionMap &sessionMap) {
+    if (mHasProgramCas) {
+        return initSession(cas, sessionMap, &mProgramCas, mProgramNumber, 0);
+    }
+    for (size_t index = 0; index < mStreamPidToCasMap.size(); index++) {
+        unsigned elementaryPID = mStreamPidToCasMap.keyAt(index);
+        status_t err;
+        if ((err = initSession(cas, sessionMap,
+                &mStreamPidToCasMap.editValueAt(index),
+                mProgramNumber, elementaryPID)) != OK) {
+            return err;
+        }
+    }
+    return OK;
+}
+
+bool ATSParser::CasManager::ProgramCasManager::getCasSession(
+        unsigned elementaryPID, sp<IDescrambler> *descrambler,
+        std::vector<uint8_t> *sessionId) const {
+    if (mHasProgramCas) {
+        *descrambler = mProgramCas.mDescrambler;
+        *sessionId = mProgramCas.mSessionId;
+        return true;
+    }
+    ssize_t index = mStreamPidToCasMap.indexOfKey(elementaryPID);
+    if (index < 0) {
+        return false;
+    }
+
+    *descrambler = mStreamPidToCasMap[index].mDescrambler;
+    *sessionId = mStreamPidToCasMap[index].mSessionId;
+    return true;
+}
+
+status_t ATSParser::CasManager::ProgramCasManager::initSession(
+         const sp<ICas>& cas, PidToSessionMap &sessionMap,
+         CasSession *session, unsigned programNumber, unsigned elementaryPID) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> casServiceBinder = sm->getService(String16("media.cas"));
+    sp<IMediaCasService> casService =
+            interface_cast<IMediaCasService>(casServiceBinder);
+
+    if (casService == NULL) {
+        ALOGE("Cannot obtain IMediaCasService");
+        return NO_INIT;
+    }
+
+    sp<IDescrambler> descrambler;
+    std::vector<uint8_t> sessionId;
+    const CADescriptor &descriptor = session->mCADescriptor;
+
+    Status status;
+    if (elementaryPID == 0) {
+        status = cas->openSession(programNumber, &sessionId);
+    } else {
+        status = cas->openSessionForStream(
+                programNumber, elementaryPID, &sessionId);
+    }
+    if (!status.isOk()) {
+        ALOGE("Failed to open session: exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
+    if (!status.isOk()) {
+        ALOGE("Failed to set private data: exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    status = casService->createDescrambler(descriptor.mSystemID, &descrambler);
+    if (!status.isOk() || descrambler == NULL) {
+        ALOGE("Failed to create descrambler: : exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    status = descrambler->setMediaCasSession(sessionId);
+    if (!status.isOk()) {
+        ALOGE("Failed to init descrambler: : exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    session->mSessionId = sessionId;
+    session->mDescrambler = descrambler;
+    sessionMap.add(descriptor.mPID, sessionId);
+
+    return OK;
+
+l_fail:
+    if (!sessionId.empty()) {
+        cas->closeSession(sessionId);
+    }
+    if (descrambler != NULL) {
+        descrambler->release();
+    }
+    return NO_INIT;
+}
+
+void ATSParser::CasManager::ProgramCasManager::closeSession(
+        const sp<ICas>& cas, const CasSession &casSession) {
+    if (casSession.mDescrambler != NULL) {
+        casSession.mDescrambler->release();
+    }
+    if (!casSession.mSessionId.empty()) {
+        cas->closeSession(casSession.mSessionId);
+    }
+}
+
+void ATSParser::CasManager::ProgramCasManager::closeAllSessions(
+        const sp<ICas>& cas) {
+    if (mHasProgramCas) {
+        closeSession(cas, mProgramCas);
+    }
+    for (size_t index = 0; index < mStreamPidToCasMap.size(); index++) {
+        closeSession(cas, mStreamPidToCasMap.editValueAt(index));
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ATSParser::CasManager::CasManager() : mSystemId(-1) {}
+
+ATSParser::CasManager::~CasManager() {
+    // Explictly close the sessions opened by us, since the CAS object is owned
+    // by the app and may not go away after the parser is destroyed, and the app
+    // may not have information about the sessions.
+    if (mICas != NULL) {
+        for (size_t index = 0; index < mProgramCasMap.size(); index++) {
+            mProgramCasMap.editValueAt(index)->closeAllSessions(mICas);
+        }
+    }
+}
+
+bool ATSParser::CasManager::setSystemId(int32_t CA_system_ID) {
+    if (mSystemId == -1) {
+        // Verify the CA_system_ID is within range on the first program
+        if (CA_system_ID < 0 || CA_system_ID > 0xffff) {
+            ALOGE("Invalid CA_system_id: %d", CA_system_ID);
+            return false;
+        }
+        mSystemId = CA_system_ID;
+    } else if (mSystemId != CA_system_ID) {
+        // All sessions need to be under the same CA system
+        ALOGE("Multiple CA systems not allowed: %d vs %d",
+                mSystemId, CA_system_ID);
+        return false;
+    }
+    return true;
+}
+
+status_t ATSParser::CasManager::setMediaCas(const sp<ICas> &cas) {
+    if (cas == NULL) {
+        ALOGE("setMediaCas: received NULL object");
+        return BAD_VALUE;
+    }
+    if (mICas != NULL) {
+        ALOGW("setMediaCas: already set");
+        return ALREADY_EXISTS;
+    }
+    for (size_t index = 0; index < mProgramCasMap.size(); index++) {
+        status_t err;
+        if ((err = mProgramCasMap.editValueAt(
+                index)->setMediaCas(cas, mCAPidToSessionIdMap)) != OK) {
+            return err;
+        }
+    }
+    mICas = cas;
+    return OK;
+}
+
+bool ATSParser::CasManager::addProgram(
+        unsigned programNumber, const CADescriptor &descriptor) {
+    if (!setSystemId(descriptor.mSystemID)) {
+        return false;
+    }
+
+    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
+    if (index < 0) {
+        ALOGV("addProgram: programNumber=%d, CA_system_ID=0x%x",
+                programNumber, descriptor.mSystemID);
+        mProgramCasMap.add(programNumber,
+                new ProgramCasManager(programNumber, descriptor));
+        mCAPidSet.insert(descriptor.mPID);
+    }
+    return true;
+}
+
+bool ATSParser::CasManager::addStream(
+        unsigned programNumber, unsigned elementaryPID,
+        const CADescriptor &descriptor) {
+    if (!setSystemId(descriptor.mSystemID)) {
+        return false;
+    }
+
+    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
+    sp<ProgramCasManager> programCasManager;
+    if (index < 0) {
+        ALOGV("addProgram (no CADescriptor): programNumber=%d", programNumber);
+        programCasManager = new ProgramCasManager(programNumber);
+        mProgramCasMap.add(programNumber, programCasManager);
+    } else {
+        programCasManager = mProgramCasMap.editValueAt(index);
+    }
+    if (programCasManager->addStream(elementaryPID, descriptor)) {
+        mCAPidSet.insert(descriptor.mPID);
+    }
+    return true;
+}
+
+bool ATSParser::CasManager::getCasSession(
+        unsigned programNumber, unsigned elementaryPID,
+        sp<IDescrambler> *descrambler, std::vector<uint8_t> *sessionId) const {
+    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
+    if (index < 0) {
+        return false;
+    }
+    return mProgramCasMap[index]->getCasSession(
+            elementaryPID, descrambler, sessionId);
+}
+
+bool ATSParser::CasManager::isCAPid(unsigned pid) {
+    return mCAPidSet.find(pid) != mCAPidSet.end();
+}
+
+bool ATSParser::CasManager::parsePID(ABitReader *br, unsigned pid) {
+    ssize_t index = mCAPidToSessionIdMap.indexOfKey(pid);
+    if (index < 0) {
+        return false;
+    }
+    MediaCas::ParcelableCasData ecm(br->data(), br->numBitsLeft() / 8);
+    Status status = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
+    if (!status.isOk()) {
+        ALOGE("Failed to process ECM: exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+    }
+    return true; // handled
+}
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/CasManager.h b/media/libstagefright/mpeg2ts/CasManager.h
new file mode 100644
index 0000000..a7a3de9
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/CasManager.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include "ATSParser.h"
+#include <utils/KeyedVector.h>
+#include <set>
+
+namespace android {
+namespace media {
+class ICas;
+class IDescrambler;
+}
+
+struct ATSParser::CasManager : public RefBase {
+    CasManager();
+    virtual ~CasManager();
+
+    status_t setMediaCas(const sp<ICas> &cas);
+
+    bool addProgram(
+            unsigned programNumber, const CADescriptor &descriptor);
+
+    bool addStream(
+            unsigned programNumber, unsigned elementaryPID,
+            const CADescriptor &descriptor);
+
+    bool getCasSession(
+            unsigned programNumber, unsigned elementaryPID,
+            sp<IDescrambler> *descrambler,
+            std::vector<uint8_t> *sessionId) const;
+
+    bool isCAPid(unsigned pid);
+
+    bool parsePID(ABitReader *br, unsigned pid);
+
+private:
+    typedef KeyedVector<unsigned, std::vector<uint8_t> > PidToSessionMap;
+    struct ProgramCasManager;
+
+    bool setSystemId(int32_t CA_system_ID);
+
+    int32_t mSystemId;
+    sp<ICas> mICas;
+    KeyedVector<unsigned, sp<ProgramCasManager> > mProgramCasMap;
+    PidToSessionMap mCAPidToSessionIdMap;
+    std::set<uint32_t> mCAPidSet;
+};
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 96ca405..b933002 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -28,6 +28,8 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
 
 #include "include/avc_utils.h"
 
@@ -53,6 +55,11 @@
 
     mRangeInfos.clear();
 
+    if (mScrambledBuffer != NULL) {
+        mScrambledBuffer->setRange(0, 0);
+    }
+    mScrambledRangeInfos.clear();
+
     if (clearFormat) {
         mFormat.clear();
     }
@@ -246,7 +253,8 @@
 }
 
 status_t ElementaryStreamQueue::appendData(
-        const void *data, size_t size, int64_t timeUs) {
+        const void *data, size_t size, int64_t timeUs,
+        int32_t payloadOffset, uint32_t pesScramblingControl) {
 
     if (mEOSReached) {
         ALOGE("appending data after EOS");
@@ -276,7 +284,7 @@
                     return ERROR_MALFORMED;
                 }
 
-                if (startOffset > 0) {
+                if (mFormat == NULL && startOffset > 0) {
                     ALOGI("found something resembling an H.264/MPEG syncword "
                           "at offset %zd",
                           startOffset);
@@ -451,6 +459,8 @@
     RangeInfo info;
     info.mLength = size;
     info.mTimestampUs = timeUs;
+    info.mPesOffset = payloadOffset;
+    info.mPesScramblingControl = pesScramblingControl;
     mRangeInfos.push_back(info);
 
 #if 0
@@ -463,8 +473,129 @@
     return OK;
 }
 
+void ElementaryStreamQueue::appendScrambledData(
+        const void *data, size_t size,
+        int32_t keyId, bool isSync,
+        sp<ABuffer> clearSizes, sp<ABuffer> encSizes) {
+    if (!isScrambled()) {
+        return;
+    }
+
+    size_t neededSize = (mScrambledBuffer == NULL ? 0 : mScrambledBuffer->size()) + size;
+    if (mScrambledBuffer == NULL || neededSize > mScrambledBuffer->capacity()) {
+        neededSize = (neededSize + 65535) & ~65535;
+
+        ALOGI("resizing scrambled buffer to size %zu", neededSize);
+
+        sp<ABuffer> buffer = new ABuffer(neededSize);
+        if (mScrambledBuffer != NULL) {
+            memcpy(buffer->data(), mScrambledBuffer->data(), mScrambledBuffer->size());
+            buffer->setRange(0, mScrambledBuffer->size());
+        } else {
+            buffer->setRange(0, 0);
+        }
+
+        mScrambledBuffer = buffer;
+    }
+    memcpy(mScrambledBuffer->data() + mScrambledBuffer->size(), data, size);
+    mScrambledBuffer->setRange(0, mScrambledBuffer->size() + size);
+
+    ScrambledRangeInfo scrambledInfo;
+    scrambledInfo.mLength = size;
+    scrambledInfo.mKeyId = keyId;
+    scrambledInfo.mIsSync = isSync;
+    scrambledInfo.mClearSizes = clearSizes;
+    scrambledInfo.mEncSizes = encSizes;
+
+    ALOGV("[stream %d] appending scrambled range: size=%zu", mMode, size);
+
+    mScrambledRangeInfos.push_back(scrambledInfo);
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
+    size_t nextScan = mBuffer->size();
+    mBuffer->setRange(0, 0);
+    int32_t pesOffset = 0, pesScramblingControl = 0;
+    int64_t timeUs = fetchTimestamp(nextScan, &pesOffset, &pesScramblingControl);
+    if (timeUs < 0ll) {
+        ALOGE("Negative timeUs");
+        return NULL;
+    }
+
+    // return scrambled unit
+    int32_t keyId = pesScramblingControl, isSync = 0, scrambledLength = 0;
+    sp<ABuffer> clearSizes, encSizes;
+    while (mScrambledRangeInfos.size() > mRangeInfos.size()) {
+        auto it = mScrambledRangeInfos.begin();
+        ALOGV("[stream %d] fetching scrambled range: size=%zu", mMode, it->mLength);
+
+        if (scrambledLength > 0) {
+            // This shouldn't happen since we always dequeue the entire PES.
+            ALOGW("Discarding srambled length %d", scrambledLength);
+        }
+        scrambledLength = it->mLength;
+
+        // TODO: handle key id change, use first non-zero keyId for now
+        if (keyId == 0) {
+            keyId = it->mKeyId;
+        }
+        clearSizes = it->mClearSizes;
+        encSizes = it->mEncSizes;
+        isSync = it->mIsSync;
+        mScrambledRangeInfos.erase(it);
+    }
+    if (scrambledLength == 0) {
+        ALOGE("[stream %d] empty scrambled unit!", mMode);
+        return NULL;
+    }
+
+    // skip the PES header, and copy the rest into scrambled access unit
+    sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
+            mScrambledBuffer->data() + pesOffset,
+            scrambledLength - pesOffset);
+
+    // fix up first sample size after skipping the PES header
+    if (pesOffset > 0) {
+        int32_t &firstClearSize = *(int32_t*)clearSizes->data();
+        int32_t &firstEncSize = *(int32_t*)encSizes->data();
+        // Cut away the PES header
+        if (firstClearSize >= pesOffset) {
+            // This is for TS-level scrambling, we descrambled the first
+            // (or it was clear to begin with)
+            firstClearSize -= pesOffset;
+        } else if (firstEncSize >= pesOffset) {
+            // This can only be PES-level scrambling
+            firstEncSize -= pesOffset;
+        }
+    }
+
+    scrambledAccessUnit->meta()->setInt64("timeUs", timeUs);
+    if (isSync) {
+        scrambledAccessUnit->meta()->setInt32("isSync", 1);
+    }
+
+    // fill in CryptoInfo fields for AnotherPacketSource::read()
+    // MediaCas doesn't use cryptoMode, but set to non-zero value here.
+    scrambledAccessUnit->meta()->setInt32(
+            "cryptoMode", CryptoPlugin::kMode_AES_CBC);
+    scrambledAccessUnit->meta()->setInt32("cryptoKey", keyId);
+    scrambledAccessUnit->meta()->setBuffer("clearBytes", clearSizes);
+    scrambledAccessUnit->meta()->setBuffer("encBytes", encSizes);
+
+    memmove(mScrambledBuffer->data(),
+            mScrambledBuffer->data() + scrambledLength,
+            mScrambledBuffer->size() - scrambledLength);
+
+    mScrambledBuffer->setRange(0, mScrambledBuffer->size() - scrambledLength);
+
+    ALOGV("[stream %d] dequeued scrambled AU: timeUs=%lld, size=%zu",
+            mMode, (long long)timeUs, scrambledAccessUnit->size());
+
+    return scrambledAccessUnit;
+}
+
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
-    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
+    if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
         if (mRangeInfos.empty()) {
             return NULL;
         }
@@ -751,7 +882,8 @@
     return accessUnit;
 }
 
-int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) {
+int64_t ElementaryStreamQueue::fetchTimestamp(
+        size_t size, int32_t *pesOffset, int32_t *pesScramblingControl) {
     int64_t timeUs = -1;
     bool first = true;
 
@@ -764,6 +896,12 @@
 
         if (first) {
             timeUs = info->mTimestampUs;
+            if (pesOffset != NULL) {
+                *pesOffset = info->mPesOffset;
+            }
+            if (pesScramblingControl != NULL) {
+                *pesScramblingControl = info->mPesScramblingControl;
+            }
             first = false;
         }
 
@@ -787,6 +925,25 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
+    if (isScrambled()) {
+        if (mBuffer == NULL || mBuffer->size() == 0) {
+            return NULL;
+        }
+        if (mFormat == NULL) {
+            mFormat = MakeAVCCodecSpecificData(mBuffer);
+            if (mFormat == NULL) {
+                ALOGI("Creating dummy AVC format for scrambled content");
+                mFormat = new MetaData;
+                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+                mFormat->setInt32(kKeyWidth, 1280);
+                mFormat->setInt32(kKeyHeight, 720);
+            }
+            // for DrmInitData
+            mFormat->setData(kKeyCas, 0, mCasSessionId.data(), mCasSessionId.size());
+        }
+        return dequeueScrambledAccessUnit();
+    }
+
     const uint8_t *data = mBuffer->data();
 
     size_t size = mBuffer->size();
@@ -1045,6 +1202,23 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
+    if (isScrambled()) {
+        if (mBuffer == NULL || mBuffer->size() == 0) {
+            return NULL;
+        }
+        if (mFormat == NULL) {
+            ALOGI("Creating dummy MPEG format for scrambled content");
+            mFormat = new MetaData;
+            mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+            mFormat->setInt32(kKeyWidth, 1280);
+            mFormat->setInt32(kKeyHeight, 720);
+
+            // for DrmInitData
+            mFormat->setData(kKeyCas, 0, mCasSessionId.data(), mCasSessionId.size());
+        }
+        return dequeueScrambledAccessUnit();
+    }
+
     const uint8_t *data = mBuffer->data();
     size_t size = mBuffer->size();
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 56f0706..6941e3f 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -22,6 +22,7 @@
 #include <utils/Errors.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
 
@@ -30,6 +31,7 @@
 
 struct ElementaryStreamQueue {
     enum Mode {
+        INVALID = 0,
         H264,
         AAC,
         AC3,
@@ -43,10 +45,19 @@
     enum Flags {
         // Data appended to the queue is always at access unit boundaries.
         kFlag_AlignedData = 1,
+        kFlag_ScrambledData = 2,
     };
     explicit ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
 
-    status_t appendData(const void *data, size_t size, int64_t timeUs);
+    status_t appendData(const void *data, size_t size,
+            int64_t timeUs, int32_t payloadOffset = 0,
+            uint32_t pesScramblingControl = 0);
+
+    void appendScrambledData(
+            const void *data, size_t size,
+            int32_t keyId, bool isSync,
+            sp<ABuffer> clearSizes, sp<ABuffer> encSizes);
+
     void signalEOS();
     void clear(bool clearFormat);
 
@@ -54,10 +65,29 @@
 
     sp<MetaData> getFormat();
 
+    bool isScrambled() {
+        return (mFlags & kFlag_ScrambledData) != 0;
+    }
+
+    void setCasSession(const std::vector<uint8_t> &sessionId) {
+        mCasSessionId = sessionId;
+    }
+
 private:
     struct RangeInfo {
         int64_t mTimestampUs;
         size_t mLength;
+        int32_t mPesOffset;
+        uint32_t mPesScramblingControl;
+    };
+
+    struct ScrambledRangeInfo {
+        //int64_t mTimestampUs;
+        size_t mLength;
+        int32_t mKeyId;
+        int32_t mIsSync;
+        sp<ABuffer> mClearSizes;
+        sp<ABuffer> mEncSizes;
     };
 
     Mode mMode;
@@ -67,6 +97,10 @@
     sp<ABuffer> mBuffer;
     List<RangeInfo> mRangeInfos;
 
+    sp<ABuffer> mScrambledBuffer;
+    List<ScrambledRangeInfo> mScrambledRangeInfos;
+    std::vector<uint8_t> mCasSessionId;
+
     sp<MetaData> mFormat;
 
     sp<ABuffer> dequeueAccessUnitH264();
@@ -80,7 +114,11 @@
 
     // consume a logical (compressed) access unit of size "size",
     // returns its timestamp in us (or -1 if no time information).
-    int64_t fetchTimestamp(size_t size);
+    int64_t fetchTimestamp(size_t size,
+            int32_t *pesOffset = NULL,
+            int32_t *pesScramblingControl = NULL);
+
+    sp<ABuffer> dequeueScrambledAccessUnit();
 
     DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue);
 };
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index bde33dc..c3f1274 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -148,12 +148,46 @@
     return meta;
 }
 
+//static
+bool MPEG2TSExtractor::isScrambledFormat(const sp<MetaData> &format) {
+    const char *mime;
+    return format->findCString(kKeyMIMEType, &mime)
+            && (!strcasecmp(MEDIA_MIMETYPE_VIDEO_SCRAMBLED, mime)
+                    || !strcasecmp(MEDIA_MIMETYPE_AUDIO_SCRAMBLED, mime));
+}
+
+status_t MPEG2TSExtractor::setMediaCas(const sp<ICas> &cas) {
+    ALOGD("setMediaCas: %p", cas.get());
+
+    status_t err = mParser->setMediaCas(cas);
+    if (err == OK) {
+        ALOGI("All tracks now have descramblers");
+        init();
+    }
+    return err;
+}
+
+void MPEG2TSExtractor::addSource(const sp<AnotherPacketSource> &impl) {
+    bool found = false;
+    for (size_t i = 0; i < mSourceImpls.size(); i++) {
+        if (mSourceImpls[i] == impl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        mSourceImpls.push(impl);
+    }
+}
+
 void MPEG2TSExtractor::init() {
     bool haveAudio = false;
     bool haveVideo = false;
     int64_t startTime = ALooper::GetNowUs();
 
-    while (feedMore(true /* isInit */) == OK) {
+    status_t err;
+    while ((err = feedMore(true /* isInit */)) == OK
+            || err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
         if (haveAudio && haveVideo) {
             addSyncPoint_l(mLastSyncEvent);
             mLastSyncEvent.reset();
@@ -165,10 +199,15 @@
                         ATSParser::VIDEO).get();
 
             if (impl != NULL) {
-                haveVideo = true;
-                mSourceImpls.push(impl);
-                mSyncPoints.push();
-                mSeekSyncPoints = &mSyncPoints.editTop();
+                sp<MetaData> format = impl->getFormat();
+                if (format != NULL) {
+                    haveVideo = true;
+                    addSource(impl);
+                    if (!isScrambledFormat(format)) {
+                        mSyncPoints.push();
+                        mSeekSyncPoints = &mSyncPoints.editTop();
+                    }
+                }
             }
         }
 
@@ -178,11 +217,16 @@
                         ATSParser::AUDIO).get();
 
             if (impl != NULL) {
-                haveAudio = true;
-                mSourceImpls.push(impl);
-                mSyncPoints.push();
-                if (!haveVideo) {
-                    mSeekSyncPoints = &mSyncPoints.editTop();
+                sp<MetaData> format = impl->getFormat();
+                if (format != NULL) {
+                    haveAudio = true;
+                    addSource(impl);
+                    if (!isScrambledFormat(format)) {
+                        mSyncPoints.push();
+                        if (!haveVideo) {
+                            mSeekSyncPoints = &mSyncPoints.editTop();
+                        }
+                    }
                 }
             }
         }
@@ -190,6 +234,16 @@
         addSyncPoint_l(mLastSyncEvent);
         mLastSyncEvent.reset();
 
+        // ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED is returned when the mpeg2ts
+        // is scrambled but we don't have a MediaCas object set. The extraction
+        // will only continue when setMediaCas() is called successfully.
+        if (err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
+            ALOGI("stopped parsing scrambled content, "
+                  "haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
+                    haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
+            return;
+        }
+
         // Wait only for 2 seconds to detect audio/video streams.
         if (ALooper::GetNowUs() - startTime > 2000000ll) {
             break;
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 82b8143..f70f13b 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -34,6 +34,9 @@
         libhidlmemory                   \
         android.hidl.memory@1.0         \
 
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
+        android.hidl.memory@1.0
+
 LOCAL_MODULE:= libstagefright_omx
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
diff --git a/media/libstagefright/omx/hal/1.0/utils/Android.mk b/media/libstagefright/omx/hal/1.0/utils/Android.mk
deleted file mode 100644
index c44ce25..0000000
--- a/media/libstagefright/omx/hal/1.0/utils/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.media.omx@1.0-utils
-LOCAL_SRC_FILES := \
-    WGraphicBufferSource.cpp \
-    WOmx.cpp \
-    WOmxBufferProducer.cpp \
-    WOmxBufferSource.cpp \
-    WOmxNode.cpp \
-    WOmxObserver.cpp \
-    WOmxProducerListener.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    libmedia \
-    libstagefright_foundation \
-    libstagefright_omx \
-    libui \
-    libgui \
-    libhidlbase \
-    libhidltransport \
-    libhwbinder \
-    libhidlmemory \
-    libutils \
-    libcutils \
-    libbinder \
-    liblog \
-    libbase \
-    android.hardware.media.omx@1.0 \
-    android.hardware.graphics.common@1.0 \
-    android.hardware.media@1.0 \
-    android.hidl.base@1.0 \
-
-LOCAL_C_INCLUDES += \
-        $(TOP)/frameworks/av/include \
-        $(TOP)/frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include \
-        $(TOP)/frameworks/native/include/media/openmax \
-        $(TOP)/frameworks/native/include/media/hardware \
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 6d0f189..5941b94 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -17,7 +17,6 @@
         android.hidl.allocator@1.0 \
         android.hidl.memory@1.0 \
         android.hardware.media.omx@1.0 \
-        android.hardware.media.omx@1.0-utils
 
 LOCAL_C_INCLUDES := \
         $(TOP)/frameworks/av/media/libstagefright \
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 0b0facf..70ae46b 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -5,7 +5,8 @@
         TextDescriptions.cpp      \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
index 096fd07..0d55de9 100644
--- a/media/libstagefright/webm/Android.mk
+++ b/media/libstagefright/webm/Android.mk
@@ -4,7 +4,8 @@
 LOCAL_CPPFLAGS += -D__STDINT_LIMITS
 
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SRC_FILES:= EbmlUtil.cpp        \
                   WebmElement.cpp     \
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 82a2627..0bf7854 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -277,19 +277,20 @@
 }
 
 void MtpDevice::print() {
-    if (mDeviceInfo) {
-        mDeviceInfo->print();
+    if (!mDeviceInfo)
+        return;
 
-        if (mDeviceInfo->mDeviceProperties) {
-            ALOGI("***** DEVICE PROPERTIES *****\n");
-            int count = mDeviceInfo->mDeviceProperties->size();
-            for (int i = 0; i < count; i++) {
-                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
-                MtpProperty* property = getDevicePropDesc(propCode);
-                if (property) {
-                    property->print();
-                    delete property;
-                }
+    mDeviceInfo->print();
+
+    if (mDeviceInfo->mDeviceProperties) {
+        ALOGI("***** DEVICE PROPERTIES *****\n");
+        int count = mDeviceInfo->mDeviceProperties->size();
+        for (int i = 0; i < count; i++) {
+            MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
+            MtpProperty* property = getDevicePropDesc(propCode);
+            if (property) {
+                property->print();
+                delete property;
             }
         }
     }
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 1262746..b4029c7 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1605,7 +1605,8 @@
     // never process effects when:
     // - on an OFFLOAD thread
     // - no more tracks are on the session and the effect tail has been rendered
-    bool doProcess = (thread->type() != ThreadBase::OFFLOAD);
+    bool doProcess = (thread->type() != ThreadBase::OFFLOAD)
+                  && (thread->type() != ThreadBase::MMAP);
     if (!isGlobalSession) {
         bool tracksOnSession = (trackCnt() != 0);
 
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 0401796..2be9362 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -41,6 +41,7 @@
     api1/client2/CaptureSequencer.cpp \
     api1/client2/ZslProcessor.cpp \
     api2/CameraDeviceClient.cpp \
+    device1/CameraHardwareInterface.cpp \
     device3/Camera3Device.cpp \
     device3/Camera3Stream.cpp \
     device3/Camera3IOStreamBase.cpp \
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index e710f0a..79e7ff0 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -507,6 +507,14 @@
             return res;
 
         if (!isStreamInfoValid) {
+            // Streaming sharing is only supported for IMPLEMENTATION_DEFINED
+            // formats.
+            if (isShared && streamInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+                String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
+                        "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
+                ALOGW("%s: %s", __FUNCTION__, msg.string());
+                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+            }
             isStreamInfoValid = true;
         }
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index c40809f..f6ad7d7 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -54,9 +54,6 @@
     mListener = listener;
     mServiceProxy = proxy;
 
-    // See if there's a passthrough HAL, but let's not complain if there's not
-    addProvider(kLegacyProviderName, /*expected*/ false);
-
     // Registering will trigger notifications for all already-known providers
     bool success = mServiceProxy->registerForNotifications(
         /* instance name, empty means no filter */ "",
@@ -67,6 +64,9 @@
         return INVALID_OPERATION;
     }
 
+    // See if there's a passthrough HAL, but let's not complain if there's not
+    addProvider(kLegacyProviderName, /*expected*/ false);
+
     return OK;
 }
 
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
new file mode 100644
index 0000000..3e4e631
--- /dev/null
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "CameraHardwareInterface"
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+#include "CameraHardwareInterface.h"
+
+namespace android {
+
+using namespace hardware::camera::device::V1_0;
+using namespace hardware::camera::common::V1_0;
+using hardware::hidl_handle;
+
+CameraHardwareInterface::~CameraHardwareInterface()
+{
+    ALOGI("Destroying camera %s", mName.string());
+    if (mDevice) {
+        int rc = mDevice->common.close(&mDevice->common);
+        if (rc != OK)
+            ALOGE("Could not close camera %s: %d", mName.string(), rc);
+    }
+    if (mHidlDevice != nullptr) {
+        mHidlDevice->close();
+        mHidlDevice.clear();
+        cleanupCirculatingBuffers();
+    }
+}
+
+status_t CameraHardwareInterface::initialize(CameraModule *module)
+{
+    if (mHidlDevice != nullptr) {
+        ALOGE("%s: camera hardware interface has been initialized to HIDL path!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    ALOGI("Opening camera %s", mName.string());
+    camera_info info;
+    status_t res = module->getCameraInfo(atoi(mName.string()), &info);
+    if (res != OK) {
+        return res;
+    }
+
+    int rc = OK;
+    if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
+        info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
+        // Open higher version camera device as HAL1.0 device.
+        rc = module->openLegacy(mName.string(),
+                                 CAMERA_DEVICE_API_VERSION_1_0,
+                                 (hw_device_t **)&mDevice);
+    } else {
+        rc = module->open(mName.string(), (hw_device_t **)&mDevice);
+    }
+    if (rc != OK) {
+        ALOGE("Could not open camera %s: %d", mName.string(), rc);
+        return rc;
+    }
+    initHalPreviewWindow();
+    return rc;
+}
+
+status_t CameraHardwareInterface::initialize(sp<CameraProviderManager> manager) {
+    if (mDevice) {
+        ALOGE("%s: camera hardware interface has been initialized to libhardware path!",
+                __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    ALOGI("Opening camera %s", mName.string());
+
+    status_t ret = manager->openSession(String8::std_string(mName), this, &mHidlDevice);
+    if (ret != OK) {
+        ALOGE("%s: openSession failed! %s (%d)", __FUNCTION__, strerror(-ret), ret);
+    }
+    return ret;
+}
+
+status_t CameraHardwareInterface::setPreviewScalingMode(int scalingMode)
+{
+    int rc = OK;
+    mPreviewScalingMode = scalingMode;
+    if (mPreviewWindow != nullptr) {
+        rc = native_window_set_scaling_mode(mPreviewWindow.get(),
+                scalingMode);
+    }
+    return rc;
+}
+
+status_t CameraHardwareInterface::setPreviewTransform(int transform) {
+    int rc = OK;
+    mPreviewTransform = transform;
+    if (mPreviewWindow != nullptr) {
+        rc = native_window_set_buffers_transform(mPreviewWindow.get(),
+                mPreviewTransform);
+    }
+    return rc;
+}
+
+/**
+ * Implementation of android::hardware::camera::device::V1_0::ICameraDeviceCallback
+ */
+hardware::Return<void> CameraHardwareInterface::notifyCallback(
+        NotifyCallbackMsg msgType, int32_t ext1, int32_t ext2) {
+    sNotifyCb((int32_t) msgType, ext1, ext2, (void*) this);
+    return hardware::Void();
+}
+
+hardware::Return<uint32_t> CameraHardwareInterface::registerMemory(
+        const hardware::hidl_handle& descriptor,
+        uint32_t bufferSize, uint32_t bufferCount) {
+    if (descriptor->numFds != 1) {
+        ALOGE("%s: camera memory descriptor has numFds %d (expect 1)",
+                __FUNCTION__, descriptor->numFds);
+        return 0;
+    }
+    if (descriptor->data[0] < 0) {
+        ALOGE("%s: camera memory descriptor has FD %d (expect >= 0)",
+                __FUNCTION__, descriptor->data[0]);
+        return 0;
+    }
+
+    camera_memory_t* mem = sGetMemory(descriptor->data[0], bufferSize, bufferCount, this);
+    sp<CameraHeapMemory> camMem(static_cast<CameraHeapMemory *>(mem->handle));
+    int memPoolId = camMem->mHeap->getHeapID();
+    if (memPoolId < 0) {
+        ALOGE("%s: CameraHeapMemory has FD %d (expect >= 0)", __FUNCTION__, memPoolId);
+        return 0;
+    }
+    mHidlMemPoolMap.insert(std::make_pair(memPoolId, mem));
+    return memPoolId;
+}
+
+hardware::Return<void> CameraHardwareInterface::unregisterMemory(uint32_t memId) {
+    if (mHidlMemPoolMap.count(memId) == 0) {
+        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
+        return hardware::Void();
+    }
+    camera_memory_t* mem = mHidlMemPoolMap.at(memId);
+    sPutMemory(mem);
+    mHidlMemPoolMap.erase(memId);
+    return hardware::Void();
+}
+
+hardware::Return<void> CameraHardwareInterface::dataCallback(
+        DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex,
+        const hardware::camera::device::V1_0::CameraFrameMetadata& metadata) {
+    if (mHidlMemPoolMap.count(data) == 0) {
+        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+        return hardware::Void();
+    }
+    camera_frame_metadata_t md;
+    md.number_of_faces = metadata.faces.size();
+    md.faces = (camera_face_t*) metadata.faces.data();
+    sDataCb((int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, &md, this);
+    return hardware::Void();
+}
+
+hardware::Return<void> CameraHardwareInterface::dataCallbackTimestamp(
+        DataCallbackMsg msgType, uint32_t data,
+        uint32_t bufferIndex, int64_t timestamp) {
+    if (mHidlMemPoolMap.count(data) == 0) {
+        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+        return hardware::Void();
+    }
+    sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+    return hardware::Void();
+}
+
+hardware::Return<void> CameraHardwareInterface::handleCallbackTimestamp(
+        DataCallbackMsg msgType, const hidl_handle& frameData, uint32_t data,
+        uint32_t bufferIndex, int64_t timestamp) {
+    if (mHidlMemPoolMap.count(data) == 0) {
+        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+        return hardware::Void();
+    }
+    sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(data)->handle));
+    VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
+            mem->mBuffers[bufferIndex]->pointer();
+    md->pHandle = const_cast<native_handle_t*>(frameData.getNativeHandle());
+    sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+    return hardware::Void();
+}
+
+std::pair<bool, uint64_t> CameraHardwareInterface::getBufferId(
+        ANativeWindowBuffer* anb) {
+    std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+    buffer_handle_t& buf = anb->handle;
+    auto it = mBufferIdMap.find(buf);
+    if (it == mBufferIdMap.end()) {
+        uint64_t bufId = mNextBufferId++;
+        mBufferIdMap[buf] = bufId;
+        mReversedBufMap[bufId] = anb;
+        return std::make_pair(true, bufId);
+    } else {
+        return std::make_pair(false, it->second);
+    }
+}
+
+void CameraHardwareInterface::cleanupCirculatingBuffers() {
+    std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+    mBufferIdMap.clear();
+    mReversedBufMap.clear();
+}
+
+hardware::Return<void>
+CameraHardwareInterface::dequeueBuffer(dequeueBuffer_cb _hidl_cb) {
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return hardware::Void();
+    }
+    ANativeWindowBuffer* anb;
+    int rc = native_window_dequeue_buffer_and_wait(a, &anb);
+    Status s = Status::INTERNAL_ERROR;
+    uint64_t bufferId = 0;
+    uint32_t stride = 0;
+    hidl_handle buf = nullptr;
+    if (rc == OK) {
+        s = Status::OK;
+        auto pair = getBufferId(anb);
+        buf = (pair.first) ? anb->handle : nullptr;
+        bufferId = pair.second;
+        stride = anb->stride;
+    }
+
+    _hidl_cb(s, bufferId, buf, stride);
+    return hardware::Void();
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::enqueueBuffer(uint64_t bufferId) {
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+    if (mReversedBufMap.count(bufferId) == 0) {
+        ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    int rc = a->queueBuffer(a, mReversedBufMap.at(bufferId), -1);
+    if (rc == 0) {
+        return Status::OK;
+    }
+    return Status::INTERNAL_ERROR;
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::cancelBuffer(uint64_t bufferId) {
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+    if (mReversedBufMap.count(bufferId) == 0) {
+        ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    int rc = a->cancelBuffer(a, mReversedBufMap.at(bufferId), -1);
+    if (rc == 0) {
+        return Status::OK;
+    }
+    return Status::INTERNAL_ERROR;
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::setBufferCount(uint32_t count) {
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a != nullptr) {
+        // Workaround for b/27039775
+        // Previously, setting the buffer count would reset the buffer
+        // queue's flag that allows for all buffers to be dequeued on the
+        // producer side, instead of just the producer's declared max count,
+        // if no filled buffers have yet been queued by the producer.  This
+        // reset no longer happens, but some HALs depend on this behavior,
+        // so it needs to be maintained for HAL backwards compatibility.
+        // Simulate the prior behavior by disconnecting/reconnecting to the
+        // window and setting the values again.  This has the drawback of
+        // actually causing memory reallocation, which may not have happened
+        // in the past.
+        native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
+        native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
+        if (mPreviewScalingMode != NOT_SET) {
+            native_window_set_scaling_mode(a, mPreviewScalingMode);
+        }
+        if (mPreviewTransform != NOT_SET) {
+            native_window_set_buffers_transform(a, mPreviewTransform);
+        }
+        if (mPreviewWidth != NOT_SET) {
+            native_window_set_buffers_dimensions(a,
+                    mPreviewWidth, mPreviewHeight);
+            native_window_set_buffers_format(a, mPreviewFormat);
+        }
+        if (mPreviewUsage != 0) {
+            native_window_set_usage(a, mPreviewUsage);
+        }
+        if (mPreviewSwapInterval != NOT_SET) {
+            a->setSwapInterval(a, mPreviewSwapInterval);
+        }
+        if (mPreviewCrop.left != NOT_SET) {
+            native_window_set_crop(a, &(mPreviewCrop));
+        }
+    }
+    int rc = native_window_set_buffer_count(a, count);
+    if (rc == OK) {
+        cleanupCirculatingBuffers();
+        return Status::OK;
+    }
+    return Status::INTERNAL_ERROR;
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::setBuffersGeometry(
+        uint32_t w, uint32_t h, hardware::graphics::common::V1_0::PixelFormat format) {
+    Status s = Status::INTERNAL_ERROR;
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return s;
+    }
+    mPreviewWidth = w;
+    mPreviewHeight = h;
+    mPreviewFormat = (int) format;
+    int rc = native_window_set_buffers_dimensions(a, w, h);
+    if (rc == OK) {
+        rc = native_window_set_buffers_format(a, mPreviewFormat);
+    }
+    if (rc == OK) {
+        cleanupCirculatingBuffers();
+        s = Status::OK;
+    }
+    return s;
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom) {
+    Status s = Status::INTERNAL_ERROR;
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return s;
+    }
+    mPreviewCrop.left = left;
+    mPreviewCrop.top = top;
+    mPreviewCrop.right = right;
+    mPreviewCrop.bottom = bottom;
+    int rc = native_window_set_crop(a, &mPreviewCrop);
+    if (rc == OK) {
+        s = Status::OK;
+    }
+    return s;
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::setUsage(hardware::graphics::allocator::V2_0::ProducerUsage usage) {
+    Status s = Status::INTERNAL_ERROR;
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return s;
+    }
+    mPreviewUsage = (int) usage;
+    int rc = native_window_set_usage(a, mPreviewUsage);
+    if (rc == OK) {
+        cleanupCirculatingBuffers();
+        s = Status::OK;
+    }
+    return s;
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::setSwapInterval(int32_t interval) {
+    Status s = Status::INTERNAL_ERROR;
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return s;
+    }
+    mPreviewSwapInterval = interval;
+    int rc = a->setSwapInterval(a, interval);
+    if (rc == OK) {
+        s = Status::OK;
+    }
+    return s;
+}
+
+hardware::Return<void>
+CameraHardwareInterface::getMinUndequeuedBufferCount(getMinUndequeuedBufferCount_cb _hidl_cb) {
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return hardware::Void();
+    }
+    int count = 0;
+    int rc = a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &count);
+    Status s = Status::INTERNAL_ERROR;
+    if (rc == OK) {
+        s = Status::OK;
+    }
+    _hidl_cb(s, count);
+    return hardware::Void();
+}
+
+hardware::Return<Status>
+CameraHardwareInterface::setTimestamp(int64_t timestamp) {
+    Status s = Status::INTERNAL_ERROR;
+    ANativeWindow *a = mPreviewWindow.get();
+    if (a == nullptr) {
+        ALOGE("%s: preview window is null", __FUNCTION__);
+        return s;
+    }
+    int rc = native_window_set_buffers_timestamp(a, timestamp);
+    if (rc == OK) {
+        s = Status::OK;
+    }
+    return s;
+}
+
+status_t CameraHardwareInterface::setPreviewWindow(const sp<ANativeWindow>& buf)
+{
+    ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        mPreviewWindow = buf;
+        if (buf != nullptr) {
+            if (mPreviewScalingMode != NOT_SET) {
+                setPreviewScalingMode(mPreviewScalingMode);
+            }
+            if (mPreviewTransform != NOT_SET) {
+                setPreviewTransform(mPreviewTransform);
+            }
+        }
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->setPreviewWindow(buf.get() ? this : nullptr));
+    } else if (mDevice) {
+        if (mDevice->ops->set_preview_window) {
+            mPreviewWindow = buf;
+            if (buf != nullptr) {
+                if (mPreviewScalingMode != NOT_SET) {
+                    setPreviewScalingMode(mPreviewScalingMode);
+                }
+                if (mPreviewTransform != NOT_SET) {
+                    setPreviewTransform(mPreviewTransform);
+                }
+            }
+            mHalPreviewWindow.user = this;
+            ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p",__FUNCTION__,
+                    &mHalPreviewWindow, mHalPreviewWindow.user);
+            return mDevice->ops->set_preview_window(mDevice,
+                    buf.get() ? &mHalPreviewWindow.nw : 0);
+        }
+    }
+    return INVALID_OPERATION;
+}
+
+void CameraHardwareInterface::setCallbacks(notify_callback notify_cb,
+        data_callback data_cb,
+        data_callback_timestamp data_cb_timestamp,
+        void* user)
+{
+    mNotifyCb = notify_cb;
+    mDataCb = data_cb;
+    mDataCbTimestamp = data_cb_timestamp;
+    mCbUser = user;
+
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+
+    if (mDevice && mDevice->ops->set_callbacks) {
+        mDevice->ops->set_callbacks(mDevice,
+                               sNotifyCb,
+                               sDataCb,
+                               sDataCbTimestamp,
+                               sGetMemory,
+                               this);
+    }
+}
+
+void CameraHardwareInterface::enableMsgType(int32_t msgType)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        mHidlDevice->enableMsgType(msgType);
+    } else if (mDevice && mDevice->ops->enable_msg_type) {
+        mDevice->ops->enable_msg_type(mDevice, msgType);
+    }
+}
+
+void CameraHardwareInterface::disableMsgType(int32_t msgType)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        mHidlDevice->disableMsgType(msgType);
+    } else if (mDevice && mDevice->ops->disable_msg_type) {
+        mDevice->ops->disable_msg_type(mDevice, msgType);
+    }
+}
+
+int CameraHardwareInterface::msgTypeEnabled(int32_t msgType)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return mHidlDevice->msgTypeEnabled(msgType);
+    } else if (mDevice && mDevice->ops->msg_type_enabled) {
+        return mDevice->ops->msg_type_enabled(mDevice, msgType);
+    }
+    return false;
+}
+
+status_t CameraHardwareInterface::startPreview()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->startPreview());
+    } else if (mDevice && mDevice->ops->start_preview) {
+        return mDevice->ops->start_preview(mDevice);
+    }
+    return INVALID_OPERATION;
+}
+
+void CameraHardwareInterface::stopPreview()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        mHidlDevice->stopPreview();
+    } else if (mDevice && mDevice->ops->stop_preview) {
+        mDevice->ops->stop_preview(mDevice);
+    }
+}
+
+int CameraHardwareInterface::previewEnabled()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return mHidlDevice->previewEnabled();
+    } else if (mDevice && mDevice->ops->preview_enabled) {
+        return mDevice->ops->preview_enabled(mDevice);
+    }
+    return false;
+}
+
+status_t CameraHardwareInterface::storeMetaDataInBuffers(int enable)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->storeMetaDataInBuffers(enable));
+    } else if (mDevice && mDevice->ops->store_meta_data_in_buffers) {
+        return mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
+    }
+    return enable ? INVALID_OPERATION: OK;
+}
+
+status_t CameraHardwareInterface::startRecording()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->startRecording());
+    } else if (mDevice && mDevice->ops->start_recording) {
+        return mDevice->ops->start_recording(mDevice);
+    }
+    return INVALID_OPERATION;
+}
+
+/**
+ * Stop a previously started recording.
+ */
+void CameraHardwareInterface::stopRecording()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        mHidlDevice->stopRecording();
+    } else if (mDevice && mDevice->ops->stop_recording) {
+        mDevice->ops->stop_recording(mDevice);
+    }
+}
+
+/**
+ * Returns true if recording is enabled.
+ */
+int CameraHardwareInterface::recordingEnabled()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return mHidlDevice->recordingEnabled();
+    } else if (mDevice && mDevice->ops->recording_enabled) {
+        return mDevice->ops->recording_enabled(mDevice);
+    }
+    return false;
+}
+
+void CameraHardwareInterface::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    int heapId = heap->getHeapID();
+    int bufferIndex = offset / size;
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        if (size == sizeof(VideoNativeHandleMetadata)) {
+            VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->pointer();
+            // Caching the handle here because md->pHandle will be subject to HAL's edit
+            native_handle_t* nh = md->pHandle;
+            hidl_handle frame = nh;
+            mHidlDevice->releaseRecordingFrameHandle(heapId, bufferIndex, frame);
+            native_handle_close(nh);
+            native_handle_delete(nh);
+        } else {
+            mHidlDevice->releaseRecordingFrame(heapId, bufferIndex);
+        }
+    } else if (mDevice && mDevice->ops->release_recording_frame) {
+        void *data = ((uint8_t *)heap->base()) + offset;
+        return mDevice->ops->release_recording_frame(mDevice, data);
+    }
+}
+
+status_t CameraHardwareInterface::autoFocus()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->autoFocus());
+    } else if (mDevice && mDevice->ops->auto_focus) {
+        return mDevice->ops->auto_focus(mDevice);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t CameraHardwareInterface::cancelAutoFocus()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->cancelAutoFocus());
+    } else if (mDevice && mDevice->ops->cancel_auto_focus) {
+        return mDevice->ops->cancel_auto_focus(mDevice);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t CameraHardwareInterface::takePicture()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->takePicture());
+    } else if (mDevice && mDevice->ops->take_picture) {
+        return mDevice->ops->take_picture(mDevice);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t CameraHardwareInterface::cancelPicture()
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->cancelPicture());
+    } else if (mDevice && mDevice->ops->cancel_picture) {
+        return mDevice->ops->cancel_picture(mDevice);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t CameraHardwareInterface::setParameters(const CameraParameters &params)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->setParameters(params.flatten().string()));
+    } else if (mDevice && mDevice->ops->set_parameters) {
+        return mDevice->ops->set_parameters(mDevice, params.flatten().string());
+    }
+    return INVALID_OPERATION;
+}
+
+CameraParameters CameraHardwareInterface::getParameters() const
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    CameraParameters parms;
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        hardware::hidl_string outParam;
+        mHidlDevice->getParameters(
+                [&outParam](const auto& outStr) {
+                    outParam = outStr;
+                });
+        String8 tmp(outParam.c_str());
+        parms.unflatten(tmp);
+    } else if (mDevice && mDevice->ops->get_parameters) {
+        char *temp = mDevice->ops->get_parameters(mDevice);
+        String8 str_parms(temp);
+        if (mDevice->ops->put_parameters)
+            mDevice->ops->put_parameters(mDevice, temp);
+        else
+            free(temp);
+        parms.unflatten(str_parms);
+    }
+    return parms;
+}
+
+status_t CameraHardwareInterface::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        return CameraProviderManager::mapToStatusT(
+                mHidlDevice->sendCommand((CommandType) cmd, arg1, arg2));
+    } else if (mDevice && mDevice->ops->send_command) {
+        return mDevice->ops->send_command(mDevice, cmd, arg1, arg2);
+    }
+    return INVALID_OPERATION;
+}
+
+/**
+ * Release the hardware resources owned by this object.  Note that this is
+ * *not* done in the destructor.
+ */
+void CameraHardwareInterface::release() {
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        mHidlDevice->close();
+        mHidlDevice.clear();
+    } else if (mDevice && mDevice->ops->release) {
+        mDevice->ops->release(mDevice);
+    }
+}
+
+/**
+ * Dump state of the camera hardware
+ */
+status_t CameraHardwareInterface::dump(int fd, const Vector<String16>& /*args*/) const
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    if (CC_LIKELY(mHidlDevice != nullptr)) {
+        native_handle_t* handle = native_handle_create(1,0);
+        handle->data[0] = fd;
+        Status s = mHidlDevice->dumpState(handle);
+        native_handle_delete(handle);
+        return CameraProviderManager::mapToStatusT(s);
+    } else if (mDevice && mDevice->ops->dump) {
+        return mDevice->ops->dump(mDevice, fd);
+    }
+    return OK; // It's fine if the HAL doesn't implement dump()
+}
+
+/**
+ * Methods for legacy (non-HIDL) path follows
+ */
+void CameraHardwareInterface::sNotifyCb(int32_t msg_type, int32_t ext1,
+                        int32_t ext2, void *user)
+{
+    ALOGV("%s", __FUNCTION__);
+    CameraHardwareInterface *object =
+            static_cast<CameraHardwareInterface *>(user);
+    object->mNotifyCb(msg_type, ext1, ext2, object->mCbUser);
+}
+
+void CameraHardwareInterface::sDataCb(int32_t msg_type,
+                      const camera_memory_t *data, unsigned int index,
+                      camera_frame_metadata_t *metadata,
+                      void *user)
+{
+    ALOGV("%s", __FUNCTION__);
+    CameraHardwareInterface *object =
+            static_cast<CameraHardwareInterface *>(user);
+    sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+    if (index >= mem->mNumBufs) {
+        ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+             index, mem->mNumBufs);
+        return;
+    }
+    object->mDataCb(msg_type, mem->mBuffers[index], metadata, object->mCbUser);
+}
+
+void CameraHardwareInterface::sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type,
+                         const camera_memory_t *data, unsigned index,
+                         void *user)
+{
+    ALOGV("%s", __FUNCTION__);
+    CameraHardwareInterface *object =
+            static_cast<CameraHardwareInterface *>(user);
+    // Start refcounting the heap object from here on.  When the clients
+    // drop all references, it will be destroyed (as well as the enclosed
+    // MemoryHeapBase.
+    sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+    if (index >= mem->mNumBufs) {
+        ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+             index, mem->mNumBufs);
+        return;
+    }
+    object->mDataCbTimestamp(timestamp, msg_type, mem->mBuffers[index], object->mCbUser);
+}
+
+camera_memory_t* CameraHardwareInterface::sGetMemory(
+        int fd, size_t buf_size, uint_t num_bufs,
+        void *user __attribute__((unused)))
+{
+    CameraHeapMemory *mem;
+    if (fd < 0) {
+        mem = new CameraHeapMemory(buf_size, num_bufs);
+    } else {
+        mem = new CameraHeapMemory(fd, buf_size, num_bufs);
+    }
+    mem->incStrong(mem);
+    return &mem->handle;
+}
+
+void CameraHardwareInterface::sPutMemory(camera_memory_t *data)
+{
+    if (!data) {
+        return;
+    }
+
+    CameraHeapMemory *mem = static_cast<CameraHeapMemory *>(data->handle);
+    mem->decStrong(mem);
+}
+
+ANativeWindow* CameraHardwareInterface::sToAnw(void *user)
+{
+    CameraHardwareInterface *object =
+            reinterpret_cast<CameraHardwareInterface *>(user);
+    return object->mPreviewWindow.get();
+}
+#define anw(n) sToAnw(((struct camera_preview_window *)(n))->user)
+#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
+    ((struct camera_preview_window *)(n))->user)
+
+int CameraHardwareInterface::sDequeueBuffer(struct preview_stream_ops* w,
+                            buffer_handle_t** buffer, int *stride)
+{
+    int rc;
+    ANativeWindow *a = anw(w);
+    ANativeWindowBuffer* anb;
+    rc = native_window_dequeue_buffer_and_wait(a, &anb);
+    if (rc == OK) {
+        *buffer = &anb->handle;
+        *stride = anb->stride;
+    }
+    return rc;
+}
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+    const __typeof__(((type *) 0)->member) *__mptr = (ptr);     \
+    (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
+#endif
+
+int CameraHardwareInterface::sLockBuffer(struct preview_stream_ops* w,
+                  buffer_handle_t* /*buffer*/)
+{
+    ANativeWindow *a = anw(w);
+    (void)a;
+    return 0;
+}
+
+int CameraHardwareInterface::sEnqueueBuffer(struct preview_stream_ops* w,
+                  buffer_handle_t* buffer)
+{
+    ANativeWindow *a = anw(w);
+    return a->queueBuffer(a,
+              container_of(buffer, ANativeWindowBuffer, handle), -1);
+}
+
+int CameraHardwareInterface::sCancelBuffer(struct preview_stream_ops* w,
+                  buffer_handle_t* buffer)
+{
+    ANativeWindow *a = anw(w);
+    return a->cancelBuffer(a,
+              container_of(buffer, ANativeWindowBuffer, handle), -1);
+}
+
+int CameraHardwareInterface::sSetBufferCount(struct preview_stream_ops* w, int count)
+{
+    ANativeWindow *a = anw(w);
+
+    if (a != nullptr) {
+        // Workaround for b/27039775
+        // Previously, setting the buffer count would reset the buffer
+        // queue's flag that allows for all buffers to be dequeued on the
+        // producer side, instead of just the producer's declared max count,
+        // if no filled buffers have yet been queued by the producer.  This
+        // reset no longer happens, but some HALs depend on this behavior,
+        // so it needs to be maintained for HAL backwards compatibility.
+        // Simulate the prior behavior by disconnecting/reconnecting to the
+        // window and setting the values again.  This has the drawback of
+        // actually causing memory reallocation, which may not have happened
+        // in the past.
+        CameraHardwareInterface *hw = hwi(w);
+        native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
+        native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
+        if (hw->mPreviewScalingMode != NOT_SET) {
+            native_window_set_scaling_mode(a, hw->mPreviewScalingMode);
+        }
+        if (hw->mPreviewTransform != NOT_SET) {
+            native_window_set_buffers_transform(a, hw->mPreviewTransform);
+        }
+        if (hw->mPreviewWidth != NOT_SET) {
+            native_window_set_buffers_dimensions(a,
+                    hw->mPreviewWidth, hw->mPreviewHeight);
+            native_window_set_buffers_format(a, hw->mPreviewFormat);
+        }
+        if (hw->mPreviewUsage != 0) {
+            native_window_set_usage(a, hw->mPreviewUsage);
+        }
+        if (hw->mPreviewSwapInterval != NOT_SET) {
+            a->setSwapInterval(a, hw->mPreviewSwapInterval);
+        }
+        if (hw->mPreviewCrop.left != NOT_SET) {
+            native_window_set_crop(a, &(hw->mPreviewCrop));
+        }
+    }
+
+    return native_window_set_buffer_count(a, count);
+}
+
+int CameraHardwareInterface::sSetBuffersGeometry(struct preview_stream_ops* w,
+                  int width, int height, int format)
+{
+    int rc;
+    ANativeWindow *a = anw(w);
+    CameraHardwareInterface *hw = hwi(w);
+    hw->mPreviewWidth = width;
+    hw->mPreviewHeight = height;
+    hw->mPreviewFormat = format;
+    rc = native_window_set_buffers_dimensions(a, width, height);
+    if (rc == OK) {
+        rc = native_window_set_buffers_format(a, format);
+    }
+    return rc;
+}
+
+int CameraHardwareInterface::sSetCrop(struct preview_stream_ops *w,
+                  int left, int top, int right, int bottom)
+{
+    ANativeWindow *a = anw(w);
+    CameraHardwareInterface *hw = hwi(w);
+    hw->mPreviewCrop.left = left;
+    hw->mPreviewCrop.top = top;
+    hw->mPreviewCrop.right = right;
+    hw->mPreviewCrop.bottom = bottom;
+    return native_window_set_crop(a, &(hw->mPreviewCrop));
+}
+
+int CameraHardwareInterface::sSetTimestamp(struct preview_stream_ops *w,
+                           int64_t timestamp) {
+    ANativeWindow *a = anw(w);
+    return native_window_set_buffers_timestamp(a, timestamp);
+}
+
+int CameraHardwareInterface::sSetUsage(struct preview_stream_ops* w, int usage)
+{
+    ANativeWindow *a = anw(w);
+    CameraHardwareInterface *hw = hwi(w);
+    hw->mPreviewUsage = usage;
+    return native_window_set_usage(a, usage);
+}
+
+int CameraHardwareInterface::sSetSwapInterval(struct preview_stream_ops *w, int interval)
+{
+    ANativeWindow *a = anw(w);
+    CameraHardwareInterface *hw = hwi(w);
+    hw->mPreviewSwapInterval = interval;
+    return a->setSwapInterval(a, interval);
+}
+
+int CameraHardwareInterface::sGetMinUndequeuedBufferCount(
+                  const struct preview_stream_ops *w,
+                  int *count)
+{
+    ANativeWindow *a = anw(w);
+    return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
+}
+
+void CameraHardwareInterface::initHalPreviewWindow()
+{
+    mHalPreviewWindow.nw.cancel_buffer = sCancelBuffer;
+    mHalPreviewWindow.nw.lock_buffer = sLockBuffer;
+    mHalPreviewWindow.nw.dequeue_buffer = sDequeueBuffer;
+    mHalPreviewWindow.nw.enqueue_buffer = sEnqueueBuffer;
+    mHalPreviewWindow.nw.set_buffer_count = sSetBufferCount;
+    mHalPreviewWindow.nw.set_buffers_geometry = sSetBuffersGeometry;
+    mHalPreviewWindow.nw.set_crop = sSetCrop;
+    mHalPreviewWindow.nw.set_timestamp = sSetTimestamp;
+    mHalPreviewWindow.nw.set_usage = sSetUsage;
+    mHalPreviewWindow.nw.set_swap_interval = sSetSwapInterval;
+
+    mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
+            sGetMinUndequeuedBufferCount;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index c8210b7..88ab2e9 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
 #define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
 
+#include <unordered_map>
 #include <binder/IMemory.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
@@ -74,10 +75,15 @@
  * provided in a data callback must be copied if it's needed after returning.
  */
 
-class CameraHardwareInterface : public virtual RefBase {
+class CameraHardwareInterface :
+        public virtual RefBase,
+        public virtual hardware::camera::device::V1_0::ICameraDeviceCallback,
+        public virtual hardware::camera::device::V1_0::ICameraDevicePreviewCallback {
+
 public:
     explicit CameraHardwareInterface(const char *name):
             mDevice(nullptr),
+            mHidlDevice(nullptr),
             mName(name),
             mPreviewScalingMode(NOT_SET),
             mPreviewTransform(NOT_SET),
@@ -90,115 +96,23 @@
     {
     }
 
-    ~CameraHardwareInterface()
-    {
-        ALOGI("Destroying camera %s", mName.string());
-        if(mDevice) {
-            int rc = mDevice->common.close(&mDevice->common);
-            if (rc != OK)
-                ALOGE("Could not close camera %s: %d", mName.string(), rc);
-        }
-    }
+    ~CameraHardwareInterface();
 
-    status_t initialize(CameraModule *module)
-    {
-        ALOGI("Opening camera %s", mName.string());
-        camera_info info;
-        status_t res = module->getCameraInfo(atoi(mName.string()), &info);
-        if (res != OK) {
-            return res;
-        }
-
-        int rc = OK;
-        if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
-            info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
-            // Open higher version camera device as HAL1.0 device.
-            rc = module->openLegacy(mName.string(),
-                                     CAMERA_DEVICE_API_VERSION_1_0,
-                                     (hw_device_t **)&mDevice);
-        } else {
-            rc = module->open(mName.string(), (hw_device_t **)&mDevice);
-        }
-        if (rc != OK) {
-            ALOGE("Could not open camera %s: %d", mName.string(), rc);
-            return rc;
-        }
-        initHalPreviewWindow();
-        return rc;
-    }
-
-    status_t initialize(sp<CameraProviderManager> manager) {
-        (void) manager;
-        ALOGE("%s: Not supported yet", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
+    status_t initialize(CameraModule *module);
+    status_t initialize(sp<CameraProviderManager> manager);
 
     /** Set the ANativeWindow to which preview frames are sent */
-    status_t setPreviewWindow(const sp<ANativeWindow>& buf)
-    {
-        ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
-        if (mDevice->ops->set_preview_window) {
-            mPreviewWindow = buf;
-            if (buf != nullptr) {
-                if (mPreviewScalingMode != NOT_SET) {
-                    setPreviewScalingMode(mPreviewScalingMode);
-                }
-                if (mPreviewTransform != NOT_SET) {
-                    setPreviewTransform(mPreviewTransform);
-                }
-            }
-            mHalPreviewWindow.user = this;
-            ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
-                    &mHalPreviewWindow, mHalPreviewWindow.user);
-            return mDevice->ops->set_preview_window(mDevice,
-                    buf.get() ? &mHalPreviewWindow.nw : 0);
-        }
-        return INVALID_OPERATION;
-    }
+    status_t setPreviewWindow(const sp<ANativeWindow>& buf);
 
-    status_t setPreviewScalingMode(int scalingMode)
-    {
-        int rc = OK;
-        mPreviewScalingMode = scalingMode;
-        if (mPreviewWindow != nullptr) {
-            rc = native_window_set_scaling_mode(mPreviewWindow.get(),
-                    scalingMode);
-        }
-        return rc;
-    }
+    status_t setPreviewScalingMode(int scalingMode);
 
-    status_t setPreviewTransform(int transform) {
-        int rc = OK;
-        mPreviewTransform = transform;
-        if (mPreviewWindow != nullptr) {
-            rc = native_window_set_buffers_transform(mPreviewWindow.get(),
-                    mPreviewTransform);
-        }
-        return rc;
-    }
+    status_t setPreviewTransform(int transform);
 
     /** Set the notification and data callbacks */
     void setCallbacks(notify_callback notify_cb,
                       data_callback data_cb,
                       data_callback_timestamp data_cb_timestamp,
-                      void* user)
-    {
-        mNotifyCb = notify_cb;
-        mDataCb = data_cb;
-        mDataCbTimestamp = data_cb_timestamp;
-        mCbUser = user;
-
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-
-        if (mDevice->ops->set_callbacks) {
-            mDevice->ops->set_callbacks(mDevice,
-                                   __notify_cb,
-                                   __data_cb,
-                                   __data_cb_timestamp,
-                                   __get_memory,
-                                   this);
-        }
-    }
+                      void* user);
 
     /**
      * The following three functions all take a msgtype,
@@ -209,12 +123,7 @@
     /**
      * Enable a message, or set of messages.
      */
-    void enableMsgType(int32_t msgType)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->enable_msg_type)
-            mDevice->ops->enable_msg_type(mDevice, msgType);
-    }
+    void enableMsgType(int32_t msgType);
 
     /**
      * Disable a message, or a set of messages.
@@ -226,57 +135,29 @@
      * modify/access any video recording frame after calling
      * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
      */
-    void disableMsgType(int32_t msgType)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->disable_msg_type)
-            mDevice->ops->disable_msg_type(mDevice, msgType);
-    }
+    void disableMsgType(int32_t msgType);
 
     /**
      * Query whether a message, or a set of messages, is enabled.
      * Note that this is operates as an AND, if any of the messages
      * queried are off, this will return false.
      */
-    int msgTypeEnabled(int32_t msgType)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->msg_type_enabled)
-            return mDevice->ops->msg_type_enabled(mDevice, msgType);
-        return false;
-    }
+    int msgTypeEnabled(int32_t msgType);
 
     /**
      * Start preview mode.
      */
-    status_t startPreview()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->start_preview)
-            return mDevice->ops->start_preview(mDevice);
-        return INVALID_OPERATION;
-    }
+    status_t startPreview();
 
     /**
      * Stop a previously started preview.
      */
-    void stopPreview()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->stop_preview)
-            mDevice->ops->stop_preview(mDevice);
-    }
+    void stopPreview();
 
     /**
      * Returns true if preview is enabled.
      */
-    int previewEnabled()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->preview_enabled)
-            return mDevice->ops->preview_enabled(mDevice);
-        return false;
-    }
+    int previewEnabled();
 
     /**
      * Request the camera hal to store meta data or real YUV data in
@@ -310,13 +191,7 @@
      * @return OK on success.
      */
 
-    status_t storeMetaDataInBuffers(int enable)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->store_meta_data_in_buffers)
-            return mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
-        return enable ? INVALID_OPERATION: OK;
-    }
+    status_t storeMetaDataInBuffers(int enable);
 
     /**
      * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
@@ -327,34 +202,17 @@
      * to manage the life-cycle of the video recording frames, and the client must
      * not modify/access any video recording frames.
      */
-    status_t startRecording()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->start_recording)
-            return mDevice->ops->start_recording(mDevice);
-        return INVALID_OPERATION;
-    }
+    status_t startRecording();
 
     /**
      * Stop a previously started recording.
      */
-    void stopRecording()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->stop_recording)
-            mDevice->ops->stop_recording(mDevice);
-    }
+    void stopRecording();
 
     /**
      * Returns true if recording is enabled.
      */
-    int recordingEnabled()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->recording_enabled)
-            return mDevice->ops->recording_enabled(mDevice);
-        return false;
-    }
+    int recordingEnabled();
 
     /**
      * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
@@ -366,30 +224,14 @@
      * responsibility of managing the life-cycle of the video recording
      * frames.
      */
-    void releaseRecordingFrame(const sp<IMemory>& mem)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->release_recording_frame) {
-            ssize_t offset;
-            size_t size;
-            sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-            void *data = ((uint8_t *)heap->base()) + offset;
-            return mDevice->ops->release_recording_frame(mDevice, data);
-        }
-    }
+    void releaseRecordingFrame(const sp<IMemory>& mem);
 
     /**
      * Start auto focus, the notification callback routine is called
      * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
      * will be called again if another auto focus is needed.
      */
-    status_t autoFocus()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->auto_focus)
-            return mDevice->ops->auto_focus(mDevice);
-        return INVALID_OPERATION;
-    }
+    status_t autoFocus();
 
     /**
      * Cancels auto-focus function. If the auto-focus is still in progress,
@@ -397,151 +239,73 @@
      * or not, this function will return the focus position to the default.
      * If the camera does not support auto-focus, this is a no-op.
      */
-    status_t cancelAutoFocus()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->cancel_auto_focus)
-            return mDevice->ops->cancel_auto_focus(mDevice);
-        return INVALID_OPERATION;
-    }
+    status_t cancelAutoFocus();
 
     /**
      * Take a picture.
      */
-    status_t takePicture()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->take_picture)
-            return mDevice->ops->take_picture(mDevice);
-        return INVALID_OPERATION;
-    }
+    status_t takePicture();
 
     /**
      * Cancel a picture that was started with takePicture.  Calling this
      * method when no picture is being taken is a no-op.
      */
-    status_t cancelPicture()
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->cancel_picture)
-            return mDevice->ops->cancel_picture(mDevice);
-        return INVALID_OPERATION;
-    }
+    status_t cancelPicture();
 
     /**
      * Set the camera parameters. This returns BAD_VALUE if any parameter is
      * invalid or not supported. */
-    status_t setParameters(const CameraParameters &params)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->set_parameters)
-            return mDevice->ops->set_parameters(mDevice,
-                                               params.flatten().string());
-        return INVALID_OPERATION;
-    }
+    status_t setParameters(const CameraParameters &params);
 
     /** Return the camera parameters. */
-    CameraParameters getParameters() const
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        CameraParameters parms;
-        if (mDevice->ops->get_parameters) {
-            char *temp = mDevice->ops->get_parameters(mDevice);
-            String8 str_parms(temp);
-            if (mDevice->ops->put_parameters)
-                mDevice->ops->put_parameters(mDevice, temp);
-            else
-                free(temp);
-            parms.unflatten(str_parms);
-        }
-        return parms;
-    }
+    CameraParameters getParameters() const;
 
     /**
      * Send command to camera driver.
      */
-    status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->send_command)
-            return mDevice->ops->send_command(mDevice, cmd, arg1, arg2);
-        return INVALID_OPERATION;
-    }
+    status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
 
     /**
      * Release the hardware resources owned by this object.  Note that this is
      * *not* done in the destructor.
      */
-    void release() {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->release)
-            mDevice->ops->release(mDevice);
-    }
+    void release();
 
     /**
      * Dump state of the camera hardware
      */
-    status_t dump(int fd, const Vector<String16>& /*args*/) const
-    {
-        ALOGV("%s(%s)", __FUNCTION__, mName.string());
-        if (mDevice->ops->dump)
-            return mDevice->ops->dump(mDevice, fd);
-        return OK; // It's fine if the HAL doesn't implement dump()
-    }
+    status_t dump(int fd, const Vector<String16>& /*args*/) const;
 
 private:
     camera_device_t *mDevice;
+    sp<hardware::camera::device::V1_0::ICameraDevice> mHidlDevice;
     String8 mName;
 
-    static void __notify_cb(int32_t msg_type, int32_t ext1,
-                            int32_t ext2, void *user)
-    {
-        ALOGV("%s", __FUNCTION__);
-        CameraHardwareInterface *__this =
-                static_cast<CameraHardwareInterface *>(user);
-        __this->mNotifyCb(msg_type, ext1, ext2, __this->mCbUser);
-    }
+    static void sNotifyCb(int32_t msg_type, int32_t ext1,
+                            int32_t ext2, void *user);
 
-    static void __data_cb(int32_t msg_type,
+    static void sDataCb(int32_t msg_type,
                           const camera_memory_t *data, unsigned int index,
                           camera_frame_metadata_t *metadata,
-                          void *user)
-    {
-        ALOGV("%s", __FUNCTION__);
-        CameraHardwareInterface *__this =
-                static_cast<CameraHardwareInterface *>(user);
-        sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
-        if (index >= mem->mNumBufs) {
-            ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
-                 index, mem->mNumBufs);
-            return;
-        }
-        __this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser);
-    }
+                          void *user);
 
-    static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
+    static void sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type,
                              const camera_memory_t *data, unsigned index,
-                             void *user)
-    {
-        ALOGV("%s", __FUNCTION__);
-        CameraHardwareInterface *__this =
-                static_cast<CameraHardwareInterface *>(user);
-        // Start refcounting the heap object from here on.  When the clients
-        // drop all references, it will be destroyed (as well as the enclosed
-        // MemoryHeapBase.
-        sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
-        if (index >= mem->mNumBufs) {
-            ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
-                 index, mem->mNumBufs);
-            return;
-        }
-        __this->mDataCbTimestamp(timestamp, msg_type, mem->mBuffers[index], __this->mCbUser);
-    }
+                             void *user);
+
+    // TODO: b/35625849
+    // Meta data buffer layout for passing a native_handle to codec
+    // matching frameworks/native/include/media/hardware/MetadataBufferType.h and
+    //          frameworks/native/include/media/hardware/HardwareAPI.h
+    struct VideoNativeHandleMetadata {
+        static const uint32_t kMetadataBufferTypeNativeHandleSource = 3;
+        uint32_t eType; // must be kMetadataBufferTypeNativeHandleSource
+        native_handle_t* pHandle;
+    };
 
     // This is a utility class that combines a MemoryHeapBase and a MemoryBase
     // in one.  Since we tend to use them in a one-to-one relationship, this is
     // handy.
-
     class CameraHeapMemory : public RefBase {
     public:
         CameraHeapMemory(int fd, size_t buf_size, uint_t num_buffers = 1) :
@@ -572,7 +336,7 @@
                                              i * mBufSize,
                                              mBufSize);
 
-            handle.release = __put_memory;
+            handle.release = sPutMemory;
         }
 
         virtual ~CameraHeapMemory()
@@ -588,199 +352,94 @@
         camera_memory_t handle;
     };
 
-    static camera_memory_t* __get_memory(int fd, size_t buf_size, uint_t num_bufs,
-                                         void *user __attribute__((unused)))
-    {
-        CameraHeapMemory *mem;
-        if (fd < 0)
-            mem = new CameraHeapMemory(buf_size, num_bufs);
-        else
-            mem = new CameraHeapMemory(fd, buf_size, num_bufs);
-        mem->incStrong(mem);
-        return &mem->handle;
-    }
+    static camera_memory_t* sGetMemory(int fd, size_t buf_size, uint_t num_bufs,
+                                         void *user __attribute__((unused)));
 
-    static void __put_memory(camera_memory_t *data)
-    {
-        if (!data)
-            return;
+    static void sPutMemory(camera_memory_t *data);
 
-        CameraHeapMemory *mem = static_cast<CameraHeapMemory *>(data->handle);
-        mem->decStrong(mem);
-    }
+    static ANativeWindow *sToAnw(void *user);
 
-    static ANativeWindow *__to_anw(void *user)
-    {
-        CameraHardwareInterface *__this =
-                reinterpret_cast<CameraHardwareInterface *>(user);
-        return __this->mPreviewWindow.get();
-    }
-#define anw(n) __to_anw(((struct camera_preview_window *)(n))->user)
-#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
-        ((struct camera_preview_window *)(n))->user)
+    static int sDequeueBuffer(struct preview_stream_ops* w,
+                                buffer_handle_t** buffer, int *stride);
 
-    static int __dequeue_buffer(struct preview_stream_ops* w,
-                                buffer_handle_t** buffer, int *stride)
-    {
-        int rc;
-        ANativeWindow *a = anw(w);
-        ANativeWindowBuffer* anb;
-        rc = native_window_dequeue_buffer_and_wait(a, &anb);
-        if (!rc) {
-            *buffer = &anb->handle;
-            *stride = anb->stride;
-        }
-        return rc;
-    }
+    static int sLockBuffer(struct preview_stream_ops* w,
+                      buffer_handle_t* /*buffer*/);
 
-#ifndef container_of
-#define container_of(ptr, type, member) ({                      \
-        const __typeof__(((type *) 0)->member) *__mptr = (ptr);     \
-        (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
-#endif
+    static int sEnqueueBuffer(struct preview_stream_ops* w,
+                      buffer_handle_t* buffer);
 
-    static int __lock_buffer(struct preview_stream_ops* w,
-                      buffer_handle_t* /*buffer*/)
-    {
-        ANativeWindow *a = anw(w);
-        (void)a;
-        return 0;
-    }
+    static int sCancelBuffer(struct preview_stream_ops* w,
+                      buffer_handle_t* buffer);
 
-    static int __enqueue_buffer(struct preview_stream_ops* w,
-                      buffer_handle_t* buffer)
-    {
-        ANativeWindow *a = anw(w);
-        return a->queueBuffer(a,
-                  container_of(buffer, ANativeWindowBuffer, handle), -1);
-    }
+    static int sSetBufferCount(struct preview_stream_ops* w, int count);
 
-    static int __cancel_buffer(struct preview_stream_ops* w,
-                      buffer_handle_t* buffer)
-    {
-        ANativeWindow *a = anw(w);
-        return a->cancelBuffer(a,
-                  container_of(buffer, ANativeWindowBuffer, handle), -1);
-    }
+    static int sSetBuffersGeometry(struct preview_stream_ops* w,
+                      int width, int height, int format);
 
-    static int __set_buffer_count(struct preview_stream_ops* w, int count)
-    {
-        ANativeWindow *a = anw(w);
+    static int sSetCrop(struct preview_stream_ops *w,
+                      int left, int top, int right, int bottom);
 
-        if (a != nullptr) {
-            // Workaround for b/27039775
-            // Previously, setting the buffer count would reset the buffer
-            // queue's flag that allows for all buffers to be dequeued on the
-            // producer side, instead of just the producer's declared max count,
-            // if no filled buffers have yet been queued by the producer.  This
-            // reset no longer happens, but some HALs depend on this behavior,
-            // so it needs to be maintained for HAL backwards compatibility.
-            // Simulate the prior behavior by disconnecting/reconnecting to the
-            // window and setting the values again.  This has the drawback of
-            // actually causing memory reallocation, which may not have happened
-            // in the past.
-            CameraHardwareInterface *hw = hwi(w);
-            native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
-            native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
-            if (hw->mPreviewScalingMode != NOT_SET) {
-                native_window_set_scaling_mode(a, hw->mPreviewScalingMode);
-            }
-            if (hw->mPreviewTransform != NOT_SET) {
-                native_window_set_buffers_transform(a, hw->mPreviewTransform);
-            }
-            if (hw->mPreviewWidth != NOT_SET) {
-                native_window_set_buffers_dimensions(a,
-                        hw->mPreviewWidth, hw->mPreviewHeight);
-                native_window_set_buffers_format(a, hw->mPreviewFormat);
-            }
-            if (hw->mPreviewUsage != 0) {
-                native_window_set_usage(a, hw->mPreviewUsage);
-            }
-            if (hw->mPreviewSwapInterval != NOT_SET) {
-                a->setSwapInterval(a, hw->mPreviewSwapInterval);
-            }
-            if (hw->mPreviewCrop.left != NOT_SET) {
-                native_window_set_crop(a, &(hw->mPreviewCrop));
-            }
-        }
+    static int sSetTimestamp(struct preview_stream_ops *w,
+                               int64_t timestamp);
 
-        return native_window_set_buffer_count(a, count);
-    }
+    static int sSetUsage(struct preview_stream_ops* w, int usage);
 
-    static int __set_buffers_geometry(struct preview_stream_ops* w,
-                      int width, int height, int format)
-    {
-        int rc;
-        ANativeWindow *a = anw(w);
-        CameraHardwareInterface *hw = hwi(w);
-        hw->mPreviewWidth = width;
-        hw->mPreviewHeight = height;
-        hw->mPreviewFormat = format;
-        rc = native_window_set_buffers_dimensions(a, width, height);
-        if (!rc) {
-            rc = native_window_set_buffers_format(a, format);
-        }
-        return rc;
-    }
+    static int sSetSwapInterval(struct preview_stream_ops *w, int interval);
 
-    static int __set_crop(struct preview_stream_ops *w,
-                      int left, int top, int right, int bottom)
-    {
-        ANativeWindow *a = anw(w);
-        CameraHardwareInterface *hw = hwi(w);
-        hw->mPreviewCrop.left = left;
-        hw->mPreviewCrop.top = top;
-        hw->mPreviewCrop.right = right;
-        hw->mPreviewCrop.bottom = bottom;
-        return native_window_set_crop(a, &(hw->mPreviewCrop));
-    }
-
-    static int __set_timestamp(struct preview_stream_ops *w,
-                               int64_t timestamp) {
-        ANativeWindow *a = anw(w);
-        return native_window_set_buffers_timestamp(a, timestamp);
-    }
-
-    static int __set_usage(struct preview_stream_ops* w, int usage)
-    {
-        ANativeWindow *a = anw(w);
-        CameraHardwareInterface *hw = hwi(w);
-        hw->mPreviewUsage = usage;
-        return native_window_set_usage(a, usage);
-    }
-
-    static int __set_swap_interval(struct preview_stream_ops *w, int interval)
-    {
-        ANativeWindow *a = anw(w);
-        CameraHardwareInterface *hw = hwi(w);
-        hw->mPreviewSwapInterval = interval;
-        return a->setSwapInterval(a, interval);
-    }
-
-    static int __get_min_undequeued_buffer_count(
+    static int sGetMinUndequeuedBufferCount(
                       const struct preview_stream_ops *w,
-                      int *count)
-    {
-        ANativeWindow *a = anw(w);
-        return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
-    }
+                      int *count);
 
-    void initHalPreviewWindow()
-    {
-        mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
-        mHalPreviewWindow.nw.lock_buffer = __lock_buffer;
-        mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
-        mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
-        mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
-        mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
-        mHalPreviewWindow.nw.set_crop = __set_crop;
-        mHalPreviewWindow.nw.set_timestamp = __set_timestamp;
-        mHalPreviewWindow.nw.set_usage = __set_usage;
-        mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval;
+    void initHalPreviewWindow();
 
-        mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
-                __get_min_undequeued_buffer_count;
-    }
+    std::pair<bool, uint64_t> getBufferId(ANativeWindowBuffer* anb);
+    void cleanupCirculatingBuffers();
+
+    /**
+     * Implementation of android::hardware::camera::device::V1_0::ICameraDeviceCallback
+     */
+    hardware::Return<void> notifyCallback(
+            hardware::camera::device::V1_0::NotifyCallbackMsg msgType,
+            int32_t ext1, int32_t ext2) override;
+    hardware::Return<uint32_t> registerMemory(
+            const hardware::hidl_handle& descriptor,
+            uint32_t bufferSize, uint32_t bufferCount) override;
+    hardware::Return<void> unregisterMemory(uint32_t memId) override;
+    hardware::Return<void> dataCallback(
+            hardware::camera::device::V1_0::DataCallbackMsg msgType,
+            uint32_t data, uint32_t bufferIndex,
+            const hardware::camera::device::V1_0::CameraFrameMetadata& metadata) override;
+    hardware::Return<void> dataCallbackTimestamp(
+            hardware::camera::device::V1_0::DataCallbackMsg msgType,
+            uint32_t data, uint32_t bufferIndex, int64_t timestamp) override;
+    hardware::Return<void> handleCallbackTimestamp(
+            hardware::camera::device::V1_0::DataCallbackMsg msgType,
+            const hardware::hidl_handle& frameData, uint32_t data,
+            uint32_t bufferIndex, int64_t timestamp) override;
+
+    /**
+     * Implementation of android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback
+     */
+    hardware::Return<void> dequeueBuffer(dequeueBuffer_cb _hidl_cb) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            enqueueBuffer(uint64_t bufferId) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            cancelBuffer(uint64_t bufferId) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            setBufferCount(uint32_t count) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            setBuffersGeometry(uint32_t w, uint32_t h,
+                    hardware::graphics::common::V1_0::PixelFormat format) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            setUsage(hardware::graphics::allocator::V2_0::ProducerUsage usage) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            setSwapInterval(int32_t interval) override;
+    hardware::Return<void> getMinUndequeuedBufferCount(
+        getMinUndequeuedBufferCount_cb _hidl_cb) override;
+    hardware::Return<hardware::camera::common::V1_0::Status>
+            setTimestamp(int64_t timestamp) override;
 
     sp<ANativeWindow>        mPreviewWindow;
 
@@ -806,6 +465,48 @@
     int mPreviewUsage;
     int mPreviewSwapInterval;
     android_native_rect_t mPreviewCrop;
+
+    struct BufferHasher {
+        size_t operator()(const buffer_handle_t& buf) const {
+            if (buf == nullptr)
+                return 0;
+
+            size_t result = 1;
+            result = 31 * result + buf->numFds;
+            result = 31 * result + buf->numInts;
+            int length = buf->numFds + buf->numInts;
+            for (int i = 0; i < length; i++) {
+                result = 31 * result + buf->data[i];
+            }
+            return result;
+        }
+    };
+
+    struct BufferComparator {
+        bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
+            if (buf1->numFds == buf2->numFds && buf1->numInts == buf2->numInts) {
+                int length = buf1->numFds + buf1->numInts;
+                for (int i = 0; i < length; i++) {
+                    if (buf1->data[i] != buf2->data[i]) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+    };
+
+    std::mutex mBufferIdMapLock; // protecting mBufferIdMap and mNextBufferId
+    typedef std::unordered_map<const buffer_handle_t, uint64_t,
+            BufferHasher, BufferComparator> BufferIdMap;
+    // stream ID -> per stream buffer ID map
+    BufferIdMap mBufferIdMap;
+    std::unordered_map<uint64_t, ANativeWindowBuffer*> mReversedBufMap;
+    uint64_t mNextBufferId = 1;
+    static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+    std::unordered_map<int, camera_memory_t*> mHidlMemPoolMap;
 };
 
 };  // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 068a2b3..f20556d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3956,7 +3956,8 @@
                 }
             }
 
-            res = outputStream->getBuffer(&outputBuffers->editItemAt(i));
+            res = outputStream->getBuffer(&outputBuffers->editItemAt(i),
+                    captureRequest->mOutputSurfaces[i]);
             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
@@ -3968,13 +3969,6 @@
             }
             halRequest->num_output_buffers++;
 
-            res = outputStream->notifyRequestedSurfaces(halRequest->frame_number,
-                    captureRequest->mOutputSurfaces[i]);
-            if (res != OK) {
-                ALOGE("RequestThread: Cannot register output surfaces: %s (%d)",
-                      strerror(-res), res);
-                return INVALID_OPERATION;
-            }
         }
         totalNumBuffers += halRequest->num_output_buffers;
 
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 1a730d6..9c951b7 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -36,7 +36,8 @@
 
 }
 
-status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *) {
+status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *,
+        const std::vector<size_t>&) {
     ATRACE_CALL();
     ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
@@ -83,14 +84,6 @@
     return OK;
 }
 
-status_t Camera3DummyStream::notifyRequestedSurfaces(uint32_t frame_number,
-        const std::vector<size_t>& surface_ids) {
-    (void) frame_number;
-    (void) surface_ids;
-    // Do nothing
-    return OK;
-}
-
 status_t Camera3DummyStream::configureQueueLocked() {
     // Do nothing
     return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index b6ec99c..35a6a18 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -56,9 +56,6 @@
 
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
 
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids);
-
     /**
      * Return if this output stream is for video encoding.
      */
@@ -102,7 +99,8 @@
     /**
      * Internal Camera3Stream interface
      */
-    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+    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);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index f971116..51dc20a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -148,73 +148,17 @@
     disconnectLocked();
 }
 
-status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
+status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer,
+        const std::vector<size_t>&) {
     ATRACE_CALL();
-    status_t res;
-
-    if ((res = getBufferPreconditionCheckLocked()) != OK) {
-        return res;
-    }
 
     ANativeWindowBuffer* anb;
     int fenceFd = -1;
-    bool gotBufferFromManager = false;
 
-    if (mUseBufferManager) {
-        sp<GraphicBuffer> gb;
-        res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, &fenceFd);
-        if (res == OK) {
-            // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
-            // successful return.
-            anb = gb.get();
-            res = mConsumer->attachBuffer(anb);
-            if (res != OK) {
-                ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
-                        __FUNCTION__, mId, strerror(-res), res);
-                return res;
-            }
-            gotBufferFromManager = true;
-            ALOGV("Stream %d: Attached new buffer", getId());
-        } else if (res == ALREADY_EXISTS) {
-            // Have sufficient free buffers already attached, can just
-            // dequeue from buffer queue
-            ALOGV("Stream %d: Reusing attached buffer", getId());
-            gotBufferFromManager = false;
-        } else if (res != OK) {
-            ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
-            return res;
-        }
-    }
-    if (!gotBufferFromManager) {
-        /**
-         * Release the lock briefly to avoid deadlock for below scenario:
-         * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
-         * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
-         * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
-         * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
-         * StreamingProcessor lock.
-         * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
-         * and try to lock bufferQueue lock.
-         * Then there is circular locking dependency.
-         */
-        sp<ANativeWindow> currentConsumer = mConsumer;
-        mLock.unlock();
-
-        res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
-        mLock.lock();
-        if (res != OK) {
-            ALOGE("%s: Stream %d: Can't dequeue next output buffer: %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 res;
+    res = getBufferLockedCommon(&anb, &fenceFd);
+    if (res != OK) {
+        return res;
     }
 
     /**
@@ -227,6 +171,11 @@
     return OK;
 }
 
+status_t Camera3OutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence) {
+    return consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+}
+
 status_t Camera3OutputStream::returnBufferLocked(
         const camera3_stream_buffer &buffer,
         nsecs_t timestamp) {
@@ -269,6 +218,7 @@
     sp<ANativeWindow> currentConsumer = mConsumer;
     mLock.unlock();
 
+    ANativeWindowBuffer *anwBuffer = container_of(buffer.buffer, ANativeWindowBuffer, handle);
     /**
      * Return buffer back to ANativeWindow
      */
@@ -276,13 +226,14 @@
         // Cancel buffer
         ALOGW("A frame is dropped for stream %d", mId);
         res = currentConsumer->cancelBuffer(currentConsumer.get(),
-                container_of(buffer.buffer, ANativeWindowBuffer, handle),
+                anwBuffer,
                 anwReleaseFence);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
                   " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
 
+        notifyBufferReleased(anwBuffer);
         if (mUseBufferManager) {
             // Return this buffer back to buffer manager.
             mBufferReleasedListener->onBufferReleased();
@@ -308,9 +259,7 @@
             return res;
         }
 
-        res = currentConsumer->queueBuffer(currentConsumer.get(),
-                container_of(buffer.buffer, ANativeWindowBuffer, handle),
-                anwReleaseFence);
+        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error queueing buffer to native window: "
                   "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
@@ -527,6 +476,76 @@
     return OK;
 }
 
+status_t Camera3OutputStream::getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd) {
+    ATRACE_CALL();
+    status_t res;
+
+    if ((res = getBufferPreconditionCheckLocked()) != OK) {
+        return res;
+    }
+
+    bool gotBufferFromManager = false;
+
+    if (mUseBufferManager) {
+        sp<GraphicBuffer> gb;
+        res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, fenceFd);
+        if (res == OK) {
+            // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
+            // successful return.
+            *anb = gb.get();
+            res = mConsumer->attachBuffer(*anb);
+            if (res != OK) {
+                ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
+                        __FUNCTION__, mId, strerror(-res), res);
+                return res;
+            }
+            gotBufferFromManager = true;
+            ALOGV("Stream %d: Attached new buffer", getId());
+        } else if (res == ALREADY_EXISTS) {
+            // Have sufficient free buffers already attached, can just
+            // dequeue from buffer queue
+            ALOGV("Stream %d: Reusing attached buffer", getId());
+            gotBufferFromManager = false;
+        } else if (res != OK) {
+            ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
+                    __FUNCTION__, mId, strerror(-res), res);
+            return res;
+        }
+    }
+    if (!gotBufferFromManager) {
+        /**
+         * Release the lock briefly to avoid deadlock for below scenario:
+         * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
+         * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
+         * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
+         * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
+         * StreamingProcessor lock.
+         * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
+         * and try to lock bufferQueue lock.
+         * Then there is circular locking dependency.
+         */
+        sp<ANativeWindow> currentConsumer = mConsumer;
+        mLock.unlock();
+
+        res = currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd);
+        mLock.lock();
+        if (res != OK) {
+            ALOGE("%s: Stream %d: Can't dequeue next output buffer: %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;
+        }
+    }
+
+    return res;
+}
+
 status_t Camera3OutputStream::disconnectLocked() {
     status_t res;
 
@@ -702,8 +721,7 @@
     return OK;
 }
 
-status_t Camera3OutputStream::notifyRequestedSurfaces(uint32_t /*frame_number*/,
-        const std::vector<size_t>& /*surface_ids*/) {
+status_t Camera3OutputStream::notifyBufferReleased(ANativeWindowBuffer* /*anwBuffer*/) {
     return OK;
 }
 
@@ -717,6 +735,7 @@
 }
 
 status_t Camera3OutputStream::setConsumers(const std::vector<sp<Surface>>& consumers) {
+    Mutex::Autolock l(mLock);
     if (consumers.size() != 1) {
         ALOGE("%s: it's illegal to set %zu consumer surfaces!",
                   __FUNCTION__, consumers.size());
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 080c721..24e4e05 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -158,8 +158,11 @@
 
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
 
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids);
+    /**
+     * Notify that the buffer is being released to the buffer queue instead of
+     * being queued to the consumer.
+     */
+    virtual status_t notifyBufferReleased(ANativeWindowBuffer *anwBuffer);
 
     /**
      * Set the graphic buffer manager to get/return the stream buffers.
@@ -198,6 +201,9 @@
 
     static const nsecs_t       kDequeueBufferTimeout   = 1000000000; // 1 sec
 
+    status_t getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd);
+
+
   private:
 
     int               mTransform;
@@ -243,11 +249,16 @@
     /**
      * Internal Camera3Stream interface
      */
-    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+    virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids);
+
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp);
 
+    virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence);
+
     virtual status_t configureQueueLocked();
 
     virtual status_t getEndpointUsage(uint32_t *usage) const;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 11868e7..8107dd0 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -59,20 +59,6 @@
      *
      */
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd) = 0;
-
-    /**
-     * Notify which surfaces are requested for a particular frame number.
-     *
-     * Mulitple surfaces could share the same output stream, but a request may
-     * be only for a subset of surfaces. In this case, the
-     * Camera3OutputStreamInterface object needs to manage the output surfaces on
-     * a per request basis.
-     *
-     * If there is only one surface for this output stream, calling this
-     * function is a no-op.
-     */
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids) = 0;
 };
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 0d6a96c..2ae5660 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -44,7 +44,7 @@
     uint32_t usage;
     getEndpointUsage(&usage);
 
-    res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, mConsumer);
+    res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, &mConsumer);
     if (res != OK) {
         ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
                 __FUNCTION__, strerror(-res), res);
@@ -54,13 +54,13 @@
     return res;
 }
 
-status_t Camera3SharedOutputStream::notifyRequestedSurfaces(uint32_t /*frame_number*/,
-        const std::vector<size_t>& surface_ids) {
+status_t Camera3SharedOutputStream::notifyBufferReleased(ANativeWindowBuffer *anwBuffer) {
     Mutex::Autolock l(mLock);
     status_t res = OK;
+    const sp<GraphicBuffer> buffer(static_cast<GraphicBuffer*>(anwBuffer));
 
     if (mStreamSplitter != nullptr) {
-        res = mStreamSplitter->notifyRequestedSurfaces(surface_ids);
+        res = mStreamSplitter->notifyBufferReleased(buffer);
     }
 
     return res;
@@ -72,6 +72,7 @@
 }
 
 status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
+    Mutex::Autolock l(mLock);
     if (surfaces.size() == 0) {
         ALOGE("%s: it's illegal to set zero consumer surfaces!", __FUNCTION__);
         return INVALID_OPERATION;
@@ -88,7 +89,7 @@
 
         // Only call addOutput if the splitter has been connected.
         if (mStreamSplitter != nullptr) {
-            ret = mStreamSplitter->addOutput(surface, camera3_stream::max_buffers);
+            ret = mStreamSplitter->addOutput(surface);
             if (ret != OK) {
                 ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
                 return ret;
@@ -99,6 +100,64 @@
     return ret;
 }
 
+status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffer,
+        const std::vector<size_t>& surface_ids) {
+    ANativeWindowBuffer* anb;
+    int fenceFd = -1;
+
+    status_t res;
+    res = getBufferLockedCommon(&anb, &fenceFd);
+    if (res != OK) {
+        return res;
+    }
+
+    // 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;
+    }
+
+    /**
+     * FenceFD now owned by HAL except in case of error,
+     * in which case we reassign it to acquire_fence
+     */
+    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
+                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
+
+    return OK;
+}
+
+status_t Camera3SharedOutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence) {
+    status_t 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.
+    if (res == OK) {
+        res = mStreamSplitter->getOnFrameAvailableResult();
+        if (res != OK) {
+            ALOGE("%s: getOnFrameAvailable returns %d", __FUNCTION__, res);
+        }
+    } else {
+        ALOGE("%s: queueBufer failed %d", __FUNCTION__, res);
+    }
+
+    return res;
+}
+
 status_t Camera3SharedOutputStream::configureQueueLocked() {
     status_t res;
 
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index cc96076..7be0940 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -40,8 +40,7 @@
 
     virtual ~Camera3SharedOutputStream();
 
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids);
+    virtual status_t notifyBufferReleased(ANativeWindowBuffer *buffer);
 
     virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
 
@@ -62,6 +61,15 @@
      */
     status_t connectStreamSplitterLocked();
 
+    /**
+     * 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);
+
     virtual status_t configureQueueLocked();
 
     virtual status_t disconnectLocked();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index c3b7565..53a3168 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -443,7 +443,8 @@
     return OK;
 }
 
-status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) {
+status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer,
+        const std::vector<size_t>& surface_ids) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
     status_t res = OK;
@@ -470,7 +471,7 @@
         }
     }
 
-    res = getBufferLocked(buffer);
+    res = getBufferLocked(buffer, surface_ids);
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
         if (buffer->buffer) {
@@ -745,7 +746,8 @@
     return res;
 }
 
-status_t Camera3Stream::getBufferLocked(camera3_stream_buffer *) {
+status_t Camera3Stream::getBufferLocked(camera3_stream_buffer *,
+        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 471b393..56cb827 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -277,12 +277,18 @@
      * Fill in the camera3_stream_buffer with the next valid buffer for this
      * stream, to hand over to 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 acquire
+     * buffers for those surfaces.
+     *
      * This method may only be called once finishConfiguration has been called.
      * For bidirectional streams, this method applies to the output-side
      * buffers.
      *
      */
-    status_t         getBuffer(camera3_stream_buffer *buffer);
+    status_t         getBuffer(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
 
     /**
      * Return a buffer to the stream after use by the HAL.
@@ -412,7 +418,8 @@
     // cast to camera3_stream*, implementations must increment the
     // refcount of the stream manually in getBufferLocked, and decrement it in
     // returnBufferLocked.
-    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+    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);
     virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index ceea08a..f7b092f 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -200,12 +200,19 @@
      * Fill in the camera3_stream_buffer with the next valid buffer for this
      * stream, to hand over to 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 acquire
+     * 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 once finishConfiguration has been called.
      * For bidirectional streams, this method applies to the output-side
      * buffers.
      *
      */
-    virtual status_t getBuffer(camera3_stream_buffer *buffer) = 0;
+    virtual status_t getBuffer(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>()) = 0;
 
     /**
      * Return a buffer to the stream after use by the HAL.
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index c9f43aa..deb6735 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -37,10 +37,10 @@
 namespace android {
 
 status_t Camera3StreamSplitter::connect(const std::vector<sp<Surface> >& surfaces,
-                                           uint32_t consumerUsage, size_t hal_max_buffers,
-                                           sp<Surface>& consumer) {
-    if (consumer != nullptr) {
-        ALOGE("%s: output Surface is not NULL", __FUNCTION__);
+        uint32_t consumerUsage, size_t halMaxBuffers, sp<Surface>* consumer) {
+    ATRACE_CALL();
+    if (consumer == nullptr) {
+        SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
         return BAD_VALUE;
     }
 
@@ -48,129 +48,147 @@
     status_t res = OK;
 
     if (mOutputs.size() > 0 || mConsumer != nullptr) {
-        ALOGE("%s: StreamSplitter already connected", __FUNCTION__);
+        SP_LOGE("%s: already connected", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    if (mBuffers.size() > 0) {
+        SP_LOGE("%s: still has %zu pending buffers", __FUNCTION__, mBuffers.size());
         return BAD_VALUE;
     }
 
+    mMaxHalBuffers = halMaxBuffers;
+    mConsumerName = getUniqueConsumerName();
     // Add output surfaces. This has to be before creating internal buffer queue
     // in order to get max consumer side buffers.
     for (size_t i = 0; i < surfaces.size(); i++) {
         if (surfaces[i] == nullptr) {
-            ALOGE("%s: Fatal: surface is NULL", __FUNCTION__);
+            SP_LOGE("%s: Fatal: surface is NULL", __FUNCTION__);
             return BAD_VALUE;
         }
-        res = addOutputLocked(surfaces[i], hal_max_buffers, OutputType::NonDeferred);
+        res = addOutputLocked(surfaces[i]);
         if (res != OK) {
-            ALOGE("%s: Failed to add output surface: %s(%d)",
+            SP_LOGE("%s: Failed to add output surface: %s(%d)",
                     __FUNCTION__, strerror(-res), res);
             return res;
         }
     }
 
-    // Create buffer queue for input
+    // Create BufferQueue for input
     BufferQueue::createBufferQueue(&mProducer, &mConsumer);
 
+    // Allocate 1 extra buffer to handle the case where all buffers are detached
+    // from input, and attached to the outputs. In this case, the input queue's
+    // dequeueBuffer can still allocate 1 extra buffer before being blocked by
+    // the output's attachBuffer().
     mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
-                                                 mMaxConsumerBuffers);
+                                                 mMaxConsumerBuffers+1);
     if (mBufferItemConsumer == nullptr) {
         return NO_MEMORY;
     }
-    mConsumer->setConsumerName(getUniqueConsumerName());
+    mConsumer->setConsumerName(mConsumerName);
 
-    mSurface = new Surface(mProducer);
-    if (mSurface == nullptr) {
+    *consumer = new Surface(mProducer);
+    if (*consumer == nullptr) {
         return NO_MEMORY;
     }
-    consumer = mSurface;
 
     res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
 
+    SP_LOGV("%s: connected", __FUNCTION__);
     return res;
 }
 
+status_t Camera3StreamSplitter::getOnFrameAvailableResult() {
+    ATRACE_CALL();
+    return mOnFrameAvailableRes.load();
+}
+
 void Camera3StreamSplitter::disconnect() {
+    ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
 
+    for (auto& notifier : mNotifiers) {
+        sp<IGraphicBufferProducer> producer = notifier.first;
+        sp<OutputListener> listener = notifier.second;
+        IInterface::asBinder(producer)->unlinkToDeath(listener);
+    }
+    mNotifiers.clear();
+
     for (auto& output : mOutputs) {
         output->disconnect(NATIVE_WINDOW_API_CAMERA);
     }
     mOutputs.clear();
+    mOutputSlots.clear();
 
-    if (mConsumer != nullptr) {
-        mConsumer->consumerDisconnect();
-        mConsumer.clear();
-    }
+    mConsumer->consumerDisconnect();
 
     if (mBuffers.size() > 0) {
-        ALOGI("%zu buffers still being tracked", mBuffers.size());
+        SP_LOGW("%zu buffers still being tracked", mBuffers.size());
+        mBuffers.clear();
     }
+
+    mMaxHalBuffers = 0;
+    mMaxConsumerBuffers = 0;
+    SP_LOGV("%s: Disconnected", __FUNCTION__);
 }
 
+
 Camera3StreamSplitter::~Camera3StreamSplitter() {
     disconnect();
 }
 
-status_t Camera3StreamSplitter::addOutput(
-        const sp<Surface>& outputQueue, size_t hal_max_buffers) {
+status_t Camera3StreamSplitter::addOutput(const sp<Surface>& outputQueue) {
+    ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
-    return addOutputLocked(outputQueue, hal_max_buffers, OutputType::Deferred);
+    status_t res = addOutputLocked(outputQueue);
+
+    if (res != OK) {
+        SP_LOGE("%s: addOutputLocked failed %d", __FUNCTION__, res);
+        return res;
+    }
+
+    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+
+    return res;
 }
 
-status_t Camera3StreamSplitter::addOutputLocked(
-        const sp<Surface>& outputQueue, size_t hal_max_buffers,
-        OutputType outputType) {
+status_t Camera3StreamSplitter::addOutputLocked(const sp<Surface>& outputQueue) {
+    ATRACE_CALL();
     if (outputQueue == nullptr) {
-        ALOGE("addOutput: outputQueue must not be NULL");
-        return BAD_VALUE;
-    }
-    if (hal_max_buffers < 1) {
-        ALOGE("%s: Camera HAL requested max_buffer count: %zu, requires at least 1",
-                __FUNCTION__, hal_max_buffers);
+        SP_LOGE("addOutput: outputQueue must not be NULL");
         return BAD_VALUE;
     }
 
     sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
     // Connect to the buffer producer
-    IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
     sp<OutputListener> listener(new OutputListener(this, gbp));
     IInterface::asBinder(gbp)->linkToDeath(listener);
-    status_t status = gbp->connect(listener, NATIVE_WINDOW_API_CAMERA,
-            /* producerControlledByApp */ true, &queueBufferOutput);
-    if (status != NO_ERROR) {
-        ALOGE("addOutput: failed to connect (%d)", status);
-       return status;
+    status_t res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
+    if (res != NO_ERROR) {
+        SP_LOGE("addOutput: failed to connect (%d)", res);
+        return res;
     }
 
     // Query consumer side buffer count, and update overall buffer count
     int maxConsumerBuffers = 0;
-    status = static_cast<ANativeWindow*>(outputQueue.get())->query(
+    res = static_cast<ANativeWindow*>(outputQueue.get())->query(
             outputQueue.get(),
             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
-    if (status != OK) {
-        ALOGE("%s: Unable to query consumer undequeued buffer count"
+    if (res != OK) {
+        SP_LOGE("%s: Unable to query consumer undequeued buffer count"
               " for surface", __FUNCTION__);
-        return status;
+        return res;
     }
 
-    if (maxConsumerBuffers > mMaxConsumerBuffers) {
-        if (outputType == OutputType::Deferred) {
-            ALOGE("%s: Fatal: Deferred surface has higher consumer buffer count"
-                  " %d than what's already configured %d", __FUNCTION__,
-                  maxConsumerBuffers, mMaxConsumerBuffers);
-            return BAD_VALUE;
-        }
-        mMaxConsumerBuffers = maxConsumerBuffers;
-    }
-
-    ALOGV("%s: Consumer wants %d buffers, HAL wants %zu", __FUNCTION__,
-            maxConsumerBuffers, hal_max_buffers);
-    size_t totalBufferCount = maxConsumerBuffers + hal_max_buffers;
-    status = native_window_set_buffer_count(outputQueue.get(),
+    SP_LOGV("%s: Consumer wants %d buffers, Producer wants %zu", __FUNCTION__,
+            maxConsumerBuffers, mMaxHalBuffers);
+    size_t totalBufferCount = maxConsumerBuffers + mMaxHalBuffers;
+    res = native_window_set_buffer_count(outputQueue.get(),
             totalBufferCount);
-    if (status != OK) {
-        ALOGE("%s: Unable to set buffer count for surface %p",
+    if (res != OK) {
+        SP_LOGE("%s: Unable to set buffer count for surface %p",
                 __FUNCTION__, outputQueue.get());
-        return status;
+        return res;
     }
 
     // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
@@ -183,157 +201,239 @@
         outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
     }
 
-    status = gbp->allowAllocation(false);
-    if (status != OK) {
-        ALOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
-        return status;
+    res = gbp->allowAllocation(false);
+    if (res != OK) {
+        SP_LOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
+        return res;
     }
 
     // Add new entry into mOutputs
     mOutputs.push_back(gbp);
+    mNotifiers[gbp] = listener;
+    mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
+
+    mMaxConsumerBuffers += maxConsumerBuffers;
     return NO_ERROR;
 }
 
+status_t Camera3StreamSplitter::outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+        const BufferItem& bufferItem) {
+    ATRACE_CALL();
+    status_t res;
+    IGraphicBufferProducer::QueueBufferInput queueInput(
+            bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
+            bufferItem.mDataSpace, bufferItem.mCrop,
+            static_cast<int32_t>(bufferItem.mScalingMode),
+            bufferItem.mTransform, bufferItem.mFence);
+
+    IGraphicBufferProducer::QueueBufferOutput queueOutput;
+
+    uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
+    const BufferTracker& tracker = *(mBuffers[bufferId]);
+    int slot = getSlotForOutputLocked(output, tracker.getBuffer());
+
+    // In case the output BufferQueue has its own lock, if we hold splitter lock while calling
+    // queueBuffer (which will try to acquire the output lock), the output could be holding its
+    // own lock calling releaseBuffer (which  will try to acquire the splitter lock), running into
+    // circular lock situation.
+    mMutex.unlock();
+    res = output->queueBuffer(slot, queueInput, &queueOutput);
+    mMutex.lock();
+
+    SP_LOGV("%s: Queuing buffer to buffer queue %p slot %d returns %d",
+            __FUNCTION__, output.get(), slot, res);
+    if (res != OK) {
+        if (res != NO_INIT && res != DEAD_OBJECT) {
+            SP_LOGE("Queuing buffer to output failed (%d)", res);
+        }
+        // If we just discovered that this output has been abandoned, note
+        // that, increment the release count so that we still release this
+        // buffer eventually, and move on to the next output
+        onAbandonedLocked();
+        decrementBufRefCountLocked(bufferItem.mGraphicBuffer->getId(), output);
+        return res;
+    }
+
+    // If the queued buffer replaces a pending buffer in the async
+    // queue, no onBufferReleased is called by the buffer queue.
+    // Proactively trigger the callback to avoid buffer loss.
+    if (queueOutput.bufferReplaced) {
+        onBufferReleasedByOutputLocked(output);
+    }
+
+    return res;
+}
+
 String8 Camera3StreamSplitter::getUniqueConsumerName() {
     static volatile int32_t counter = 0;
     return String8::format("Camera3StreamSplitter-%d", android_atomic_inc(&counter));
 }
 
-status_t Camera3StreamSplitter::notifyRequestedSurfaces(
-        const std::vector<size_t>& surfaces) {
+status_t Camera3StreamSplitter::notifyBufferReleased(const sp<GraphicBuffer>& buffer) {
     ATRACE_CALL();
+    status_t res = OK;
+
     Mutex::Autolock lock(mMutex);
 
-    mRequestedSurfaces.push_back(surfaces);
-    return OK;
-}
+    uint64_t bufferId = buffer->getId();
+    std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[bufferId]);
+    mBuffers.erase(bufferId);
 
-
-void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /* item */) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mMutex);
-
-    // The current policy is that if any one consumer is consuming buffers too
-    // slowly, the splitter will stall the rest of the outputs by not acquiring
-    // any more buffers from the input. This will cause back pressure on the
-    // input queue, slowing down its producer.
-
-    // If there are too many outstanding buffers, we block until a buffer is
-    // released back to the input in onBufferReleased
-    while (mOutstandingBuffers >= mMaxConsumerBuffers) {
-        mReleaseCondition.wait(mMutex);
-
-        // If the splitter is abandoned while we are waiting, the release
-        // condition variable will be broadcast, and we should just return
-        // without attempting to do anything more (since the input queue will
-        // also be abandoned).
-        if (mIsAbandoned) {
-            return;
+    for (const auto surface : tracker_ptr->requestedSurfaces()) {
+        sp<IGraphicBufferProducer>& gbp = mOutputs[surface];
+        OutputSlots& outputSlots = *(mOutputSlots[gbp]);
+        int slot = getSlotForOutputLocked(gbp, buffer);
+        if (slot != BufferItem::INVALID_BUFFER_SLOT) {
+             gbp->detachBuffer(slot);
+             outputSlots[slot].clear();
         }
     }
-    // If the splitter is abandoned without reaching mMaxConsumerBuffers, just
-    // return without attempting to do anything more.
-    if (mIsAbandoned) {
-        return;
+
+    return res;
+}
+
+status_t Camera3StreamSplitter::attachBufferToOutputs(ANativeWindowBuffer* anb,
+        const std::vector<size_t>& surface_ids) {
+    ATRACE_CALL();
+    status_t res = OK;
+
+    Mutex::Autolock lock(mMutex);
+
+    sp<GraphicBuffer> gb(static_cast<GraphicBuffer*>(anb));
+    uint64_t bufferId = gb->getId();
+
+    // Initialize buffer tracker for this input buffer
+    auto tracker = std::make_unique<BufferTracker>(gb, surface_ids);
+
+    for (auto& surface_id : surface_ids) {
+        sp<IGraphicBufferProducer>& gbp = mOutputs[surface_id];
+        int slot = BufferItem::INVALID_BUFFER_SLOT;
+        //Temporarly Unlock the mutex when trying to attachBuffer to the output
+        //queue, because attachBuffer could block in case of a slow consumer. If
+        //we block while holding the lock, onFrameAvailable and onBufferReleased
+        //will block as well because they need to acquire the same lock.
+        mMutex.unlock();
+        res = gbp->attachBuffer(&slot, gb);
+        mMutex.lock();
+        if (res != OK) {
+            SP_LOGE("%s: Cannot acquireBuffer from GraphicBufferProducer %p: %s (%d)",
+                    __FUNCTION__, gbp.get(), strerror(-res), res);
+            return res;
+        }
+        auto& outputSlots = *mOutputSlots[gbp];
+        if (outputSlots[slot] != nullptr) {
+            // If the buffer is attached to a slot which already contains a buffer,
+            // the previous buffer will be removed from the output queue. Decrement
+            // the reference count accordingly.
+            decrementBufRefCountLocked(outputSlots[slot]->getId(), gbp);
+        }
+        SP_LOGV("%s: Attached buffer %p to slot %d on output %p.",__FUNCTION__, gb.get(),
+                slot, gbp.get());
+        outputSlots[slot] = gb;
     }
 
-    ++mOutstandingBuffers;
+    mBuffers[bufferId] = std::move(tracker);
+
+    return res;
+}
+
+void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /*item*/) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
 
     // Acquire and detach the buffer from the input
     BufferItem bufferItem;
-    status_t status = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "acquiring buffer from input failed (%d)", status);
+    status_t res = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: Acquiring buffer from input failed (%d)", __FUNCTION__, res);
+        mOnFrameAvailableRes.store(res);
+        return;
+    }
+    if (mBuffers.find(bufferItem.mGraphicBuffer->getId()) == mBuffers.end()) {
+        SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
+                __FUNCTION__);
+        mOnFrameAvailableRes.store(INVALID_OPERATION);
+        return;
+    }
 
-    ALOGV("acquired buffer %#" PRIx64 " from input",
-            bufferItem.mGraphicBuffer->getId());
+    SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
+            bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
 
-    status = mConsumer->detachBuffer(bufferItem.mSlot);
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "detaching buffer from input failed (%d)", status);
-
-    IGraphicBufferProducer::QueueBufferInput queueInput(
-            bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
-            bufferItem.mDataSpace, bufferItem.mCrop,
-            static_cast<int32_t>(bufferItem.mScalingMode),
-            bufferItem.mTransform, bufferItem.mFence);
+    res = mConsumer->detachBuffer(bufferItem.mSlot);
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: detaching buffer from input failed (%d)", __FUNCTION__, res);
+        mOnFrameAvailableRes.store(res);
+        return;
+    }
 
     // Attach and queue the buffer to each of the outputs
-    std::vector<std::vector<size_t> >::iterator surfaces = mRequestedSurfaces.begin();
-    if (surfaces != mRequestedSurfaces.end()) {
+    BufferTracker& tracker = *(mBuffers[bufferItem.mGraphicBuffer->getId()]);
 
-        LOG_ALWAYS_FATAL_IF(surfaces->size() == 0,
-                "requested surface ids shouldn't be empty");
+    SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
+           __FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
+    for (const auto id : tracker.requestedSurfaces()) {
 
-        // Initialize our reference count for this buffer
-        mBuffers[bufferItem.mGraphicBuffer->getId()] =
-                std::unique_ptr<BufferTracker>(
-                new BufferTracker(bufferItem.mGraphicBuffer, surfaces->size()));
+        LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
+                "requested surface id exceeding max registered ids");
 
-        for (auto id : *surfaces) {
-
-            LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
-                    "requested surface id exceeding max registered ids");
-
-            int slot = BufferItem::INVALID_BUFFER_SLOT;
-            status = mOutputs[id]->attachBuffer(&slot, bufferItem.mGraphicBuffer);
-            if (status == NO_INIT) {
-                // If we just discovered that this output has been abandoned, note
-                // that, decrement the reference count so that we still release this
-                // buffer eventually, and move on to the next output
-                onAbandonedLocked();
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else if (status == WOULD_BLOCK) {
-                // If the output is async, attachBuffer may return WOULD_BLOCK
-                // indicating number of dequeued buffers has reached limit. In
-                // this case, simply decrement the reference count, and move on
-                // to the next output.
-                // TODO: Do we need to report BUFFER_ERROR for this result?
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else if (status == TIMED_OUT) {
-                // If attachBuffer times out due to the value set by
-                // setDequeueTimeout, simply decrement the reference count, and
-                // move on to the next output.
-                // TODO: Do we need to report BUFFER_ERROR for this result?
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else {
-                LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                        "attaching buffer to output failed (%d)", status);
-            }
-
-            IGraphicBufferProducer::QueueBufferOutput queueOutput;
-            status = mOutputs[id]->queueBuffer(slot, queueInput, &queueOutput);
-            if (status == NO_INIT) {
-                // If we just discovered that this output has been abandoned, note
-                // that, increment the release count so that we still release this
-                // buffer eventually, and move on to the next output
-                onAbandonedLocked();
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else {
-                LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                        "queueing buffer to output failed (%d)", status);
-            }
-
-            // If the queued buffer replaces a pending buffer in the async
-            // queue, no onBufferReleased is called by the buffer queue.
-            // Proactively trigger the callback to avoid buffer loss.
-            if (queueOutput.bufferReplaced) {
-                onBufferReleasedByOutputLocked(mOutputs[id]);
-            }
-
-            ALOGV("queued buffer %#" PRIx64 " to output %p",
-                    bufferItem.mGraphicBuffer->getId(), mOutputs[id].get());
+        res = outputBufferLocked(mOutputs[id], bufferItem);
+        if (res != OK) {
+            SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
+            mOnFrameAvailableRes.store(res);
+            // If we fail to send buffer to certain output, keep sending to
+            // other outputs.
+            continue;
         }
+    }
 
-        mRequestedSurfaces.erase(surfaces);
+    mOnFrameAvailableRes.store(res);
+}
+
+void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id,
+        const sp<IGraphicBufferProducer>& from) {
+    ATRACE_CALL();
+    size_t referenceCount = mBuffers[id]->decrementReferenceCountLocked();
+
+    removeSlotForOutputLocked(from, mBuffers[id]->getBuffer());
+    if (referenceCount > 0) {
+        return;
+    }
+
+    // We no longer need to track the buffer now that it is being returned to the
+    // input. Note that this should happen before we unlock the mutex and call
+    // releaseBuffer, to avoid the case where the same bufferId is acquired in
+    // attachBufferToOutputs resulting in a new BufferTracker with same bufferId
+    // overwrites the current one.
+    std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[id]);
+    mBuffers.erase(id);
+
+    // Attach and release the buffer back to the input
+    int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
+    status_t res = mConsumer->attachBuffer(&consumerSlot, tracker_ptr->getBuffer());
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: attaching buffer to input failed (%d)", __FUNCTION__, res);
+        return;
+    }
+
+    // Temporarily unlock mutex to avoid circular lock:
+    // 1. This function holds splitter lock, calls releaseBuffer which triggers
+    // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the
+    // OutputStream lock
+    // 2. Camera3SharedOutputStream::getBufferLocked calls
+    // attachBufferToOutputs, which holds the stream lock, and waits for the
+    // splitter lock.
+    sp<IGraphicBufferConsumer> consumer(mConsumer);
+    mMutex.unlock();
+    if (consumer != nullptr) {
+        res = consumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
+    } else {
+        SP_LOGE("%s: consumer has become null!", __FUNCTION__);
+    }
+    mMutex.lock();
+    // If the producer of this queue is disconnected, -22 error will occur
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
     }
 }
 
@@ -347,73 +447,79 @@
 
 void Camera3StreamSplitter::onBufferReleasedByOutputLocked(
         const sp<IGraphicBufferProducer>& from) {
-
+    ATRACE_CALL();
     sp<GraphicBuffer> buffer;
     sp<Fence> fence;
-    status_t status = from->detachNextBuffer(&buffer, &fence);
-    if (status == NO_INIT) {
+    status_t res = from->detachNextBuffer(&buffer, &fence);
+    if (res == NO_INIT) {
         // If we just discovered that this output has been abandoned, note that,
         // but we can't do anything else, since buffer is invalid
         onAbandonedLocked();
         return;
+    } else if (res == NO_MEMORY) {
+        SP_LOGV("%s: No free buffers", __FUNCTION__);
+        return;
     } else {
-        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                "detaching buffer from output failed (%d)", status);
+        LOG_ALWAYS_FATAL_IF(res != NO_ERROR,
+                "detaching buffer from output failed (%d)", res);
     }
 
-    ALOGV("detached buffer %#" PRIx64 " from output %p",
-          buffer->getId(), from.get());
-
     BufferTracker& tracker = *(mBuffers[buffer->getId()]);
-
     // Merge the release fence of the incoming buffer so that the fence we send
     // back to the input includes all of the outputs' fences
-    tracker.mergeFence(fence);
+    if (fence != nullptr && fence->isValid()) {
+        tracker.mergeFence(fence);
+    }
+    SP_LOGV("detached buffer %" PRId64 " %p from output %p",
+            buffer->getId(), buffer.get(), from.get());
 
     // Check to see if this is the last outstanding reference to this buffer
-    size_t referenceCount = tracker.decrementReferenceCountLocked();
-    ALOGV("buffer %#" PRIx64 " reference count %zu", buffer->getId(),
-            referenceCount);
-    if (referenceCount > 0) {
-        return;
-    }
-
-    // If we've been abandoned, we can't return the buffer to the input, so just
-    // stop tracking it and move on
-    if (mIsAbandoned) {
-        mBuffers.erase(buffer->getId());
-        return;
-    }
-
-    // Attach and release the buffer back to the input
-    int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
-    status = mConsumer->attachBuffer(&consumerSlot, tracker.getBuffer());
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "attaching buffer to input failed (%d)", status);
-
-    status = mConsumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
-            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker.getMergedFence());
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "releasing buffer to input failed (%d)", status);
-
-    ALOGV("released buffer %#" PRIx64 " to input", buffer->getId());
-
-    // We no longer need to track the buffer once it has been returned to the
-    // input
-    mBuffers.erase(buffer->getId());
-
-    // Notify any waiting onFrameAvailable calls
-    --mOutstandingBuffers;
-    mReleaseCondition.signal();
+    decrementBufRefCountLocked(buffer->getId(), from);
 }
 
 void Camera3StreamSplitter::onAbandonedLocked() {
-    ALOGE("one of my outputs has abandoned me");
-    if (!mIsAbandoned && mConsumer != nullptr) {
-        mConsumer->consumerDisconnect();
+    // If this is called from binderDied callback, it means the app process
+    // holding the binder has died. CameraService will be notified of the binder
+    // death, and camera device will be closed, which in turn calls
+    // disconnect().
+    //
+    // If this is called from onBufferReleasedByOutput or onFrameAvailable, one
+    // consumer being abanoned shouldn't impact the other consumer. So we won't
+    // stop the buffer flow.
+    //
+    // In both cases, we don't need to do anything here.
+    SP_LOGV("One of my outputs has abandoned me");
+}
+
+int Camera3StreamSplitter::getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+        const sp<GraphicBuffer>& gb) {
+    auto& outputSlots = *mOutputSlots[gbp];
+
+    for (size_t i = 0; i < outputSlots.size(); i++) {
+        if (outputSlots[i] == gb) {
+            return (int)i;
+        }
     }
-    mIsAbandoned = true;
-    mReleaseCondition.broadcast();
+
+    SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+            gbp.get());
+    return BufferItem::INVALID_BUFFER_SLOT;
+}
+
+status_t Camera3StreamSplitter::removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+        const sp<GraphicBuffer>& gb) {
+    auto& outputSlots = *mOutputSlots[gbp];
+
+    for (size_t i = 0; i < outputSlots.size(); i++) {
+        if (outputSlots[i] == gb) {
+           outputSlots[i].clear();
+           return NO_ERROR;
+        }
+    }
+
+    SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+            gbp.get());
+    return BAD_VALUE;
 }
 
 Camera3StreamSplitter::OutputListener::OutputListener(
@@ -422,6 +528,7 @@
       : mSplitter(splitter), mOutput(output) {}
 
 void Camera3StreamSplitter::OutputListener::onBufferReleased() {
+    ATRACE_CALL();
     sp<Camera3StreamSplitter> splitter = mSplitter.promote();
     sp<IGraphicBufferProducer> output = mOutput.promote();
     if (splitter != nullptr && output != nullptr) {
@@ -438,9 +545,9 @@
 }
 
 Camera3StreamSplitter::BufferTracker::BufferTracker(
-        const sp<GraphicBuffer>& buffer, size_t referenceCount)
-      : mBuffer(buffer), mMergedFence(Fence::NO_FENCE),
-        mReferenceCount(referenceCount) {}
+        const sp<GraphicBuffer>& buffer, const std::vector<size_t>& requestedSurfaces)
+      : mBuffer(buffer), mMergedFence(Fence::NO_FENCE), mRequestedSurfaces(requestedSurfaces),
+        mReferenceCount(requestedSurfaces.size()) {}
 
 void Camera3StreamSplitter::BufferTracker::mergeFence(const sp<Fence>& with) {
     mMergedFence = Fence::merge(String8("Camera3StreamSplitter"), mMergedFence, with);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 92371ff..cc623e0 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -26,6 +26,11 @@
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 
+#define SP_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+
 namespace android {
 
 class GraphicBuffer;
@@ -47,8 +52,8 @@
     // Connect to the stream splitter by creating buffer queue and connecting it
     // with output surfaces.
     status_t connect(const std::vector<sp<Surface> >& surfaces,
-            uint32_t consumerUsage, size_t hal_max_buffers,
-            sp<Surface>& consumer);
+            uint32_t consumerUsage, size_t halMaxBuffers,
+            sp<Surface>* consumer);
 
     // addOutput adds an output BufferQueue to the splitter. The splitter
     // connects to outputQueue as a CPU producer, and any buffers queued
@@ -61,13 +66,22 @@
     // outputQueue has not been added to the splitter. BAD_VALUE is returned if
     // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
     // of other error codes.
-    status_t addOutput(const sp<Surface>& outputQueue, size_t hal_max_buffers);
+    status_t addOutput(const sp<Surface>& outputQueue);
 
-    // Request surfaces for a particular frame number. The requested surfaces
-    // are stored in a FIFO queue. And when the buffer becomes available from the
-    // input queue, the registered surfaces are used to decide which output is
-    // the buffer sent to.
-    status_t notifyRequestedSurfaces(const std::vector<size_t>& surfaces);
+    // Notification that the graphic buffer has been released to the input
+    // BufferQueue. The buffer should be reused by the camera device instead of
+    // queuing to the outputs.
+    status_t notifyBufferReleased(const sp<GraphicBuffer>& buffer);
+
+    // Attach a buffer to the specified outputs. This call reserves a buffer
+    // slot in the output queue.
+    status_t attachBufferToOutputs(ANativeWindowBuffer* anb,
+            const std::vector<size_t>& surface_ids);
+
+    // Get return value of onFrameAvailable to work around problem that
+    // onFrameAvailable is void. This function should be called by the producer
+    // right after calling queueBuffer().
+    status_t getOnFrameAvailableResult();
 
     // Disconnect the buffer queue from output surfaces.
     void disconnect();
@@ -115,6 +129,10 @@
     // acquire. This must be called with mMutex locked.
     void onAbandonedLocked();
 
+    // Decrement the buffer's reference count. Once the reference count becomes
+    // 0, return the buffer back to the input BufferQueue.
+    void decrementBufRefCountLocked(uint64_t id, const sp<IGraphicBufferProducer>& from);
+
     // This is a thin wrapper class that lets us determine which BufferQueue
     // the IProducerListener::onBufferReleased callback is associated with. We
     // create one of these per output BufferQueue, and then pass the producer
@@ -139,7 +157,8 @@
 
     class BufferTracker {
     public:
-        BufferTracker(const sp<GraphicBuffer>& buffer, size_t referenceCount);
+        BufferTracker(const sp<GraphicBuffer>& buffer,
+                const std::vector<size_t>& requestedSurfaces);
         ~BufferTracker() = default;
 
         const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
@@ -151,6 +170,8 @@
         // Only called while mMutex is held
         size_t decrementReferenceCountLocked();
 
+        const std::vector<size_t> requestedSurfaces() const { return mRequestedSurfaces; }
+
     private:
 
         // Disallow copying
@@ -159,39 +180,43 @@
 
         sp<GraphicBuffer> mBuffer; // One instance that holds this native handle
         sp<Fence> mMergedFence;
+
+        // Request surfaces for a particular buffer. And when the buffer becomes
+        // available from the input queue, the registered surfaces are used to decide
+        // which output is the buffer sent to.
+        std::vector<size_t> mRequestedSurfaces;
         size_t mReferenceCount;
     };
 
-    // A deferred output is an output being added to the splitter after
-    // connect() call, whereas a non deferred output is added within connect()
-    // call.
-    enum class OutputType { NonDeferred, Deferred };
-
     // Must be accessed through RefBase
     virtual ~Camera3StreamSplitter();
 
-    status_t addOutputLocked(const sp<Surface>& outputQueue,
-                             size_t hal_max_buffers, OutputType outputType);
+    status_t addOutputLocked(const sp<Surface>& outputQueue);
+
+    // Send a buffer to particular output, and increment the reference count
+    // of the buffer. If this output is abandoned, the buffer's reference count
+    // won't be incremented.
+    status_t outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+            const BufferItem& bufferItem);
 
     // Get unique name for the buffer queue consumer
-    static String8 getUniqueConsumerName();
+    String8 getUniqueConsumerName();
 
-    // Max consumer side buffers for deferred surface. This will be used as a
-    // lower bound for overall consumer side max buffers.
-    static const int MAX_BUFFERS_DEFERRED_OUTPUT = 2;
-    int mMaxConsumerBuffers = MAX_BUFFERS_DEFERRED_OUTPUT;
+    // Helper function to get the BufferQueue slot where a particular buffer is attached to.
+    int getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+            const sp<GraphicBuffer>& gb);
+    // Helper function to remove the buffer from the BufferQueue slot
+    status_t removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+            const sp<GraphicBuffer>& gb);
+
+
+    // Sum of max consumer buffers for all outputs
+    size_t mMaxConsumerBuffers = 0;
+    size_t mMaxHalBuffers = 0;
 
     static const nsecs_t kDequeueBufferTimeout   = s2ns(1); // 1 sec
 
-    // mIsAbandoned is set to true when an output dies. Once the Camera3StreamSplitter
-    // has been abandoned, it will continue to detach buffers from other
-    // outputs, but it will disconnect from the input and not attempt to
-    // communicate with it further.
-    bool mIsAbandoned = false;
-
     Mutex mMutex;
-    Condition mReleaseCondition;
-    int mOutstandingBuffers = 0;
 
     sp<IGraphicBufferProducer> mProducer;
     sp<IGraphicBufferConsumer> mConsumer;
@@ -199,14 +224,28 @@
     sp<Surface> mSurface;
 
     std::vector<sp<IGraphicBufferProducer> > mOutputs;
-    // Tracking which outputs should the buffer be attached and queued
-    // to for each input buffer.
-    std::vector<std::vector<size_t> > mRequestedSurfaces;
-
     // Map of GraphicBuffer IDs (GraphicBuffer::getId()) to buffer tracking
     // objects (which are mostly for counting how many outputs have released the
     // buffer, but also contain merged release fences).
     std::unordered_map<uint64_t, std::unique_ptr<BufferTracker> > mBuffers;
+
+    struct GBPHash {
+        std::size_t operator()(const sp<IGraphicBufferProducer>& producer) const {
+            return std::hash<IGraphicBufferProducer *>{}(producer.get());
+        }
+    };
+
+    std::unordered_map<sp<IGraphicBufferProducer>, sp<OutputListener>,
+            GBPHash> mNotifiers;
+
+    typedef std::vector<sp<GraphicBuffer>> OutputSlots;
+    std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>,
+            GBPHash> mOutputSlots;
+
+    // Latest onFrameAvailable return value
+    std::atomic<status_t> mOnFrameAvailableRes{0};
+
+    String8 mConsumerName;
 };
 
 } // namespace android
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index a428c75..8814cf2 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -20,7 +20,7 @@
 
 # service executable
 include $(CLEAR_VARS)
-LOCAL_REQUIRED_MODULES_arm := mediacodec-seccomp.policy
+LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
 LOCAL_SRC_FILES := main_codecservice.cpp
 LOCAL_SHARED_LIBRARIES := \
     libmedia \
@@ -46,4 +46,20 @@
 LOCAL_INIT_RC := mediacodec.rc
 include $(BUILD_EXECUTABLE)
 
+# service seccomp policy
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediacodec.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
+# use the 32 bit policy
+ifdef TARGET_2ND_ARCH
+    LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_2ND_ARCH).policy
+else
+    LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_ARCH).policy
+endif
+include $(BUILD_PREBUILT)
+endif
+
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 688c651..ef305b4 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -38,13 +38,16 @@
 using namespace android;
 
 // Must match location in Android.mk.
-static const char kSeccompPolicyPath[] = "/system/etc/seccomp_policy/mediacodec-seccomp.policy";
+static const char kSystemSeccompPolicyPath[] =
+        "/system/etc/seccomp_policy/mediacodec.policy";
+static const char kVendorSeccompPolicyPath[] =
+        "/vendor/etc/seccomp_policy/mediacodec.policy";
 
 int main(int argc __unused, char** argv)
 {
     LOG(INFO) << "mediacodecservice starting";
     signal(SIGPIPE, SIG_IGN);
-    SetUpMinijail(kSeccompPolicyPath, std::string());
+    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
     strcpy(argv[0], "media.codec");
 
diff --git a/services/mediacodec/minijail/Android.mk b/services/mediacodec/minijail/Android.mk
deleted file mode 100644
index de05bc3..0000000
--- a/services/mediacodec/minijail/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediacodec-seccomp.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-
-# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
-# use the 32 bit policy
-ifdef TARGET_2ND_ARCH
-    LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediacodec-seccomp-$(TARGET_2ND_ARCH).policy
-else
-    LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediacodec-seccomp-$(TARGET_ARCH).policy
-endif
-
-# allow device specific additions to the syscall whitelist
-LOCAL_SRC_FILES += $(wildcard $(foreach dir, $(BOARD_SECCOMP_POLICY), \
-                     $(dir)/mediacodec-seccomp.policy))
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_SRC_FILES)
-	@mkdir -p $(dir $@)
-	$(hide) cat > $@ $^
-
-endif
diff --git a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
similarity index 100%
rename from services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
rename to services/mediacodec/seccomp_policy/mediacodec-arm.policy
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 169c770..1ebb7ff 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -11,10 +11,9 @@
 # service executable
 include $(CLEAR_VARS)
 # seccomp filters are defined for the following architectures:
-LOCAL_REQUIRED_MODULES_arm := mediaextractor-seccomp.policy
-LOCAL_REQUIRED_MODULES_arm64 := mediaextractor-seccomp.policy
-LOCAL_REQUIRED_MODULES_x86 := mediaextractor-seccomp.policy
-# TODO add seccomp filter for x86_64.
+LOCAL_REQUIRED_MODULES_arm := mediaextractor.policy
+LOCAL_REQUIRED_MODULES_arm64 := mediaextractor.policy
+LOCAL_REQUIRED_MODULES_x86 := mediaextractor.policy
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
     liblog libbase libicuuc libavservices_minijail
@@ -24,4 +23,12 @@
 LOCAL_C_INCLUDES := frameworks/av/media/libmedia
 include $(BUILD_EXECUTABLE)
 
-include $(call all-makefiles-under, $(LOCAL_PATH))
+# service seccomp filter
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediaextractor.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+LOCAL_SRC_FILES := seccomp_policy/mediaextractor-$(TARGET_ARCH).policy
+include $(BUILD_PREBUILT)
+endif
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 752b7e4..9bc69c4 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -24,6 +24,8 @@
 
 #include <string>
 
+#include <android-base/logging.h>
+
 // from LOCAL_C_INCLUDES
 #include "IcuUtils.h"
 #include "MediaExtractorService.h"
@@ -32,8 +34,10 @@
 
 using namespace android;
 
-// Must match location in Android.mk.
-static const char kSeccompPolicyPath[] = "/system/etc/seccomp_policy/mediaextractor-seccomp.policy";
+static const char kSystemSeccompPolicyPath[] =
+        "/system/etc/seccomp_policy/mediaextractor.policy";
+static const char kVendorSeccompPolicyPath[] =
+        "/vendor/etc/seccomp_policy/mediaextractor.policy";
 
 int main(int argc __unused, char** argv)
 {
@@ -43,7 +47,7 @@
         20 /* upper limit as percentage of physical RAM */);
 
     signal(SIGPIPE, SIG_IGN);
-    SetUpMinijail(kSeccompPolicyPath, std::string());
+    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
     InitializeIcuOrDie();
 
diff --git a/services/mediaextractor/minijail/Android.mk b/services/mediaextractor/minijail/Android.mk
deleted file mode 100644
index 6b01e77..0000000
--- a/services/mediaextractor/minijail/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# TODO add filter for x86_64
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediaextractor-seccomp.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_ARCH).policy
-
-# allow device specific additions to the syscall whitelist
-LOCAL_SRC_FILES += $(wildcard $(foreach dir, $(BOARD_SECCOMP_POLICY), \
-                     $(dir)/mediaextractor-seccomp.policy))
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_SRC_FILES)
-	@mkdir -p $(dir $@)
-	$(hide) cat > $@ $^
-
-endif
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
similarity index 100%
rename from services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
rename to services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
similarity index 100%
rename from services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy
rename to services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
similarity index 100%
rename from services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
rename to services/mediaextractor/seccomp_policy/mediaextractor-x86.policy