Merge "Camera: Map between bufferqueue gralloc0 usage, and HIDL gralloc1 usages" into oc-dev
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index bf9904c..c6c35ef 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -240,6 +240,14 @@
     c->releaseRecordingFrameHandle(handle);
 }
 
+void Camera::releaseRecordingFrameHandleBatch(
+        const std::vector<native_handle_t*> handles) {
+    ALOGV("releaseRecordingFrameHandleBatch");
+    sp <::android::hardware::ICamera> c = mCamera;
+    if (c == 0) return;
+    c->releaseRecordingFrameHandleBatch(handles);
+}
+
 // get preview state
 bool Camera::previewEnabled()
 {
@@ -418,6 +426,37 @@
     }
 }
 
+void Camera::recordingFrameHandleCallbackTimestampBatch(
+        const std::vector<nsecs_t>& timestamps,
+        const std::vector<native_handle_t*>& handles)
+{
+    // If recording proxy listener is registered, forward the frame and return.
+    // The other listener (mListener) is ignored because the receiver needs to
+    // call releaseRecordingFrameHandle.
+    sp<ICameraRecordingProxyListener> proxylistener;
+    {
+        Mutex::Autolock _l(mLock);
+        proxylistener = mRecordingProxyListener;
+    }
+    if (proxylistener != NULL) {
+        proxylistener->recordingFrameHandleCallbackTimestampBatch(timestamps, handles);
+        return;
+    }
+
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+
+    if (listener != NULL) {
+        listener->postRecordingFrameHandleTimestampBatch(timestamps, handles);
+    } else {
+        ALOGW("No listener was set. Drop a batch of recording frames.");
+        releaseRecordingFrameHandleBatch(handles);
+    }
+}
+
 sp<ICameraRecordingProxy> Camera::getRecordingProxy() {
     ALOGV("getProxy");
     return new RecordingProxy(this);
@@ -448,6 +487,12 @@
     mCamera->releaseRecordingFrameHandle(handle);
 }
 
+void Camera::RecordingProxy::releaseRecordingFrameHandleBatch(
+        const std::vector<native_handle_t*>& handles) {
+    ALOGV("RecordingProxy::releaseRecordingFrameHandleBatch");
+    mCamera->releaseRecordingFrameHandleBatch(handles);
+}
+
 Camera::RecordingProxy::RecordingProxy(const sp<Camera>& camera)
 {
     mCamera = camera;
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 2bf956d..f0945c7 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -55,6 +55,7 @@
     SET_VIDEO_BUFFER_MODE,
     SET_VIDEO_BUFFER_TARGET,
     RELEASE_RECORDING_FRAME_HANDLE,
+    RELEASE_RECORDING_FRAME_HANDLE_BATCH,
 };
 
 class BpCamera: public BpInterface<ICamera>
@@ -172,6 +173,24 @@
         native_handle_delete(handle);
     }
 
+    void releaseRecordingFrameHandleBatch(const std::vector<native_handle_t*>& handles) {
+        ALOGV("releaseRecordingFrameHandleBatch");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        uint32_t n = handles.size();
+        data.writeUint32(n);
+        for (auto& handle : handles) {
+            data.writeNativeHandle(handle);
+        }
+        remote()->transact(RELEASE_RECORDING_FRAME_HANDLE_BATCH, data, &reply);
+
+        // Close the native handle because camera received a dup copy.
+        for (auto& handle : handles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+    }
+
     status_t setVideoBufferMode(int32_t videoBufferMode)
     {
         ALOGV("setVideoBufferMode: %d", videoBufferMode);
@@ -378,6 +397,19 @@
             releaseRecordingFrameHandle(data.readNativeHandle());
             return NO_ERROR;
         } break;
+        case RELEASE_RECORDING_FRAME_HANDLE_BATCH: {
+            ALOGV("RELEASE_RECORDING_FRAME_HANDLE_BATCH");
+            CHECK_INTERFACE(ICamera, data, reply);
+            // releaseRecordingFrameHandle will be responsble to close the native handle.
+            uint32_t n = data.readUint32();
+            std::vector<native_handle_t*> handles;
+            handles.reserve(n);
+            for (uint32_t i = 0; i < n; i++) {
+                handles.push_back(data.readNativeHandle());
+            }
+            releaseRecordingFrameHandleBatch(handles);
+            return NO_ERROR;
+        } break;
         case SET_VIDEO_BUFFER_MODE: {
             ALOGV("SET_VIDEO_BUFFER_MODE");
             CHECK_INTERFACE(ICamera, data, reply);
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 1b6fac4..7e6297c 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -32,6 +32,7 @@
     DATA_CALLBACK,
     DATA_CALLBACK_TIMESTAMP,
     RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP,
+    RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH,
 };
 
 class BpCameraClient: public BpInterface<ICameraClient>
@@ -91,6 +92,29 @@
         remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP, data, &reply,
                 IBinder::FLAG_ONEWAY);
     }
+
+    void recordingFrameHandleCallbackTimestampBatch(
+            const std::vector<nsecs_t>& timestamps,
+            const std::vector<native_handle_t*>& handles) {
+        ALOGV("recordingFrameHandleCallbackTimestampBatch");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        uint32_t n = timestamps.size();
+        if (n != handles.size()) {
+            ALOGE("%s: size of timestamps(%zu) and handles(%zu) mismatch!",
+                    __FUNCTION__, timestamps.size(), handles.size());
+            return;
+        }
+        data.writeUint32(n);
+        for (auto ts : timestamps) {
+            data.writeInt64(ts);
+        }
+        for (auto& handle : handles) {
+            data.writeNativeHandle(handle);
+        }
+        remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
@@ -154,6 +178,41 @@
             recordingFrameHandleCallbackTimestamp(timestamp, handle);
             return NO_ERROR;
         } break;
+        case RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH: {
+            ALOGV("RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            uint32_t n = 0;
+            status_t res = data.readUint32(&n);
+            if (res != OK) {
+                ALOGE("%s: Failed to read batch size: %s (%d)", __FUNCTION__, strerror(-res), res);
+                return BAD_VALUE;
+            }
+            std::vector<nsecs_t> timestamps;
+            std::vector<native_handle_t*> handles;
+            timestamps.reserve(n);
+            handles.reserve(n);
+            for (uint32_t i = 0; i < n; i++) {
+                res = data.readInt64(&timestamps[i]);
+                if (res != OK) {
+                    ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
+                            __FUNCTION__, i, strerror(-res), res);
+                    return BAD_VALUE;
+                }
+            }
+            for (uint32_t i = 0; i < n; i++) {
+                native_handle_t* handle = data.readNativeHandle();
+                if (handle == nullptr) {
+                    ALOGE("%s: Received a null native handle at handles[%d]",
+                            __FUNCTION__, i);
+                    return BAD_VALUE;
+                }
+                handles.push_back(handle);
+            }
+
+            // The native handle will be freed in BpCamera::releaseRecordingFrameHandleBatch.
+            recordingFrameHandleCallbackTimestampBatch(timestamps, handles);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
index c9f8b5c..bd6af75 100644
--- a/camera/ICameraRecordingProxy.cpp
+++ b/camera/ICameraRecordingProxy.cpp
@@ -32,6 +32,7 @@
     STOP_RECORDING,
     RELEASE_RECORDING_FRAME,
     RELEASE_RECORDING_FRAME_HANDLE,
+    RELEASE_RECORDING_FRAME_HANDLE_BATCH,
 };
 
 
@@ -82,6 +83,24 @@
         native_handle_close(handle);
         native_handle_delete(handle);
     }
+
+    void releaseRecordingFrameHandleBatch(const std::vector<native_handle_t*>& handles) {
+        ALOGV("releaseRecordingFrameHandleBatch");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
+        uint32_t n = handles.size();
+        data.writeUint32(n);
+        for (auto& handle : handles) {
+            data.writeNativeHandle(handle);
+        }
+        remote()->transact(RELEASE_RECORDING_FRAME_HANDLE_BATCH, data, &reply);
+
+        // Close the native handle because camera received a dup copy.
+        for (auto& handle : handles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraRecordingProxy, "android.hardware.ICameraRecordingProxy");
@@ -121,6 +140,31 @@
             releaseRecordingFrameHandle(data.readNativeHandle());
             return NO_ERROR;
         } break;
+        case RELEASE_RECORDING_FRAME_HANDLE_BATCH: {
+            ALOGV("RELEASE_RECORDING_FRAME_HANDLE_BATCH");
+            CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
+            uint32_t n = 0;
+            status_t res = data.readUint32(&n);
+            if (res != OK) {
+                ALOGE("%s: Failed to read batch size: %s (%d)", __FUNCTION__, strerror(-res), res);
+                return BAD_VALUE;
+            }
+            std::vector<native_handle_t*> handles;
+            handles.reserve(n);
+            for (uint32_t i = 0; i < n; i++) {
+                native_handle_t* handle = data.readNativeHandle();
+                if (handle == nullptr) {
+                    ALOGE("%s: Received a null native handle at handles[%d]",
+                            __FUNCTION__, i);
+                    return BAD_VALUE;
+                }
+                handles.push_back(handle);
+            }
+
+            // releaseRecordingFrameHandleBatch will be responsble to close the native handle.
+            releaseRecordingFrameHandleBatch(handles);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index 8529d3e..c954241 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -28,6 +28,7 @@
 enum {
     DATA_CALLBACK_TIMESTAMP = IBinder::FIRST_CALL_TRANSACTION,
     RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP,
+    RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH
 };
 
 class BpCameraRecordingProxyListener: public BpInterface<ICameraRecordingProxyListener>
@@ -62,6 +63,36 @@
         native_handle_close(handle);
         native_handle_delete(handle);
     }
+
+    void recordingFrameHandleCallbackTimestampBatch(
+            const std::vector<nsecs_t>& timestamps,
+            const std::vector<native_handle_t*>& handles) {
+        ALOGV("recordingFrameHandleCallbackTimestampBatch");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraRecordingProxyListener::getInterfaceDescriptor());
+
+        uint32_t n = timestamps.size();
+        if (n != handles.size()) {
+            ALOGE("%s: size of timestamps(%zu) and handles(%zu) mismatch!",
+                    __FUNCTION__, timestamps.size(), handles.size());
+            return;
+        }
+        data.writeUint32(n);
+        for (auto ts : timestamps) {
+            data.writeInt64(ts);
+        }
+        for (auto& handle : handles) {
+            data.writeNativeHandle(handle);
+        }
+        remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH, data, &reply,
+                IBinder::FLAG_ONEWAY);
+
+        // The native handle is dupped in ICameraClient so we need to free it here.
+        for (auto& handle : handles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraRecordingProxyListener, "android.hardware.ICameraRecordingProxyListener");
@@ -101,6 +132,41 @@
             recordingFrameHandleCallbackTimestamp(timestamp, handle);
             return NO_ERROR;
         } break;
+        case RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH: {
+            ALOGV("RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP_BATCH");
+            CHECK_INTERFACE(ICameraRecordingProxyListener, data, reply);
+            uint32_t n = 0;
+            status_t res = data.readUint32(&n);
+            if (res != OK) {
+                ALOGE("%s: Failed to read batch size: %s (%d)", __FUNCTION__, strerror(-res), res);
+                return BAD_VALUE;
+            }
+            std::vector<nsecs_t> timestamps;
+            std::vector<native_handle_t*> handles;
+            timestamps.reserve(n);
+            handles.reserve(n);
+            for (uint32_t i = 0; i < n; i++) {
+                res = data.readInt64(&timestamps[i]);
+                if (res != OK) {
+                    ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
+                            __FUNCTION__, i, strerror(-res), res);
+                    return BAD_VALUE;
+                }
+            }
+            for (uint32_t i = 0; i < n; i++) {
+                native_handle_t* handle = data.readNativeHandle();
+                if (handle == nullptr) {
+                    ALOGE("%s: Received a null native handle at handles[%d]",
+                            __FUNCTION__, i);
+                    return BAD_VALUE;
+                }
+                handles.push_back(handle);
+            }
+            // The native handle will be freed in
+            // BpCameraRecordingProxy::releaseRecordingFrameHandleBatch.
+            recordingFrameHandleCallbackTimestampBatch(timestamps, handles);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 57dc228..430aa1c 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -44,6 +44,9 @@
                           camera_frame_metadata_t *metadata) = 0;
     virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
     virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle) = 0;
+    virtual void postRecordingFrameHandleTimestampBatch(
+            const std::vector<nsecs_t>& timestamps,
+            const std::vector<native_handle_t*>& handles) = 0;
 };
 
 class Camera;
@@ -118,6 +121,10 @@
             // release a recording frame handle
             void        releaseRecordingFrameHandle(native_handle_t *handle);
 
+            // release a batch of recording frame handles
+            void        releaseRecordingFrameHandleBatch(
+                    const std::vector<native_handle_t*> handles);
+
             // autoFocus - status returned from callback
             status_t    autoFocus();
 
@@ -166,6 +173,10 @@
                                      camera_frame_metadata_t *metadata);
     virtual void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
     virtual void        recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle);
+    virtual void        recordingFrameHandleCallbackTimestampBatch(
+                                const std::vector<nsecs_t>& timestamps,
+                                const std::vector<native_handle_t*>& handles);
+
 
     class RecordingProxy : public BnCameraRecordingProxy
     {
@@ -177,6 +188,8 @@
         virtual void stopRecording();
         virtual void releaseRecordingFrame(const sp<IMemory>& mem);
         virtual void releaseRecordingFrameHandle(native_handle_t* handle);
+        virtual void releaseRecordingFrameHandleBatch(
+                const std::vector<native_handle_t*>& handles);
 
     private:
         sp<Camera>         mCamera;
diff --git a/camera/include/camera/ICameraRecordingProxy.h b/camera/include/camera/ICameraRecordingProxy.h
index cb6824a..02af2f3 100644
--- a/camera/include/camera/ICameraRecordingProxy.h
+++ b/camera/include/camera/ICameraRecordingProxy.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_H
 #define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_H
 
+#include <vector>
 #include <binder/IInterface.h>
 #include <cutils/native_handle.h>
 #include <utils/RefBase.h>
@@ -85,6 +86,8 @@
     virtual void            stopRecording() = 0;
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem) = 0;
     virtual void            releaseRecordingFrameHandle(native_handle_t *handle) = 0;
+    virtual void            releaseRecordingFrameHandleBatch(
+                                    const std::vector<native_handle_t*>& handles) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/camera/include/camera/ICameraRecordingProxyListener.h b/camera/include/camera/ICameraRecordingProxyListener.h
index 1fee5b9..da03c56 100644
--- a/camera/include/camera/ICameraRecordingProxyListener.h
+++ b/camera/include/camera/ICameraRecordingProxyListener.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_LISTENER_H
 #define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_LISTENER_H
 
+#include <vector>
 #include <binder/IInterface.h>
 #include <cutils/native_handle.h>
 #include <stdint.h>
@@ -38,6 +39,10 @@
 
     virtual void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
                                                        native_handle_t* handle) = 0;
+
+    virtual void recordingFrameHandleCallbackTimestampBatch(
+            const std::vector<nsecs_t>& timestamps,
+            const std::vector<native_handle_t*>& handles) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/camera/include/camera/android/hardware/ICamera.h b/camera/include/camera/android/hardware/ICamera.h
index 315669e..80823d6 100644
--- a/camera/include/camera/android/hardware/ICamera.h
+++ b/camera/include/camera/android/hardware/ICamera.h
@@ -101,6 +101,11 @@
     // ICameraClient::recordingFrameHandleCallbackTimestamp.
     virtual void            releaseRecordingFrameHandle(native_handle_t *handle) = 0;
 
+    // Release a batch of recording frame handles that was received via
+    // ICameraClient::recordingFrameHandleCallbackTimestampBatch
+    virtual void            releaseRecordingFrameHandleBatch(
+            const std::vector<native_handle_t*>& handles) = 0;
+
     // auto focus
     virtual status_t        autoFocus() = 0;
 
diff --git a/camera/include/camera/android/hardware/ICameraClient.h b/camera/include/camera/android/hardware/ICameraClient.h
index f6ee311..8e46d17 100644
--- a/camera/include/camera/android/hardware/ICameraClient.h
+++ b/camera/include/camera/android/hardware/ICameraClient.h
@@ -41,6 +41,13 @@
     // ICamera::releaseRecordingFrameHandle to release the frame handle.
     virtual void            recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
                                          native_handle_t* handle) = 0;
+
+    // Invoked to send a batch of recording frame handles with timestamp. Call
+    // ICamera::releaseRecordingFrameHandleBatch to release the frame handles.
+    // Size of timestamps and handles must match
+    virtual void            recordingFrameHandleCallbackTimestampBatch(
+                                        const std::vector<nsecs_t>& timestamps,
+                                        const std::vector<native_handle_t*>& handles) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
index 6c91fdc..ecca354 100644
--- a/camera/tests/CameraZSLTests.cpp
+++ b/camera/tests/CameraZSLTests.cpp
@@ -51,6 +51,9 @@
             const sp<IMemory>&) override {};
     void recordingFrameHandleCallbackTimestamp(nsecs_t,
             native_handle_t*) override {};
+    void recordingFrameHandleCallbackTimestampBatch(
+            const std::vector<nsecs_t>&,
+            const std::vector<native_handle_t*>&) override {};
 
     status_t waitForPreviewStart();
     status_t waitForEvent(Mutex &mutex, Condition &condition, bool &flag);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 4d8dd3c..80aad2f 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -908,9 +908,7 @@
 
     if (listComponents) {
         sp<IOMX> omx;
-        int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
-        if ((trebleOmx == 1) || ((trebleOmx == -1) &&
-                property_get_bool("persist.hal.binderization", 0))) {
+        if (property_get_bool("persist.media.treble_omx", true)) {
             using namespace ::android::hardware::media::omx::V1_0;
             sp<IOmx> tOmx = IOmx::getService();
 
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 590622e..5b56501 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_SRC_FILES += \
     CasImpl.cpp \
     DescramblerImpl.cpp \
+    DrmPluginPath.cpp \
     DrmSessionManager.cpp \
     ICrypto.cpp \
     IDrm.cpp \
diff --git a/drm/libmediadrm/Crypto.cpp b/drm/libmediadrm/Crypto.cpp
index d93dad6..a5d7346 100644
--- a/drm/libmediadrm/Crypto.cpp
+++ b/drm/libmediadrm/Crypto.cpp
@@ -22,6 +22,7 @@
 
 #include <binder/IMemory.h>
 #include <media/Crypto.h>
+#include <media/DrmPluginPath.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AString.h>
@@ -102,7 +103,7 @@
     }
 
     // no luck, have to search
-    String8 dirPath("/vendor/lib/mediadrm");
+    String8 dirPath(getDrmPluginPath());
     String8 pluginPath;
 
     DIR* pDir = opendir(dirPath.string());
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 1466222..25c16da 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -105,7 +105,8 @@
 CryptoHal::CryptoHal()
     : mFactories(makeCryptoFactories()),
       mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
-      mNextBufferId(0) {
+      mNextBufferId(0),
+      mHeapSeqNum(0) {
 }
 
 CryptoHal::~CryptoHal() {
@@ -225,26 +226,37 @@
  * size.  Once the heap base is established, shared memory buffers
  * are sent by providing an offset into the heap and a buffer size.
  */
-void CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+    if (heap == NULL) {
+        ALOGE("setHeapBase(): heap is NULL");
+        return -1;
+    }
     native_handle_t* nativeHandle = native_handle_create(1, 0);
     if (!nativeHandle) {
-        ALOGE("setSharedBufferBase(), failed to create native handle");
-        return;
+        ALOGE("setHeapBase(), failed to create native handle");
+        return -1;
     }
-    if (heap == NULL) {
-        ALOGE("setSharedBufferBase(): heap is NULL");
-        return;
-    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    int32_t seqNum = mHeapSeqNum++;
     int fd = heap->getHeapID();
     nativeHandle->data[0] = fd;
     auto hidlHandle = hidl_handle(nativeHandle);
     auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
-    mHeapBases.add(heap->getBase(), mNextBufferId);
+    mHeapBases.add(seqNum, mNextBufferId);
     Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
     ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+    return seqNum;
 }
 
-status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer) {
+void CryptoHal::clearHeapBase(int32_t seqNum) {
+    Mutex::Autolock autoLock(mLock);
+
+    mHeapBases.removeItem(seqNum);
+}
+
+status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer) {
     ssize_t offset;
     size_t size;
 
@@ -257,11 +269,10 @@
         return UNEXPECTED_NULL;
     }
 
-    if (mHeapBases.indexOfKey(heap->getBase()) < 0) {
-        setHeapBase(heap);
-    }
+    // memory must be in the declared heap
+    CHECK(mHeapBases.indexOfKey(seqNum) >= 0);
 
-    buffer->bufferId = mHeapBases.valueFor(heap->getBase());
+    buffer->bufferId = mHeapBases.valueFor(seqNum);
     buffer->offset = offset >= 0 ? offset : 0;
     buffer->size = size;
     return OK;
@@ -269,7 +280,7 @@
 
 ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
         CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-        const sp<IMemory> &source, size_t offset,
+        const ICrypto::SourceBuffer &source, size_t offset,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
         const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {
     Mutex::Autolock autoLock(mLock);
@@ -309,11 +320,12 @@
     }
     auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
 
+    int32_t heapSeqNum = source.mHeapSeqNum;
     bool secure;
     ::DestinationBuffer hDestination;
     if (destination.mType == kDestinationTypeSharedMemory) {
         hDestination.type = BufferType::SHARED_MEMORY;
-        status_t status = toSharedBuffer(destination.mSharedMemory,
+        status_t status = toSharedBuffer(destination.mSharedMemory, heapSeqNum,
                 &hDestination.nonsecureMemory);
         if (status != OK) {
             return status;
@@ -326,7 +338,7 @@
     }
 
     ::SharedBuffer hSource;
-    status_t status = toSharedBuffer(source, &hSource);
+    status_t status = toSharedBuffer(source.mSharedMemory, heapSeqNum, &hSource);
     if (status != OK) {
         return status;
     }
diff --git a/drm/libmediadrm/Drm.cpp b/drm/libmediadrm/Drm.cpp
index e3176e3..1004eb8 100644
--- a/drm/libmediadrm/Drm.cpp
+++ b/drm/libmediadrm/Drm.cpp
@@ -21,6 +21,7 @@
 #include <dirent.h>
 #include <dlfcn.h>
 
+#include <media/DrmPluginPath.h>
 #include <media/DrmSessionClientInterface.h>
 #include <media/DrmSessionManager.h>
 #include <media/Drm.h>
@@ -220,7 +221,7 @@
     }
 
     // no luck, have to search
-    String8 dirPath("/vendor/lib/mediadrm");
+    String8 dirPath(getDrmPluginPath());
     DIR* pDir = opendir(dirPath.string());
 
     if (pDir == NULL) {
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 16035c0..ddbc83d 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -291,6 +291,9 @@
         case EventType::VENDOR_DEFINED:
             eventType = DrmPlugin::kDrmPluginEventVendorDefined;
             break;
+        case EventType::SESSION_RECLAIMED:
+            eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
+            break;
         default:
             return Void();
         }
diff --git a/drm/libmediadrm/DrmPluginPath.cpp b/drm/libmediadrm/DrmPluginPath.cpp
new file mode 100644
index 0000000..c760825
--- /dev/null
+++ b/drm/libmediadrm/DrmPluginPath.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "DrmPluginPath"
+#include <utils/Log.h>
+
+#include <cutils/properties.h>
+#include <media/DrmPluginPath.h>
+
+namespace android {
+
+const char* getDrmPluginPath() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("drm.64bit.enabled", value, NULL) == 0) {
+        return "/vendor/lib/mediadrm";
+    } else {
+        return "/vendor/lib64/mediadrm";
+    }
+}
+
+}  // namespace android
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 92c9548..8506d95 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -36,6 +36,8 @@
     DECRYPT,
     NOTIFY_RESOLUTION,
     SET_MEDIADRM_SESSION,
+    SET_HEAP,
+    UNSET_HEAP,
 };
 
 struct BpCrypto : public BpInterface<ICrypto> {
@@ -96,7 +98,7 @@
 
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const sp<IMemory> &source, size_t offset,
+            const SourceBuffer &source, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             const DestinationBuffer &destination, AString *errorDetailMsg) {
         Parcel data, reply;
@@ -125,7 +127,8 @@
         }
 
         data.writeInt32(totalSize);
-        data.writeStrongBinder(IInterface::asBinder(source));
+        data.writeStrongBinder(IInterface::asBinder(source.mSharedMemory));
+        data.writeInt32(source.mHeapSeqNum);
         data.writeInt32(offset);
 
         data.writeInt32(numSubSamples);
@@ -177,6 +180,30 @@
         return reply.readInt32();
     }
 
+    virtual int32_t setHeap(const sp<IMemoryHeap> &heap) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(heap));
+        status_t err = remote()->transact(SET_HEAP, data, &reply);
+        if (err != NO_ERROR) {
+            return -1;
+        }
+        int32_t seqNum;
+        if (reply.readInt32(&seqNum) != NO_ERROR) {
+            return -1;
+        }
+        return seqNum;
+    }
+
+    virtual void unsetHeap(int32_t seqNum) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        data.writeInt32(seqNum);
+        remote()->transact(UNSET_HEAP, data, &reply);
+        return;
+    }
+
+
 private:
     void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
         uint32_t size = reply.readInt32();
@@ -295,12 +322,17 @@
             data.read(iv, sizeof(iv));
 
             size_t totalSize = data.readInt32();
-            sp<IMemory> source =
+
+            SourceBuffer source;
+
+            source.mSharedMemory =
                 interface_cast<IMemory>(data.readStrongBinder());
-            if (source == NULL) {
+            if (source.mSharedMemory == NULL) {
                 reply->writeInt32(BAD_VALUE);
                 return OK;
             }
+            source.mHeapSeqNum = data.readInt32();
+
             int32_t offset = data.readInt32();
 
             int32_t numSubSamples = data.readInt32();
@@ -353,9 +385,9 @@
 
             if (overflow || sumSubsampleSizes != totalSize) {
                 result = -EINVAL;
-            } else if (totalSize > source->size()) {
+            } else if (totalSize > source.mSharedMemory->size()) {
                 result = -EINVAL;
-            } else if ((size_t)offset > source->size() - totalSize) {
+            } else if ((size_t)offset > source.mSharedMemory->size() - totalSize) {
                 result = -EINVAL;
             } else {
                 result = decrypt(key, iv, mode, pattern, source, offset,
@@ -404,6 +436,23 @@
             return OK;
         }
 
+        case SET_HEAP:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+            sp<IMemoryHeap> heap =
+                interface_cast<IMemoryHeap>(data.readStrongBinder());
+            reply->writeInt32(setHeap(heap));
+            return OK;
+        }
+
+        case UNSET_HEAP:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+            int32_t seqNum = data.readInt32();
+            unsetHeap(seqNum);
+            return OK;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index 8cc5ee9..5fdac5c 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -37,6 +37,9 @@
 
 status_t DrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
     sp<Session> session = mSessionLibrary->findSession(sessionId);
+    if (sessionId.size() == 0) {
+        return android::BAD_VALUE;
+    }
     if (session.get()) {
         mSessionLibrary->destroySession(session);
         return android::OK;
@@ -54,6 +57,9 @@
         String8& defaultUrl,
         DrmPlugin::KeyRequestType *keyRequestType) {
     UNUSED(optionalParameters);
+    if (scope.size() == 0) {
+        return android::BAD_VALUE;
+    }
     if (keyType != kKeyType_Streaming) {
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
@@ -70,6 +76,9 @@
         const Vector<uint8_t>& scope,
         const Vector<uint8_t>& response,
         Vector<uint8_t>& keySetId) {
+    if (scope.size() == 0 || response.size() == 0) {
+        return android::BAD_VALUE;
+    }
     sp<Session> session = mSessionLibrary->findSession(scope);
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index c4d934e..d5a47ca 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -99,9 +99,12 @@
             const Vector<uint8_t>& response,
             Vector<uint8_t>& certificate,
             Vector<uint8_t>& wrappedKey) {
-        UNUSED(response);
         UNUSED(certificate);
         UNUSED(wrappedKey);
+        if (response.size() == 0) {
+            // empty response
+            return android::BAD_VALUE;
+        }
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
@@ -111,13 +114,18 @@
     }
 
     virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
-        UNUSED(ssid);
+        if (ssid.size() == 0) {
+            return android::BAD_VALUE;
+        }
+
         UNUSED(secureStop);
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
     virtual status_t releaseSecureStops(const Vector<uint8_t>& ssRelease) {
-        UNUSED(ssRelease);
+        if (ssRelease.size() == 0) {
+            return android::BAD_VALUE;
+        }
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
@@ -151,15 +159,17 @@
 
     virtual status_t setCipherAlgorithm(
             const Vector<uint8_t>& sessionId, const String8& algorithm) {
-        UNUSED(sessionId);
-        UNUSED(algorithm);
+        if (sessionId.size() == 0 || algorithm.size() == 0) {
+            return android::BAD_VALUE;
+        }
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
     virtual status_t setMacAlgorithm(
             const Vector<uint8_t>& sessionId, const String8& algorithm) {
-        UNUSED(sessionId);
-        UNUSED(algorithm);
+        if (sessionId.size() == 0 || algorithm.size() == 0) {
+            return android::BAD_VALUE;
+        }
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
diff --git a/include/media/DrmPluginPath.h b/include/media/DrmPluginPath.h
new file mode 120000
index 0000000..06b12cf
--- /dev/null
+++ b/include/media/DrmPluginPath.h
@@ -0,0 +1 @@
+../../media/libmedia/include/DrmPluginPath.h
\ No newline at end of file
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 511fe94..80b6252 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -27,6 +27,7 @@
 #define NUM_SECONDS   10
 #define NANOS_PER_MICROSECOND ((int64_t)1000)
 #define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
+#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * 1000)
 
 static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
     const char *modeText = "unknown";
@@ -43,6 +44,15 @@
     return modeText;
 }
 
+static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+    struct timespec time;
+    int result = clock_gettime(clockId, &time);
+    if (result < 0) {
+        return -errno;
+    }
+    return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
+}
+
 int main(int argc, char **argv)
 {
     (void)argc; // unused
@@ -56,7 +66,8 @@
     const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
     aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_I16;
 
-    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
     aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
@@ -172,6 +183,26 @@
             goto finish;
         }
         framesLeft -= actual;
+
+        // Use timestamp to estimate latency.
+        {
+            int64_t presentationFrame;
+            int64_t presentationTime;
+            result = AAudioStream_getTimestamp(aaudioStream,
+                                               CLOCK_MONOTONIC,
+                                               &presentationFrame,
+                                               &presentationTime
+                                               );
+            if (result == AAUDIO_OK) {
+                int64_t elapsedNanos = getNanoseconds() - presentationTime;
+                int64_t elapsedFrames = actualSampleRate * elapsedNanos / NANOS_PER_SECOND;
+                int64_t currentFrame = presentationFrame + elapsedFrames;
+                int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream);
+                int64_t estimatedLatencyFrames = framesWritten - currentFrame;
+                int64_t estimatedLatencyMillis = estimatedLatencyFrames * 1000 / actualSampleRate;
+                printf("estimatedLatencyMillis %d\n", (int)estimatedLatencyMillis);
+            }
+        }
     }
 
     xRunCount = AAudioStream_getXRunCount(aaudioStream);
diff --git a/media/libaaudio/include/aaudio/AAudioDefinitions.h b/media/libaaudio/include/aaudio/AAudioDefinitions.h
index e5b7d7a..846318c 100644
--- a/media/libaaudio/include/aaudio/AAudioDefinitions.h
+++ b/media/libaaudio/include/aaudio/AAudioDefinitions.h
@@ -46,6 +46,12 @@
     AAUDIO_FORMAT_PCM_I8_24,
     AAUDIO_FORMAT_PCM_I32
 };
+typedef int32_t aaudio_format_t;
+
+/**
+ * @deprecated use aaudio_format_t instead
+ * TODO remove when tests and examples are updated
+ */
 typedef int32_t aaudio_audio_format_t;
 
 enum {
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index af0593d..6ac8554 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -50,7 +50,6 @@
     virtual aaudio_result_t requestFlush() = 0;
     virtual aaudio_result_t requestStop() = 0;
 
-    // TODO use aaudio_clockid_t all the way down to AudioClock
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) = 0;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index dd040a0..d380eb8 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -25,6 +25,7 @@
 
 #include "AudioClock.h"
 #include "AudioStreamRecord.h"
+#include "utility/AAudioUtilities.h"
 
 using namespace android;
 using namespace aaudio;
@@ -224,5 +225,28 @@
     return 192; // TODO add query to AudioRecord.cpp
 }
 
-// TODO implement getTimestamp
-
+aaudio_result_t AudioStreamRecord::getTimestamp(clockid_t clockId,
+                                               int64_t *framePosition,
+                                               int64_t *timeNanoseconds) {
+    ExtendedTimestamp extendedTimestamp;
+    status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
+    if (status != NO_ERROR) {
+        return AAudioConvert_androidToAAudioResult(status);
+    }
+    // TODO Merge common code into AudioStreamLegacy after rebasing.
+    int timebase;
+    switch(clockId) {
+        case CLOCK_BOOTTIME:
+            timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
+            break;
+        case CLOCK_MONOTONIC:
+            timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
+            break;
+        default:
+            ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
+            return AAUDIO_ERROR_UNEXPECTED_VALUE;
+            break;
+    }
+    status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase);
+    return AAudioConvert_androidToAAudioResult(status);
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index c8d389b..4667f05 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -44,10 +44,8 @@
     virtual aaudio_result_t requestStop() override;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
-                                       int64_t *framePosition,
-                                       int64_t *timeNanoseconds) override {
-        return AAUDIO_ERROR_UNIMPLEMENTED; // TODO
-    }
+                                         int64_t *framePosition,
+                                         int64_t *timeNanoseconds) override;
 
     virtual aaudio_result_t read(void *buffer,
                              int32_t numFrames,
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index e0a04c3..8bb6aee 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -20,11 +20,11 @@
 
 #include <stdint.h>
 #include <media/AudioTrack.h>
-
 #include <aaudio/AAudio.h>
-#include "AudioClock.h"
-#include "AudioStreamTrack.h"
 
+#include "utility/AudioClock.h"
+#include "AudioStreamTrack.h"
+#include "utility/AAudioUtilities.h"
 
 using namespace android;
 using namespace aaudio;
@@ -292,3 +292,29 @@
     }
     return AudioStream::getFramesRead();
 }
+
+aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId,
+                                     int64_t *framePosition,
+                                     int64_t *timeNanoseconds) {
+    ExtendedTimestamp extendedTimestamp;
+    status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
+    if (status != NO_ERROR) {
+        return AAudioConvert_androidToAAudioResult(status);
+    }
+    // TODO Merge common code into AudioStreamLegacy after rebasing.
+    int timebase;
+    switch(clockId) {
+        case CLOCK_BOOTTIME:
+            timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
+            break;
+        case CLOCK_MONOTONIC:
+            timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
+            break;
+        default:
+            ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
+            return AAUDIO_ERROR_UNEXPECTED_VALUE;
+            break;
+    }
+    status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase);
+    return AAudioConvert_androidToAAudioResult(status);
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 1de07ce..7a53022 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -47,9 +47,7 @@
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
                                        int64_t *framePosition,
-                                       int64_t *timeNanoseconds) override {
-        return AAUDIO_ERROR_UNIMPLEMENTED; // TODO call getTimestamp(ExtendedTimestamp *timestamp);
-    }
+                                       int64_t *timeNanoseconds) override;
 
     virtual aaudio_result_t write(const void *buffer,
                              int32_t numFrames,
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 9459b87..ee604eb 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -140,7 +140,7 @@
                                        {120001, 460000},
                                        {460001, 1800000},
                                        {1800001, 7000000},
-                                       {7000001, 1}};
+                                       {7000001, 20000000}};
 
 //Note: If these frequencies change, please update LimitLevel values accordingly.
 static const LVM_UINT16  EQNB_5BandPresetsFrequencies[] = {
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index 8b00d85..7c0d08d 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -23,11 +23,13 @@
 #include <sys/types.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractorService.h>
+#include <media/stagefright/MediaExtractor.h>
 
 namespace android {
 
 enum {
-    MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION
+    MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION,
+    MAKE_IDATA_SOURCE_FD,
 };
 
 class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
@@ -52,6 +54,21 @@
         return NULL;
     }
 
+    virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        status_t ret = remote()->transact(MAKE_IDATA_SOURCE_FD, data, &reply);
+        ALOGV("fd:%d offset:%lld length:%lld ret:%d",
+                fd, (long long)offset, (long long)length, ret);
+        if (ret == NO_ERROR) {
+            return interface_cast<IDataSource>(reply.readStrongBinder());
+        }
+        return nullptr;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
@@ -80,6 +97,23 @@
             reply->writeStrongBinder(IInterface::asBinder(ex));
             return NO_ERROR;
         }
+
+        case MAKE_IDATA_SOURCE_FD: {
+            CHECK_INTERFACE(IMediaExtractorService, data, reply);
+            const int fd = dup(data.readFileDescriptor()); // -1 fd checked in makeIDataSource
+            const int64_t offset = data.readInt64();
+            const int64_t length = data.readInt64();
+            ALOGV("fd %d  offset%lld  length:%lld", fd, (long long)offset, (long long)length);
+            sp<IDataSource> source = makeIDataSource(fd, offset, length);
+            reply->writeStrongBinder(IInterface::asBinder(source));
+            // The FileSource closes the descriptor, so if it is not created
+            // we need to close the descriptor explicitly.
+            if (source.get() == nullptr && fd != -1) {
+                close(fd);
+            }
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/include/Crypto.h b/media/libmedia/include/Crypto.h
index ce08f98..b68413d 100644
--- a/media/libmedia/include/Crypto.h
+++ b/media/libmedia/include/Crypto.h
@@ -55,6 +55,9 @@
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             const DestinationBuffer &destination, AString *errorDetailMsg);
 
+    virtual void setHeap(const sp<IMemoryHeap>&) {}
+    virtual void unsetHeap(const sp<IMemoryHeap>&) {}
+
 private:
     mutable Mutex mLock;
 
diff --git a/media/libmedia/include/CryptoHal.h b/media/libmedia/include/CryptoHal.h
index 28ade20..a5d8b43 100644
--- a/media/libmedia/include/CryptoHal.h
+++ b/media/libmedia/include/CryptoHal.h
@@ -55,11 +55,16 @@
 
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const sp<IMemory> &source, size_t offset,
+            const ICrypto::SourceBuffer &source, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             const ICrypto::DestinationBuffer &destination,
             AString *errorDetailMsg);
 
+    virtual int32_t setHeap(const sp<IMemoryHeap>& heap) {
+        return setHeapBase(heap);
+    }
+    virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
+
 private:
     mutable Mutex mLock;
 
@@ -74,16 +79,18 @@
      */
     status_t mInitCheck;
 
-    KeyedVector<void *, uint32_t> mHeapBases;
+    KeyedVector<int32_t, uint32_t> mHeapBases;
     uint32_t mNextBufferId;
+    int32_t mHeapSeqNum;
 
     Vector<sp<ICryptoFactory>> makeCryptoFactories();
     sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
             const uint8_t uuid[16], const void *initData, size_t size);
 
-    void setHeapBase(const sp<IMemoryHeap>& heap);
+    int32_t setHeapBase(const sp<IMemoryHeap>& heap);
+    void clearHeapBase(int32_t seqNum);
 
-    status_t toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer);
+    status_t toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
 };
diff --git a/media/libmedia/include/DrmPluginPath.h b/media/libmedia/include/DrmPluginPath.h
new file mode 100644
index 0000000..51ba26e
--- /dev/null
+++ b/media/libmedia/include/DrmPluginPath.h
@@ -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.
+ */
+
+#ifndef DRM_PLUGIN_PATH_H_
+
+#define DRM_PLUGIN_PATH_H_
+
+namespace android {
+
+const char* getDrmPluginPath();
+
+}  // namespace android
+
+#endif  // DRM_PLUGIN_PATH_H_
diff --git a/media/libmedia/include/ICrypto.h b/media/libmedia/include/ICrypto.h
index 8990f4b..6d896b8 100644
--- a/media/libmedia/include/ICrypto.h
+++ b/media/libmedia/include/ICrypto.h
@@ -27,6 +27,7 @@
 
 struct AString;
 class IMemory;
+class IMemoryHeap;
 
 struct ICrypto : public IInterface {
     DECLARE_META_INTERFACE(Crypto);
@@ -47,6 +48,11 @@
 
     virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
 
+    struct SourceBuffer {
+        sp<IMemory> mSharedMemory;
+        int32_t mHeapSeqNum;
+    };
+
     enum DestinationType {
         kDestinationTypeSharedMemory, // non-secure
         kDestinationTypeNativeHandle  // secure
@@ -60,10 +66,19 @@
 
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const sp<IMemory> &source, size_t offset,
+            const SourceBuffer &source, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             const DestinationBuffer &destination, AString *errorDetailMsg) = 0;
 
+    /**
+     * Declare the heap that the shared memory source buffers passed
+     * to decrypt will be allocated from. Returns a sequence number
+     * that subsequent decrypt calls can use to refer to the heap,
+     * with -1 indicating failure.
+     */
+    virtual int32_t setHeap(const sp<IMemoryHeap>& heap) = 0;
+    virtual void unsetHeap(int32_t seqNum) = 0;
+
 private:
     DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
 };
diff --git a/media/libmedia/include/IMediaExtractorService.h b/media/libmedia/include/IMediaExtractorService.h
index 4d7b317..45e9620 100644
--- a/media/libmedia/include/IMediaExtractorService.h
+++ b/media/libmedia/include/IMediaExtractorService.h
@@ -32,6 +32,7 @@
 
     virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
 
+    virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length) = 0;
 };
 
 class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index f3fc924..b082654 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -736,9 +736,7 @@
     mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
     binder->linkToDeath(mExtractorDeathListener);
 
-    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
-    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
-            property_get_bool("persist.hal.binderization", 0))) {
+    if (property_get_bool("persist.media.treble_omx", true)) {
         // Treble IOmx
         sp<IOmx> omx = IOmx::getService();
         if (omx == nullptr) {
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 638eec3..6400481 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -450,9 +450,7 @@
     }
     sCameraChecked = true;
 
-    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
-    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
-            property_get_bool("persist.hal.binderization", 0))) {
+    if (property_get_bool("persist.media.treble_omx", true)) {
         // Treble IOmx
         sp<IOmx> omx = IOmx::getService();
         if (omx == nullptr) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f689ac9..95f378f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -397,13 +397,13 @@
 
 // Attempt to parse an float literal optionally surrounded by whitespace,
 // returns true on success, false otherwise.
-static bool safe_strtof(const char *s, float *val) {
+static bool safe_strtod(const char *s, double *val) {
     char *end;
 
     // It is lame, but according to man page, we have to set errno to 0
-    // before calling strtof().
+    // before calling strtod().
     errno = 0;
-    *val = strtof(s, &end);
+    *val = strtod(s, &end);
 
     if (end == s || errno == ERANGE) {
         return false;
@@ -706,13 +706,23 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setParamCaptureFps(float fps) {
+status_t StagefrightRecorder::setParamCaptureFps(double fps) {
     ALOGV("setParamCaptureFps: %.2f", fps);
 
-    int64_t timeUs = (int64_t) (1000000.0 / fps + 0.5f);
+    constexpr int64_t k1E12 = 1000000000000ll;
+    int64_t fpsx1e12 = k1E12 * fps;
+    if (fpsx1e12 == 0) {
+        ALOGE("FPS is zero or too small");
+        return BAD_VALUE;
+    }
 
-    // Not allowing time more than a day
-    if (timeUs <= 0 || timeUs > 86400*1E6) {
+    // This does not overflow since 10^6 * 10^12 < 2^63
+    int64_t timeUs = 1000000ll * k1E12 / fpsx1e12;
+
+    // Not allowing time more than a day and a millisecond for error margin.
+    // Note: 1e12 / 86400 = 11574074.(074) and 1e18 / 11574074 = 86400000553;
+    //       therefore 1 ms of margin should be sufficient.
+    if (timeUs <= 0 || timeUs > 86400001000ll) {
         ALOGE("Time between frame capture (%lld) is out of range [0, 1 Day]", (long long)timeUs);
         return BAD_VALUE;
     }
@@ -846,8 +856,8 @@
             return setParamCaptureFpsEnable(captureFpsEnable);
         }
     } else if (key == "time-lapse-fps") {
-        float fps;
-        if (safe_strtof(value.string(), &fps)) {
+        double fps;
+        if (safe_strtod(value.string(), &fps)) {
             return setParamCaptureFps(fps);
         }
     } else {
@@ -2073,7 +2083,7 @@
     mMaxFileSizeBytes = 0;
     mTrackEveryTimeDurationUs = 0;
     mCaptureFpsEnable = false;
-    mCaptureFps = 0.0f;
+    mCaptureFps = 0.0;
     mTimeBetweenCaptureUs = -1;
     mCameraSourceTimeLapse = NULL;
     mMetaDataStoredInVideoBuffers = kMetadataBufferTypeInvalid;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 38377d2..9a6c4da 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -122,7 +122,7 @@
     int32_t mTotalBitRate;
 
     bool mCaptureFpsEnable;
-    float mCaptureFps;
+    double mCaptureFps;
     int64_t mTimeBetweenCaptureUs;
     sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
 
@@ -172,7 +172,7 @@
     status_t setParamAudioSamplingRate(int32_t sampleRate);
     status_t setParamAudioTimeScale(int32_t timeScale);
     status_t setParamCaptureFpsEnable(int32_t timeLapseEnable);
-    status_t setParamCaptureFps(float fps);
+    status_t setParamCaptureFps(double fps);
     status_t setParamVideoEncodingBitRate(int32_t bitRate);
     status_t setParamVideoIFramesInterval(int32_t seconds);
     status_t setParamVideoEncoderProfile(int32_t profile);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 8378d24..aedca3f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -21,7 +21,9 @@
 #include "NuPlayerDrm.h"
 
 #include "AnotherPacketSource.h"
-
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <media/IMediaExtractorService.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -361,7 +363,32 @@
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
         } else {
-            mDataSource = new FileSource(mFd, mOffset, mLength);
+            if (property_get_bool("media.stagefright.extractremote", true) &&
+                    !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
+                sp<IBinder> binder =
+                        defaultServiceManager()->getService(String16("media.extractor"));
+                if (binder != nullptr) {
+                    ALOGD("FileSource remote");
+                    sp<IMediaExtractorService> mediaExService(
+                            interface_cast<IMediaExtractorService>(binder));
+                    sp<IDataSource> source =
+                            mediaExService->makeIDataSource(mFd, mOffset, mLength);
+                    ALOGV("IDataSource(FileSource): %p %d %lld %lld",
+                            source.get(), mFd, (long long)mOffset, (long long)mLength);
+                    if (source.get() != nullptr) {
+                        mDataSource = DataSource::CreateFromIDataSource(source);
+                    } else {
+                        ALOGW("extractor service cannot make data source");
+                    }
+                } else {
+                    ALOGW("extractor service not running");
+                }
+            }
+            if (mDataSource == nullptr) {
+                ALOGD("FileSource local");
+                mDataSource = new FileSource(mFd, mOffset, mLength);
+            }
+
             mFd = -1;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 50d5343..510794c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1535,8 +1535,6 @@
     if (driver != NULL) {
         int64_t now = systemTime();
         int64_t played = now - mLastStartedPlayingTimeNs;
-        ALOGD("played from %" PRId64 " to %" PRId64 " = %" PRId64 ,
-              mLastStartedPlayingTimeNs, now, played);
 
         driver->notifyMorePlayingTimeUs((played+500)/1000);
     }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index cb668e4..9a4bc8c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -294,6 +294,9 @@
             return;
         }
 
+        if (streamErr != ERROR_END_OF_STREAM) {
+            handleError(streamErr);
+        }
         mReachedEOS = true;
         if (mRenderer != NULL) {
             mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 66b64f8..01008b4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -583,8 +583,12 @@
         return;
     }
 
-    // only bother to log non-empty records
-    if (mAnalyticsItem->count() > 0) {
+    // log only non-empty records
+    // we always updateMetrics() before we get here
+    // and that always injects 2 fields (duration and playing time) into
+    // the record.
+    // So the canonical "empty" record has 2 elements in it.
+    if (mAnalyticsItem->count() > 2) {
 
         mAnalyticsItem->setFinalized(true);
         mAnalyticsItem->selfrecord();
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index ecbbd03..40ac986 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -39,6 +39,12 @@
 using BufferInfo = ACodecBufferChannel::BufferInfo;
 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
 
+ACodecBufferChannel::~ACodecBufferChannel() {
+    if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
+        mCrypto->unsetHeap(mHeapSeqNum);
+    }
+}
+
 static BufferInfoIterator findClientBuffer(
         const std::shared_ptr<const std::vector<const BufferInfo>> &array,
         const sp<MediaCodecBuffer> &buffer) {
@@ -71,7 +77,8 @@
 ACodecBufferChannel::ACodecBufferChannel(
         const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
     : mInputBufferFilled(inputBufferFilled),
-      mOutputBufferDrained(outputBufferDrained) {
+      mOutputBufferDrained(outputBufferDrained),
+      mHeapSeqNum(-1) {
 }
 
 status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
@@ -122,11 +129,15 @@
         destination.mSharedMemory = mDecryptDestination;
     }
 
+    ICrypto::SourceBuffer source;
+    source.mSharedMemory = it->mSharedEncryptedBuffer;
+    source.mHeapSeqNum = mHeapSeqNum;
+
     ssize_t result = -1;
     if (mCrypto != NULL) {
         result = mCrypto->decrypt(key, iv, mode, pattern,
-                    it->mSharedEncryptedBuffer, it->mClientBuffer->offset(),
-                    subSamples, numSubSamples, destination, errorDetailMsg);
+                source, it->mClientBuffer->offset(),
+                subSamples, numSubSamples, destination, errorDetailMsg);
     } else {
         DescrambleInfo descrambleInfo;
         descrambleInfo.dstType = destination.mType ==
@@ -254,6 +265,25 @@
     }
 }
 
+sp<MemoryDealer> ACodecBufferChannel::makeMemoryDealer(size_t heapSize) {
+    sp<MemoryDealer> dealer;
+    if (mDealer != nullptr && mCrypto != nullptr && mHeapSeqNum >= 0) {
+        mCrypto->unsetHeap(mHeapSeqNum);
+    }
+    dealer = new MemoryDealer(heapSize, "ACodecBufferChannel");
+    if (mCrypto != nullptr) {
+        int32_t seqNum = mCrypto->setHeap(dealer->getMemoryHeap());
+        if (seqNum >= 0) {
+            mHeapSeqNum = seqNum;
+            ALOGD("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
+        } else {
+            mHeapSeqNum = -1;
+            ALOGD("setHeap failed, setting mHeapSeqNum=-1");
+        }
+    }
+    return dealer;
+}
+
 void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
     if (hasCryptoOrDescrambler()) {
         size_t totalSize = std::accumulate(
@@ -268,8 +298,10 @@
                 (size_t max, const BufferAndId& elem) {
                     return std::max(max, align(elem.mBuffer->capacity(), alignment));
                 });
-        mDealer = new MemoryDealer(totalSize + maxSize, "ACodecBufferChannel");
-        mDecryptDestination = mDealer->allocate(maxSize);
+        size_t destinationBufferSize = maxSize;
+        size_t heapSize = totalSize + destinationBufferSize;
+        mDealer = makeMemoryDealer(heapSize);
+        mDecryptDestination = mDealer->allocate(destinationBufferSize);
     }
     std::vector<const BufferInfo> inputBuffers;
     for (const BufferAndId &elem : array) {
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 0434bab..4309372 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -113,6 +113,10 @@
     return mIDataSource->DrmInitialization(mime);
 }
 
+sp<IDataSource> CallbackDataSource::getIDataSource() const {
+    return mIDataSource;
+}
+
 TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
     : mSource(source), mCachedOffset(0), mCachedSize(0) {
     mName = String8::format("TinyCacheSource(%s)", mSource->toString().string());
@@ -190,4 +194,9 @@
     mCachedSize = 0;
     return mSource->DrmInitialization(mime);
 }
+
+sp<IDataSource> TinyCacheSource::getIDataSource() const {
+    return mSource->getIDataSource();
+}
+
 } // namespace android
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 0fe44eb..a569f5d 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -58,6 +58,10 @@
 
     virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle);
 
+    virtual void postRecordingFrameHandleTimestampBatch(
+                const std::vector<nsecs_t>& timestamps,
+                const std::vector<native_handle_t*>& handles);
+
 protected:
     virtual ~CameraSourceListener();
 
@@ -110,6 +114,20 @@
     }
 }
 
+void CameraSourceListener::postRecordingFrameHandleTimestampBatch(
+        const std::vector<nsecs_t>& timestamps,
+        const std::vector<native_handle_t*>& handles) {
+    sp<CameraSource> source = mSource.promote();
+    if (source.get() != nullptr) {
+        int n = timestamps.size();
+        std::vector<nsecs_t> modifiedTimestamps(n);
+        for (int i = 0; i < n; i++) {
+            modifiedTimestamps[i] = timestamps[i] / 1000;
+        }
+        source->recordingFrameHandleCallbackTimestampBatch(modifiedTimestamps, handles);
+    }
+}
+
 static int32_t getColorFormat(const char* colorFormat) {
     if (!colorFormat) {
         ALOGE("Invalid color format");
@@ -952,10 +970,35 @@
         }
 
         if (handle != nullptr) {
-            // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
-            releaseRecordingFrameHandle(handle);
-            mMemoryBases.push_back(frame);
-            mMemoryBaseAvailableCond.signal();
+            uint32_t batchSize = 0;
+            {
+                Mutex::Autolock autoLock(mBatchLock);
+                if (mInflightBatchSizes.size() > 0) {
+                    batchSize = mInflightBatchSizes[0];
+                }
+            }
+            if (batchSize == 0) { // return buffers one by one
+                // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
+                releaseRecordingFrameHandle(handle);
+                mMemoryBases.push_back(frame);
+                mMemoryBaseAvailableCond.signal();
+            } else { // Group buffers in batch then return
+                Mutex::Autolock autoLock(mBatchLock);
+                mInflightReturnedHandles.push_back(handle);
+                mInflightReturnedMemorys.push_back(frame);
+                if (mInflightReturnedHandles.size() == batchSize) {
+                    releaseRecordingFrameHandleBatch(mInflightReturnedHandles);
+
+                    mInflightBatchSizes.pop_front();
+                    mInflightReturnedHandles.clear();
+                    for (const auto& mem : mInflightReturnedMemorys) {
+                        mMemoryBases.push_back(mem);
+                        mMemoryBaseAvailableCond.signal();
+                    }
+                    mInflightReturnedMemorys.clear();
+                }
+            }
+
         } else if (mCameraRecordingProxy != nullptr) {
             // mCamera is created by application. Return the frame back to camera via camera
             // recording proxy.
@@ -1126,6 +1169,21 @@
     }
 }
 
+void CameraSource::releaseRecordingFrameHandleBatch(const std::vector<native_handle_t*>& handles) {
+    if (mCameraRecordingProxy != nullptr) {
+        mCameraRecordingProxy->releaseRecordingFrameHandleBatch(handles);
+    } else if (mCamera != nullptr) {
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
+        mCamera->releaseRecordingFrameHandleBatch(handles);
+        IPCThreadState::self()->restoreCallingIdentity(token);
+    } else {
+        for (auto& handle : handles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+    }
+}
+
 void CameraSource::recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
                 native_handle_t* handle) {
     ALOGV("%s: timestamp %lld us", __FUNCTION__, (long long)timestampUs);
@@ -1163,6 +1221,62 @@
     mFrameAvailableCondition.signal();
 }
 
+void CameraSource::recordingFrameHandleCallbackTimestampBatch(
+        const std::vector<int64_t>& timestampsUs,
+        const std::vector<native_handle_t*>& handles) {
+    size_t n = timestampsUs.size();
+    if (n != handles.size()) {
+        ALOGE("%s: timestampsUs(%zu) and handles(%zu) size mismatch!",
+                __FUNCTION__, timestampsUs.size(), handles.size());
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    int batchSize = 0;
+    for (size_t i = 0; i < n; i++) {
+        int64_t timestampUs = timestampsUs[i];
+        native_handle_t* handle = handles[i];
+
+        ALOGV("%s: timestamp %lld us", __FUNCTION__, (long long)timestampUs);
+        if (handle == nullptr) continue;
+
+        if (shouldSkipFrameLocked(timestampUs)) {
+            releaseRecordingFrameHandle(handle);
+            continue;
+        }
+
+        while (mMemoryBases.empty()) {
+            if (mMemoryBaseAvailableCond.waitRelative(mLock, kMemoryBaseAvailableTimeoutNs) ==
+                    TIMED_OUT) {
+                ALOGW("Waiting on an available memory base timed out. Dropping a recording frame.");
+                releaseRecordingFrameHandle(handle);
+                continue;
+            }
+        }
+        ++batchSize;
+        ++mNumFramesReceived;
+        sp<IMemory> data = *mMemoryBases.begin();
+        mMemoryBases.erase(mMemoryBases.begin());
+
+        // Wrap native handle in sp<IMemory> so it can be pushed to mFramesReceived.
+        VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->pointer());
+        metadata->eType = kMetadataBufferTypeNativeHandleSource;
+        metadata->pHandle = handle;
+
+        mFramesReceived.push_back(data);
+        int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
+        mFrameTimes.push_back(timeUs);
+        ALOGV("initial delay: %" PRId64 ", current time stamp: %" PRId64, mStartTimeUs, timeUs);
+
+    }
+    if (batchSize > 0) {
+        Mutex::Autolock autoLock(mBatchLock);
+        mInflightBatchSizes.push_back(batchSize);
+    }
+    for (int i = 0; i < batchSize; i++) {
+        mFrameAvailableCondition.signal();
+    }
+}
+
 CameraSource::BufferQueueListener::BufferQueueListener(const sp<BufferItemConsumer>& consumer,
         const sp<CameraSource>& cameraSource) {
     mConsumer = consumer;
@@ -1279,6 +1393,17 @@
     mSource->recordingFrameHandleCallbackTimestamp(timestamp / 1000, handle);
 }
 
+void CameraSource::ProxyListener::recordingFrameHandleCallbackTimestampBatch(
+        const std::vector<int64_t>& timestampsUs,
+        const std::vector<native_handle_t*>& handles) {
+    int n = timestampsUs.size();
+    std::vector<nsecs_t> modifiedTimestamps(n);
+    for (int i = 0; i < n; i++) {
+        modifiedTimestamps[i] = timestampsUs[i] / 1000;
+    }
+    mSource->recordingFrameHandleCallbackTimestampBatch(modifiedTimestamps, handles);
+}
+
 void CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
     ALOGI("Camera recording proxy died");
 }
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 390c556..970526a 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -315,6 +315,17 @@
     CameraSource::recordingFrameHandleCallbackTimestamp(timestampUs, handle);
 }
 
+void CameraSourceTimeLapse::recordingFrameHandleCallbackTimestampBatch(
+        const std::vector<int64_t>& timestampsUs,
+        const std::vector<native_handle_t*>& handles) {
+    ALOGV("recordingFrameHandleCallbackTimestampBatch");
+    int n = timestampsUs.size();
+    for (int i = 0; i < n; i++) {
+        // Don't do batching for CameraSourceTimeLapse for now
+        recordingFrameHandleCallbackTimestamp(timestampsUs[i], handles[i]);
+    }
+}
+
 void CameraSourceTimeLapse::processBufferQueueFrame(BufferItem& buffer) {
     ALOGV("processBufferQueueFrame");
     int64_t timestampUs = buffer.mTimestamp / 1000;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index ded79f3..a5760d1 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -20,6 +20,7 @@
 #include "include/HTTPBase.h"
 #include "include/NuCachedSource2.h"
 
+#include <media/IDataSource.h>
 #include <media/IMediaHTTPConnection.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -29,6 +30,7 @@
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaHTTP.h>
+#include <media/stagefright/RemoteDataSource.h>
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
@@ -36,8 +38,6 @@
 
 #include <private/android_filesystem_config.h>
 
-#include <arpa/inet.h>
-
 namespace android {
 
 bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -98,6 +98,10 @@
     return ERROR_UNSUPPORTED;
 }
 
+sp<IDataSource> DataSource::getIDataSource() const {
+    return nullptr;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 // static
@@ -167,6 +171,11 @@
     return source;
 }
 
+sp<DataSource> DataSource::CreateFromFd(int fd, int64_t offset, int64_t length) {
+    sp<FileSource> source = new FileSource(fd, offset, length);
+    return source->initCheck() != OK ? nullptr : source;
+}
+
 sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
     if (httpService == NULL) {
         return NULL;
@@ -188,4 +197,8 @@
     return String8("application/octet-stream");
 }
 
+sp<IDataSource> DataSource::asIDataSource() {
+    return RemoteDataSource::wrap(sp<DataSource>(this));
+}
+
 }  // namespace android
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 5b92f91..97d8988 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -21,6 +21,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/Utils.h>
+#include <private/android_filesystem_config.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -171,6 +172,7 @@
 }
 
 sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
+    if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
@@ -227,4 +229,18 @@
         return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
     }
 }
+
+/* static */
+bool FileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
+    std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
+    sp<DecryptHandle> decryptHandle =
+            drmClient->openDecryptSession(fd, offset, length, mime);
+    bool requiresDrm = false;
+    if (decryptHandle != nullptr) {
+        requiresDrm = decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED;
+        drmClient->closeDecryptSession(decryptHandle);
+    }
+    return requiresDrm;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 82e7a26..22df522 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -538,7 +538,7 @@
             buffer->release();
             buffer = NULL;
 
-            return ERROR_END_OF_STREAM;
+            return (n < 0 ? n : ERROR_END_OF_STREAM);
         }
 
         uint32_t header = U32_AT((const uint8_t *)buffer->data());
@@ -582,7 +582,7 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_END_OF_STREAM;
+        return (n < 0 ? n : ERROR_END_OF_STREAM);
     }
 
     buffer->set_range(0, frame_size);
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 059a730..bb20850 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -940,6 +940,10 @@
             CHECK(msg->findInt32("err", &err));
             ALOGE("Encoder (%s) reported error : 0x%x",
                     mIsVideo ? "video" : "audio", err);
+            if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+                mStopping = true;
+                mPuller->stop();
+            }
             signalEOS();
        }
        break;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 76775c2..9965462 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -117,74 +117,6 @@
     return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
 }
 
-
-
-class RemoteDataSource : public BnDataSource {
-public:
-    enum {
-        kBufferSize = 64 * 1024,
-    };
-
-    static sp<IDataSource> wrap(const sp<DataSource> &source);
-    virtual ~RemoteDataSource();
-
-    virtual sp<IMemory> getIMemory();
-    virtual ssize_t readAt(off64_t offset, size_t size);
-    virtual status_t getSize(off64_t* size);
-    virtual void close();
-    virtual uint32_t getFlags();
-    virtual String8 toString();
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
-
-private:
-    sp<IMemory> mMemory;
-    sp<DataSource> mSource;
-    String8 mName;
-    explicit RemoteDataSource(const sp<DataSource> &source);
-    DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
-};
-
-
-sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
-    return new RemoteDataSource(source);
-}
-RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) {
-    mSource = source;
-    sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
-    mMemory = memoryDealer->allocate(kBufferSize);
-    if (mMemory == NULL) {
-        ALOGE("Failed to allocate memory!");
-    }
-    mName = String8::format("RemoteDataSource(%s)", mSource->toString().string());
-}
-RemoteDataSource::~RemoteDataSource() {
-    close();
-}
-sp<IMemory> RemoteDataSource::getIMemory() {
-    return mMemory;
-}
-ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) {
-    ALOGV("readAt(%" PRId64 ", %zu)", offset, size);
-    return mSource->readAt(offset, mMemory->pointer(), size);
-}
-status_t RemoteDataSource::getSize(off64_t* size) {
-    return mSource->getSize(size);
-}
-void RemoteDataSource::close() {
-    mSource = NULL;
-}
-uint32_t RemoteDataSource::getFlags() {
-    return mSource->flags();
-}
-
-String8 RemoteDataSource::toString() {
-    return mName;
-}
-
-sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) {
-    return mSource->DrmInitialization(mime);
-}
-
 // static
 sp<IMediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
@@ -201,7 +133,7 @@
 
         if (binder != 0) {
             sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
-            sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
+            sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime);
             return ex;
         } else {
             ALOGE("extractor service not running");
@@ -218,7 +150,7 @@
     RegisterDefaultSniffers();
 
     // initialize source decryption if needed
-    source->DrmInitialization();
+    source->DrmInitialization(nullptr /* mime */);
 
     sp<AMessage> meta;
 
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 1706221..02d275b 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -38,9 +38,7 @@
 }
 
 status_t OMXClient::connect(bool* trebleFlag) {
-    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
-    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
-            property_get_bool("persist.hal.binderization", 0))) {
+    if (property_get_bool("persist.media.treble_omx", true)) {
         if (trebleFlag != nullptr) {
             *trebleFlag = true;
         }
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 02468c1..0da2e81 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -60,7 +60,7 @@
 
     ACodecBufferChannel(
             const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
-    virtual ~ACodecBufferChannel() = default;
+    virtual ~ACodecBufferChannel();
 
     // BufferChannelBase interface
     virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
@@ -116,6 +116,7 @@
 
     sp<MemoryDealer> mDealer;
     sp<IMemory> mDecryptDestination;
+    int32_t mHeapSeqNum;
 
     // These should only be accessed via std::atomic_* functions.
     //
@@ -127,6 +128,8 @@
     std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
     std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
 
+    sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
+
     bool hasCryptoOrDescrambler() {
         return mCrypto != NULL || mDescrambler != NULL;
     }
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 80cd1f7..0d775e6 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -42,6 +42,7 @@
         return mName;
     }
     virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
+    virtual sp<IDataSource> getIDataSource() const;
 
 private:
     sp<IDataSource> mIDataSource;
@@ -70,6 +71,7 @@
         return mName;
     }
     virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
+    virtual sp<IDataSource> getIDataSource() const;
 
 private:
     // 2kb comes from experimenting with the time-to-first-frame from a MediaPlayer
diff --git a/media/libstagefright/include/CameraSource.h b/media/libstagefright/include/CameraSource.h
index c604f2d..aa56d27 100644
--- a/media/libstagefright/include/CameraSource.h
+++ b/media/libstagefright/include/CameraSource.h
@@ -18,6 +18,7 @@
 
 #define CAMERA_SOURCE_H_
 
+#include <deque>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaSource.h>
 #include <camera/android/hardware/ICamera.h>
@@ -141,6 +142,9 @@
                 const sp<IMemory> &data);
         virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
                 native_handle_t* handle);
+        virtual void recordingFrameHandleCallbackTimestampBatch(
+                const std::vector<int64_t>& timestampsUs,
+                const std::vector<native_handle_t*>& handles);
 
     private:
         sp<CameraSource> mSource;
@@ -213,6 +217,8 @@
     virtual status_t startCameraRecording();
     virtual void releaseRecordingFrame(const sp<IMemory>& frame);
     virtual void releaseRecordingFrameHandle(native_handle_t* handle);
+    // stagefright recorder not using this for now
+    virtual void releaseRecordingFrameHandleBatch(const std::vector<native_handle_t*>& handles);
 
     // Returns true if need to skip the current frame.
     // Called from dataCallbackTimestamp.
@@ -227,6 +233,10 @@
     virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
             native_handle_t* handle);
 
+    virtual void recordingFrameHandleCallbackTimestampBatch(
+            const std::vector<int64_t>& timestampsUs,
+            const std::vector<native_handle_t*>& handles);
+
     // Process a buffer item received in BufferQueueListener.
     virtual void processBufferQueueFrame(BufferItem& buffer);
 
@@ -271,6 +281,13 @@
     KeyedVector<ANativeWindowBuffer*, BufferItem> mReceivedBufferItemMap;
     sp<BufferQueueListener> mBufferQueueListener;
 
+    Mutex mBatchLock; // protecting access to mInflightXXXXX members below
+    // Start of members protected by mBatchLock
+    std::deque<uint32_t> mInflightBatchSizes;
+    std::vector<native_handle_t*> mInflightReturnedHandles;
+    std::vector<const sp<IMemory>> mInflightReturnedMemorys;
+    // End of members protected by mBatchLock
+
     void releaseQueuedFrames();
     void releaseOneRecordingFrame(const sp<IMemory>& frame);
     void createVideoBufferMemoryHeap(size_t size, uint32_t bufferCount);
diff --git a/media/libstagefright/include/CameraSourceTimeLapse.h b/media/libstagefright/include/CameraSourceTimeLapse.h
index 871c1d9..b066f9a 100644
--- a/media/libstagefright/include/CameraSourceTimeLapse.h
+++ b/media/libstagefright/include/CameraSourceTimeLapse.h
@@ -147,12 +147,23 @@
 
     // In the video camera case calls skipFrameAndModifyTimeStamp() to modify
     // timestamp and set mSkipCurrentFrame.
-    // Then it calls the base CameraSource::recordingFrameHandleCallbackTimestamp()
+    // Then it calls the base CameraSource::recordingFrameHandleCallbackTimestamp() or
+    // CameraSource::recordingFrameHandleCallbackTimestampBatch()
     // This will be called in VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA mode when
     // the metadata is VideoNativeHandleMetadata.
     virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
             native_handle_t* handle);
 
+    // In the video camera case calls skipFrameAndModifyTimeStamp() to modify
+    // timestamp and set mSkipCurrentFrame.
+    // Then it calls the base CameraSource::recordingFrameHandleCallbackTimestamp() or
+    // CameraSource::recordingFrameHandleCallbackTimestampBatch()
+    // This will be called in VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA mode when
+    // the metadata is VideoNativeHandleMetadata.
+    virtual void recordingFrameHandleCallbackTimestampBatch(
+            const std::vector<int64_t>& timestampsUs,
+            const std::vector<native_handle_t*>& handles);
+
     // Process a buffer item received in CameraSource::BufferQueueListener.
     // This will be called in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
     virtual void processBufferQueueFrame(BufferItem& buffer);
diff --git a/media/libstagefright/include/DataSource.h b/media/libstagefright/include/DataSource.h
index e7135a2..8f2c7eb 100644
--- a/media/libstagefright/include/DataSource.h
+++ b/media/libstagefright/include/DataSource.h
@@ -56,6 +56,7 @@
 
     static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
     static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
+    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
 
     DataSource() {}
 
@@ -117,6 +118,12 @@
 
     virtual void close() {};
 
+    // creates an IDataSource wrapper to the DataSource.
+    virtual sp<IDataSource> asIDataSource();
+
+    // returns a pointer to IDataSource if it is wrapped.
+    virtual sp<IDataSource> getIDataSource() const;
+
 protected:
     virtual ~DataSource() {}
 
diff --git a/media/libstagefright/include/FileSource.h b/media/libstagefright/include/FileSource.h
index 9f3bb5e..7267e9a 100644
--- a/media/libstagefright/include/FileSource.h
+++ b/media/libstagefright/include/FileSource.h
@@ -51,6 +51,8 @@
         return mName;
     }
 
+    static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
+
 protected:
     virtual ~FileSource();
 
diff --git a/media/libstagefright/include/RemoteDataSource.h b/media/libstagefright/include/RemoteDataSource.h
new file mode 100644
index 0000000..255b7ae
--- /dev/null
+++ b/media/libstagefright/include/RemoteDataSource.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef REMOTE_DATA_SOURCE_H_
+#define REMOTE_DATA_SOURCE_H_
+
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <media/IDataSource.h>
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+
+// Originally in MediaExtractor.cpp
+class RemoteDataSource : public BnDataSource {
+public:
+    static sp<IDataSource> wrap(const sp<DataSource> &source) {
+        if (source.get() == nullptr) {
+            return nullptr;
+        }
+        if (source->getIDataSource().get() != nullptr) {
+            return source->getIDataSource();
+        }
+        return new RemoteDataSource(source);
+    }
+
+    virtual ~RemoteDataSource() {
+        close();
+    }
+    virtual sp<IMemory> getIMemory() {
+        return mMemory;
+    }
+    virtual ssize_t readAt(off64_t offset, size_t size) {
+        ALOGV("readAt(%lld, %zu)", (long long)offset, size);
+        if (size > kBufferSize) {
+            size = kBufferSize;
+        }
+        return mSource->readAt(offset, mMemory->pointer(), size);
+    }
+    virtual status_t getSize(off64_t *size) {
+        return mSource->getSize(size);
+    }
+    virtual void close() {
+        mSource = nullptr;
+        mMemory = nullptr;
+    }
+    virtual uint32_t getFlags() {
+        return mSource->flags();
+    }
+    virtual String8 toString()  {
+        return mName;
+    }
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
+        return mSource->DrmInitialization(mime);
+    }
+
+private:
+    enum {
+        kBufferSize = 64 * 1024,
+    };
+
+    sp<IMemory> mMemory;
+    sp<DataSource> mSource;
+    String8 mName;
+
+    explicit RemoteDataSource(const sp<DataSource> &source) {
+        mSource = source;
+        sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
+        mMemory = memoryDealer->allocate(kBufferSize);
+        if (mMemory.get() == nullptr) {
+            ALOGE("Failed to allocate memory!");
+        }
+        mName = String8::format("RemoteDataSource(%s)", mSource->toString().string());
+    }
+
+    DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
+};
+
+}  // namespace android
+
+#endif  // REMOTE_DATA_SOURCE_H_
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index dae1ee9..afbde6a 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -384,6 +384,7 @@
     // to be handled and [pause, 1us], [resume 2us] will be discarded.
     bool dropped = false;
     bool done = false;
+    bool seeStopAction = false;
     if (!mActionQueue.empty()) {
         // First scan to check if bufferTimestamp is smaller than first action's timestamp.
         ActionItem nextAction = *(mActionQueue.begin());
@@ -431,7 +432,7 @@
                     dropped = true;
                     // Clear the whole ActionQueue as recording is done
                     mActionQueue.clear();
-                    submitEndOfInputStream_l();
+                    seeStopAction = true;
                     break;
                 }
                 default:
@@ -443,6 +444,14 @@
 
     if (dropped) {
         releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+        if (seeStopAction) {
+            // Clear all the buffers before setting mEndOfStream and signal EndOfInputStream.
+            if (!releaseAllBuffers()) {
+                ALOGW("Failed to release all the buffers when handling STOP action");
+            }
+            mEndOfStream = true;
+            submitEndOfInputStream_l();
+        }
         return true;
     }
 
@@ -922,18 +931,8 @@
         if (suspend) {
             mSuspended = true;
 
-            while (mNumFramesAvailable > 0) {
-                BufferItem item;
-                status_t err = acquireBuffer(&item);
-
-                if (err != OK) {
-                    ALOGE("setSuspend: acquireBuffer returned err=%d", err);
-                    break;
-                }
-
-                --mNumFramesAvailable;
-
-                releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+            if (!releaseAllBuffers()) {
+                ALOGW("Failed to release all the buffers during suspend");
             }
             return OK;
         } else {
@@ -954,6 +953,23 @@
     return OK;
 }
 
+bool GraphicBufferSource::releaseAllBuffers() {
+    while (mNumFramesAvailable > 0) {
+        BufferItem item;
+        status_t err = acquireBuffer(&item);
+
+        if (err != OK) {
+            ALOGE("releaseAllBuffers: acquireBuffer fail returned err=%d", err);
+            return false;;
+        }
+
+        --mNumFramesAvailable;
+
+        releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+    }
+    return true;
+}
+
 status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
     ALOGV("setRepeatPreviousFrameDelayUs: delayUs=%lld", (long long)repeatAfterUs);
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 371c5ed..ab52ce2 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -220,6 +220,8 @@
     // Acquire buffer from the consumer
     status_t acquireBuffer(BufferItem *bi);
 
+    bool releaseAllBuffers();
+
     // Release buffer to the consumer
     void releaseBuffer(int id, uint64_t frameNum, const sp<Fence> &fence);
 
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index c49403d..9fe6018 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -30,9 +30,12 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaDefs.h>
 
+#include <ui/Fence.h>
 #include <ui/GraphicBufferMapper.h>
 #include <ui/Rect.h>
 
+#include <hardware/gralloc.h>
+
 #include <OMX_IndexExt.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index cbca461..fcc44d8 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -78,9 +78,7 @@
 }
 
 status_t Harness::initOMX() {
-    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
-    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
-            property_get_bool("persist.hal.binderization", 0))) {
+    if (property_get_bool("persist.media.treble_omx", true)) {
         using namespace ::android::hardware::media::omx::V1_0;
         sp<IOmx> tOmx = IOmx::getService();
         if (tOmx == nullptr) {
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 0984ca4..2c070af 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -47,6 +47,9 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 
+LOCAL_STATIC_LIBRARIES := \
+    libgrallocusage \
+
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libmedia \
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index c0aee90..c449611 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -27,6 +27,7 @@
 #include <android_media_Utils.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <grallocusage/GrallocUsageConversion.h>
 
 using namespace android;
 
@@ -260,7 +261,8 @@
     uint64_t consumerUsage;
     android_hardware_HardwareBuffer_convertToGrallocUsageBits(
             &producerUsage, &consumerUsage, mUsage0, mUsage1);
-    mHalUsage = consumerUsage;
+    // Strip out producerUsage here.
+    mHalUsage = android_convertGralloc1To0Usage(0, consumerUsage);
 
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
@@ -411,11 +413,9 @@
         }
 
         // Check if the producer buffer configurations match what ImageReader configured.
-        if ((bufferFmt != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
-                (readerWidth != bufferWidth || readerHeight != bufferHeight)) {
-            ALOGW("%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
-                    __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
-        }
+        ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
+                "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
+                __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
 
         // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
         // ImageReader requested has been supported from the producer side.
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 0ff9314..4537ae6 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -944,7 +944,7 @@
     }
 
     // need to set __get_memory in set_callbacks().
-    device->setCallbacks(NULL, NULL, NULL, NULL);
+    device->setCallbacks(NULL, NULL, NULL, NULL, NULL);
 
     mParameters = device->getParameters();
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 3aec562..335e999 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1261,6 +1261,13 @@
     ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
 }
 
+void Camera2Client::releaseRecordingFrameHandleBatch(
+        const std::vector<native_handle_t*>& handles) {
+    (void)handles;
+    ATRACE_CALL();
+    ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
+}
+
 status_t Camera2Client::autoFocus() {
     ATRACE_CALL();
     Mutex::Autolock icl(mBinderSerializationLock);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 87c91a0..9738aca 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -72,6 +72,8 @@
     virtual bool            recordingEnabled();
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
     virtual void            releaseRecordingFrameHandle(native_handle_t *handle);
+    virtual void            releaseRecordingFrameHandleBatch(
+                                    const std::vector<native_handle_t*>& handles);
     virtual status_t        autoFocus();
     virtual status_t        cancelAutoFocus();
     virtual status_t        takePicture(int msgType);
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index ffb657e..df8726e 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -98,6 +98,7 @@
     mHardware->setCallbacks(notifyCallback,
             dataCallback,
             dataCallbackTimestamp,
+            handleCallbackTimestampBatch,
             (void *)(uintptr_t)mCameraId);
 
     // Enable zoom, error, focus, and metadata messages by default
@@ -533,6 +534,50 @@
     mHardware->releaseRecordingFrame(dataPtr);
 }
 
+void CameraClient::releaseRecordingFrameHandleBatch(const std::vector<native_handle_t*>& handles) {
+    size_t n = handles.size();
+    std::vector<sp<IMemory>> frames;
+    frames.reserve(n);
+    bool error = false;
+    for (auto& handle : handles) {
+        sp<IMemory> dataPtr;
+        {
+            Mutex::Autolock l(mAvailableCallbackBuffersLock);
+            if (!mAvailableCallbackBuffers.empty()) {
+                dataPtr = mAvailableCallbackBuffers.back();
+                mAvailableCallbackBuffers.pop_back();
+            }
+        }
+
+        if (dataPtr == nullptr) {
+            ALOGE("%s: %d: No callback buffer available. Dropping frames.", __FUNCTION__,
+                    __LINE__);
+            error = true;
+            break;
+        } else if (dataPtr->size() != sizeof(VideoNativeHandleMetadata)) {
+            ALOGE("%s: %d: Callback buffer must be VideoNativeHandleMetadata", __FUNCTION__,
+                    __LINE__);
+            error = true;
+            break;
+        }
+
+        VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+        metadata->eType = kMetadataBufferTypeNativeHandleSource;
+        metadata->pHandle = handle;
+        frames.push_back(dataPtr);
+    }
+
+    if (error) {
+        for (auto& handle : handles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+    } else {
+        mHardware->releaseRecordingFrameBatch(frames);
+    }
+    return;
+}
+
 status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
     LOG1("setVideoBufferMode: %d", videoBufferMode);
     bool enableMetadataInBuffers = false;
@@ -855,6 +900,49 @@
     client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
 }
 
+void CameraClient::handleCallbackTimestampBatch(
+        int32_t msgType, const std::vector<HandleTimestampMessage>& msgs, void* user) {
+    LOG2("dataCallbackTimestampBatch");
+    sp<CameraClient> client = getClientFromCookie(user);
+    if (client.get() == nullptr) return;
+    if (!client->lockIfMessageWanted(msgType)) return;
+
+    sp<hardware::ICameraClient> c = client->mRemoteCallback;
+    client->mLock.unlock();
+    if (c != 0 && msgs.size() > 0) {
+        size_t n = msgs.size();
+        std::vector<nsecs_t> timestamps;
+        std::vector<native_handle_t*> handles;
+        timestamps.reserve(n);
+        handles.reserve(n);
+        for (auto& msg : msgs) {
+            native_handle_t* handle = nullptr;
+            if (msg.dataPtr->size() != sizeof(VideoNativeHandleMetadata)) {
+                ALOGE("%s: dataPtr does not contain VideoNativeHandleMetadata!", __FUNCTION__);
+                return;
+            }
+            VideoNativeHandleMetadata *metadata =
+                (VideoNativeHandleMetadata*)(msg.dataPtr->pointer());
+            if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
+                handle = metadata->pHandle;
+            }
+
+            if (handle == nullptr) {
+                ALOGE("%s: VideoNativeHandleMetadata type mismatch or null handle passed!",
+                        __FUNCTION__);
+                return;
+            }
+            {
+                Mutex::Autolock l(client->mAvailableCallbackBuffersLock);
+                client->mAvailableCallbackBuffers.push_back(msg.dataPtr);
+            }
+            timestamps.push_back(msg.timestamp);
+            handles.push_back(handle);
+        }
+        c->recordingFrameHandleCallbackTimestampBatch(timestamps, handles);
+    }
+}
+
 // snapshot taken callback
 void CameraClient::handleShutter(void) {
     if (mPlayShutterSound) {
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 91f00e3..1073384 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -50,6 +50,8 @@
     virtual bool            recordingEnabled();
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
     virtual void            releaseRecordingFrameHandle(native_handle_t *handle);
+    virtual void            releaseRecordingFrameHandleBatch(
+                                    const std::vector<native_handle_t*>& handles);
     virtual status_t        autoFocus();
     virtual status_t        cancelAutoFocus();
     virtual status_t        takePicture(int msgType);
@@ -109,6 +111,8 @@
     static void             dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
             camera_frame_metadata_t *metadata, void* user);
     static void             dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+    static void             handleCallbackTimestampBatch(
+                                    int32_t msgType, const std::vector<HandleTimestampMessage>&, void* user);
     // handlers for messages
     void                    handleShutter(void);
     void                    handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index a9211e8..0b57c50 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -195,6 +195,36 @@
     return hardware::Void();
 }
 
+hardware::Return<void> CameraHardwareInterface::handleCallbackTimestampBatch(
+        DataCallbackMsg msgType,
+        const hardware::hidl_vec<hardware::camera::device::V1_0::HandleTimestampMessage>& messages) {
+    std::vector<android::HandleTimestampMessage> msgs;
+    msgs.reserve(messages.size());
+
+    for (const auto& hidl_msg : messages) {
+        if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
+            return hardware::Void();
+        }
+        sp<CameraHeapMemory> mem(
+                static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
+
+        if (hidl_msg.bufferIndex >= mem->mNumBufs) {
+            ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+                 hidl_msg.bufferIndex, mem->mNumBufs);
+            return hardware::Void();
+        }
+        VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
+                mem->mBuffers[hidl_msg.bufferIndex]->pointer();
+        md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
+
+        msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
+    }
+
+    mDataCbTimestampBatch((int32_t) msgType, msgs, mCbUser);
+    return hardware::Void();
+}
+
 std::pair<bool, uint64_t> CameraHardwareInterface::getBufferId(
         ANativeWindowBuffer* anb) {
     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
@@ -470,11 +500,13 @@
 void CameraHardwareInterface::setCallbacks(notify_callback notify_cb,
         data_callback data_cb,
         data_callback_timestamp data_cb_timestamp,
+        data_callback_timestamp_batch data_cb_timestamp_batch,
         void* user)
 {
     mNotifyCb = notify_cb;
     mDataCb = data_cb;
     mDataCbTimestamp = data_cb_timestamp;
+    mDataCbTimestampBatch = data_cb_timestamp_batch;
     mCbUser = user;
 
     ALOGV("%s(%s)", __FUNCTION__, mName.string());
@@ -630,6 +662,44 @@
     }
 }
 
+void CameraHardwareInterface::releaseRecordingFrameBatch(const std::vector<sp<IMemory>>& frames)
+{
+    ALOGV("%s(%s)", __FUNCTION__, mName.string());
+    size_t n = frames.size();
+    std::vector<VideoFrameMessage> msgs;
+    msgs.reserve(n);
+    for (auto& mem : frames) {
+        if (CC_LIKELY(mHidlDevice != nullptr)) {
+            ssize_t offset;
+            size_t size;
+            sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+            if (size == sizeof(VideoNativeHandleMetadata)) {
+                uint32_t heapId = heap->getHeapID();
+                uint32_t bufferIndex = offset / size;
+                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;
+                VideoFrameMessage msg;
+                msgs.push_back({nh, heapId, bufferIndex});
+            } else {
+                ALOGE("%s only supports VideoNativeHandleMetadata mode", __FUNCTION__);
+                return;
+            }
+        } else {
+            ALOGE("Non HIDL mode do not support %s", __FUNCTION__);
+            return;
+        }
+    }
+
+    mHidlDevice->releaseRecordingFrameHandleBatch(msgs);
+
+    for (auto& msg : msgs) {
+        native_handle_t* nh = const_cast<native_handle_t*>(msg.frameData.getNativeHandle());
+        native_handle_close(nh);
+        native_handle_delete(nh);
+    }
+}
+
 status_t CameraHardwareInterface::autoFocus()
 {
     ALOGV("%s(%s)", __FUNCTION__, mName.string());
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 9816c48..caeacef 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -48,6 +48,15 @@
                             const sp<IMemory> &dataPtr,
                             void *user);
 
+struct HandleTimestampMessage {
+    nsecs_t timestamp;
+    const sp<IMemory> dataPtr;
+};
+
+typedef void (*data_callback_timestamp_batch)(
+        int32_t msgType,
+        const std::vector<HandleTimestampMessage>&, void* user);
+
 /**
  * CameraHardwareInterface.h defines the interface to the
  * camera hardware abstraction layer, used for setting and getting
@@ -112,6 +121,7 @@
     void setCallbacks(notify_callback notify_cb,
                       data_callback data_cb,
                       data_callback_timestamp data_cb_timestamp,
+                      data_callback_timestamp_batch data_cb_timestamp_batch,
                       void* user);
 
     /**
@@ -227,6 +237,20 @@
     void releaseRecordingFrame(const sp<IMemory>& mem);
 
     /**
+     * Release a batch of recording frames previously returned by
+     * CAMERA_MSG_VIDEO_FRAME. This method only supports frames that are
+     * stored as VideoNativeHandleMetadata.
+     *
+     * It is camera hal client's responsibility to release video recording
+     * frames sent out by the camera hal before the camera hal receives
+     * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
+     * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
+     * responsibility of managing the life-cycle of the video recording
+     * frames.
+     */
+    void releaseRecordingFrameBatch(const std::vector<sp<IMemory>>& frames);
+
+    /**
      * 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.
@@ -416,6 +440,10 @@
             hardware::camera::device::V1_0::DataCallbackMsg msgType,
             const hardware::hidl_handle& frameData, uint32_t data,
             uint32_t bufferIndex, int64_t timestamp) override;
+    hardware::Return<void> handleCallbackTimestampBatch(
+            hardware::camera::device::V1_0::DataCallbackMsg msgType,
+            const hardware::hidl_vec<
+                    hardware::camera::device::V1_0::HandleTimestampMessage>&) override;
 
     /**
      * Implementation of android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback
@@ -450,9 +478,10 @@
 
     struct camera_preview_window mHalPreviewWindow;
 
-    notify_callback         mNotifyCb;
-    data_callback           mDataCb;
-    data_callback_timestamp mDataCbTimestamp;
+    notify_callback               mNotifyCb;
+    data_callback                 mDataCb;
+    data_callback_timestamp       mDataCbTimestamp;
+    data_callback_timestamp_batch mDataCbTimestampBatch;
     void *mCbUser;
 
     // Cached values for preview stream parameters
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 38717b5..3a4546b 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -54,9 +54,7 @@
     ::android::hardware::configureRpcThreadpool(64, false);
     sp<ProcessState> proc(ProcessState::self());
 
-    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
-    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
-            property_get_bool("persist.hal.binderization", 0))) {
+    if (property_get_bool("persist.media.treble_omx", true)) {
         using namespace ::android::hardware::media::omx::V1_0;
         sp<IOmx> omx = new implementation::Omx();
         if (omx == nullptr) {
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 87fddd4..1d5fa07 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -40,7 +40,13 @@
 endif
 
 LOCAL_MODULE:= mediadrmserver
+
+# TODO: Some legacy DRM plugins only support 32-bit. They need to be migrated to
+# 64-bit. (b/18948909) Once all of a device's legacy DRM plugins support 64-bit,
+# that device can turn on ENABLE_MEDIADRM_64 to build this service as 64-bit.
+ifneq ($(ENABLE_MEDIADRM_64), true)
 LOCAL_32_BIT_ONLY := true
+endif
 
 LOCAL_INIT_RC := mediadrmserver.rc
 
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 4a80166..08cbef6 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -22,6 +22,7 @@
 
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/RemoteDataSource.h>
 #include "MediaExtractorService.h"
 
 namespace android {
@@ -45,6 +46,12 @@
     return ret;
 }
 
+sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
+{
+    sp<DataSource> source = DataSource::CreateFromFd(fd, offset, length);
+    return source.get() != nullptr ? source->asIDataSource() : nullptr;
+}
+
 status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
     return dumpExtractors(fd, args);
 }
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index 078af0c..9df3ecd 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -34,6 +34,9 @@
     static const char*  getServiceName() { return "media.extractor"; }
 
     virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime);
+
+    virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length);
+
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
     virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 96840a0..4e4ce30 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -37,6 +37,11 @@
 getgid32: 1
 getegid32: 1
 getgroups32: 1
+nanosleep: 1
+
+# for FileSource
+readlinkat: 1
+_llseek: 1
 
 # for attaching to debuggerd on process crash
 sigaction: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index c95ddb7..1683adb 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -26,6 +26,11 @@
 exit_group: 1
 rt_sigreturn: 1
 getrlimit: 1
+nanosleep: 1
+
+# for FileSource
+readlinkat: 1
+_llseek: 1
 
 # for attaching to debuggerd on process crash
 tgkill: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 2ce6cf8..83725cd 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -37,6 +37,10 @@
 getgroups32: 1
 nanosleep: 1
 
+# for FileSource
+readlinkat: 1
+_llseek: 1
+
 # for attaching to debuggerd on process crash
 socketcall: 1
 sigaction: 1