Camera: Fix passing video native handle for 64-bit app

Add new binder calls to pass video native handle so the video native
handle can be passed between 32-bit and 64-bit processes.

Remove problematic code that used IMemory to pass video native
handle because the sizes of VideoNativeMetadata are different in
32-bit and 64-bit processes.

Bug: 28403412
Change-Id: I3341b1812ecc41d61846bb72ca926ecb1674c9ec
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index c52e581..bf9904c 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -232,6 +232,14 @@
     c->releaseRecordingFrame(mem);
 }
 
+void Camera::releaseRecordingFrameHandle(native_handle_t* handle)
+{
+    ALOGV("releaseRecordingFrameHandle");
+    sp <::android::hardware::ICamera> c = mCamera;
+    if (c == 0) return;
+    c->releaseRecordingFrameHandle(handle);
+}
+
 // get preview state
 bool Camera::previewEnabled()
 {
@@ -381,6 +389,35 @@
     }
 }
 
+void Camera::recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle)
+{
+    // 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->recordingFrameHandleCallbackTimestamp(timestamp, handle);
+        return;
+    }
+
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+
+    if (listener != NULL) {
+        listener->postRecordingFrameHandleTimestamp(timestamp, handle);
+    } else {
+        ALOGW("No listener was set. Drop a recording frame.");
+        releaseRecordingFrameHandle(handle);
+    }
+}
+
 sp<ICameraRecordingProxy> Camera::getRecordingProxy() {
     ALOGV("getProxy");
     return new RecordingProxy(this);
@@ -406,6 +443,11 @@
     mCamera->releaseRecordingFrame(mem);
 }
 
+void Camera::RecordingProxy::releaseRecordingFrameHandle(native_handle_t* handle) {
+    ALOGV("RecordingProxy::releaseRecordingFrameHandle");
+    mCamera->releaseRecordingFrameHandle(handle);
+}
+
 Camera::RecordingProxy::RecordingProxy(const sp<Camera>& camera)
 {
     mCamera = camera;
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
index 26eebe3..1676be1 100644
--- a/camera/CameraUtils.cpp
+++ b/camera/CameraUtils.cpp
@@ -122,19 +122,4 @@
     return OK;
 }
 
-// Return whether the image data contains a native handle.
-bool CameraUtils::isNativeHandleMetadata(const sp<IMemory>& imageData) {
-    if (imageData == nullptr) {
-        return false;
-    }
-
-    if (imageData->size() == sizeof(VideoNativeHandleMetadata)) {
-        VideoNativeHandleMetadata *metadata =
-                (VideoNativeHandleMetadata*)(imageData->pointer());
-        return metadata->eType == kMetadataBufferTypeNativeHandleSource;
-    }
-
-    return false;
-}
-
 } /* namespace android */
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 37b0a10..0680d7c 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -54,6 +54,7 @@
     RELEASE_RECORDING_FRAME,
     SET_VIDEO_BUFFER_MODE,
     SET_VIDEO_BUFFER_TARGET,
+    RELEASE_RECORDING_FRAME_HANDLE,
 };
 
 class BpCamera: public BpInterface<ICamera>
@@ -155,21 +156,20 @@
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         data.writeStrongBinder(IInterface::asBinder(mem));
 
-        native_handle_t *nh = nullptr;
-        if (CameraUtils::isNativeHandleMetadata(mem)) {
-            VideoNativeHandleMetadata *metadata =
-                        (VideoNativeHandleMetadata*)(mem->pointer());
-            nh = metadata->pHandle;
-            data.writeNativeHandle(nh);
-        }
-
         remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+    }
 
-        if (nh) {
-            // Close the native handle because camera received a dup copy.
-            native_handle_close(nh);
-            native_handle_delete(nh);
-        }
+    void releaseRecordingFrameHandle(native_handle_t *handle) {
+        ALOGV("releaseRecordingFrameHandle");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeNativeHandle(handle);
+
+        remote()->transact(RELEASE_RECORDING_FRAME_HANDLE, data, &reply);
+
+        // Close the native handle because camera received a dup copy.
+        native_handle_close(handle);
+        native_handle_delete(handle);
     }
 
     status_t setVideoBufferMode(int32_t videoBufferMode)
@@ -368,17 +368,16 @@
             ALOGV("RELEASE_RECORDING_FRAME");
             CHECK_INTERFACE(ICamera, data, reply);
             sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
-
-            if (CameraUtils::isNativeHandleMetadata(mem)) {
-                VideoNativeHandleMetadata *metadata =
-                        (VideoNativeHandleMetadata*)(mem->pointer());
-                metadata->pHandle = data.readNativeHandle();
-                // releaseRecordingFrame will be responsble to close the native handle.
-            }
-
             releaseRecordingFrame(mem);
             return NO_ERROR;
         } break;
+        case RELEASE_RECORDING_FRAME_HANDLE: {
+            ALOGV("RELEASE_RECORDING_FRAME_HANDLE");
+            CHECK_INTERFACE(ICamera, data, reply);
+            // releaseRecordingFrameHandle will be responsble to close the native handle.
+            releaseRecordingFrameHandle(data.readNativeHandle());
+            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 d058138..68cbfb8 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -31,6 +31,7 @@
     NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
     DATA_CALLBACK,
     DATA_CALLBACK_TIMESTAMP,
+    RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP,
 };
 
 class BpCameraClient: public BpInterface<ICameraClient>
@@ -78,15 +79,18 @@
         data.writeInt64(timestamp);
         data.writeInt32(msgType);
         data.writeStrongBinder(IInterface::asBinder(imageData));
-        // If imageData is metadata and it contains a native handle, write the native handle to
-        // parcel.
-        if (CameraUtils::isNativeHandleMetadata(imageData)) {
-            VideoNativeHandleMetadata *metadata =
-                    (VideoNativeHandleMetadata*)(imageData->pointer());
-            data.writeNativeHandle(metadata->pHandle);
-        }
         remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle) {
+        ALOGV("recordingFrameHandleCallbackTimestamp");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeInt64(timestamp);
+        data.writeNativeHandle(handle);
+        remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
@@ -128,20 +132,26 @@
             nsecs_t timestamp = data.readInt64();
             int32_t msgType = data.readInt32();
             sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
-
-            // If the image data contains a native handle, read the native handle from the parcel
-            // and replace the native handle in the image data. (The native handle in image data is
-            // not serielized/deserialized so it's not valid in the process.)
-            if (CameraUtils::isNativeHandleMetadata(imageData)) {
-                VideoNativeHandleMetadata *metadata =
-                        (VideoNativeHandleMetadata*)(imageData->pointer());
-                metadata->pHandle = data.readNativeHandle();
-
-                // The native handle will be freed in
-                // BpCameraRecordingProxyListener::releaseRecordingFrame.
+            dataCallbackTimestamp(timestamp, msgType, imageData);
+            return NO_ERROR;
+        } break;
+        case RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP: {
+            ALOGV("RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            nsecs_t timestamp;
+            status_t res = data.readInt64(&timestamp);
+            if (res != OK) {
+                ALOGE("%s: Failed to read timestamp: %s (%d)", __FUNCTION__, strerror(-res), res);
+                return BAD_VALUE;
+            }
+            native_handle_t* handle = data.readNativeHandle();
+            if (handle == nullptr) {
+                ALOGE("%s: Received a null native handle", __FUNCTION__);
+                return BAD_VALUE;
             }
 
-            dataCallbackTimestamp(timestamp, msgType, imageData);
+            // The native handle will be freed in BpCamera::releaseRecordingFrameHandle.
+            recordingFrameHandleCallbackTimestamp(timestamp, handle);
             return NO_ERROR;
         } break;
         default:
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
index d128f5b..63c4b1d 100644
--- a/camera/ICameraRecordingProxy.cpp
+++ b/camera/ICameraRecordingProxy.cpp
@@ -31,6 +31,7 @@
     START_RECORDING = IBinder::FIRST_CALL_TRANSACTION,
     STOP_RECORDING,
     RELEASE_RECORDING_FRAME,
+    RELEASE_RECORDING_FRAME_HANDLE,
 };
 
 
@@ -66,22 +67,20 @@
         Parcel data, reply;
         data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
         data.writeStrongBinder(IInterface::asBinder(mem));
-
-        native_handle_t *nh = nullptr;
-        if (CameraUtils::isNativeHandleMetadata(mem)) {
-            VideoNativeHandleMetadata *metadata =
-                        (VideoNativeHandleMetadata*)(mem->pointer());
-            nh = metadata->pHandle;
-            data.writeNativeHandle(nh);
-        }
-
         remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+    }
 
-        if (nh) {
-            // Close the native handle because camera received a dup copy.
-            native_handle_close(nh);
-            native_handle_delete(nh);
-        }
+    void releaseRecordingFrameHandle(native_handle_t *handle) {
+        ALOGV("releaseRecordingFrameHandle");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
+        data.writeNativeHandle(handle);
+
+        remote()->transact(RELEASE_RECORDING_FRAME_HANDLE, data, &reply);
+
+        // Close the native handle because camera received a dup copy.
+        native_handle_close(handle);
+        native_handle_delete(handle);
     }
 };
 
@@ -111,19 +110,17 @@
             ALOGV("RELEASE_RECORDING_FRAME");
             CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
             sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
-
-            if (CameraUtils::isNativeHandleMetadata(mem)) {
-                VideoNativeHandleMetadata *metadata =
-                        (VideoNativeHandleMetadata*)(mem->pointer());
-                metadata->pHandle = data.readNativeHandle();
-
-                // releaseRecordingFrame will be responsble to close the native handle.
-            }
             releaseRecordingFrame(mem);
-
             return NO_ERROR;
         } break;
+        case RELEASE_RECORDING_FRAME_HANDLE: {
+            ALOGV("RELEASE_RECORDING_FRAME_HANDLE");
+            CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
 
+            // releaseRecordingFrameHandle will be responsble to close the native handle.
+            releaseRecordingFrameHandle(data.readNativeHandle());
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index 447174e..fa4dfd8 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -27,6 +27,7 @@
 
 enum {
     DATA_CALLBACK_TIMESTAMP = IBinder::FIRST_CALL_TRANSACTION,
+    RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP,
 };
 
 class BpCameraRecordingProxyListener: public BpInterface<ICameraRecordingProxyListener>
@@ -45,22 +46,21 @@
         data.writeInt64(timestamp);
         data.writeInt32(msgType);
         data.writeStrongBinder(IInterface::asBinder(imageData));
-        native_handle_t* nh = nullptr;
-
-        if (CameraUtils::isNativeHandleMetadata(imageData)) {
-            VideoNativeHandleMetadata *metadata =
-                    (VideoNativeHandleMetadata*)(imageData->pointer());
-            nh = metadata->pHandle;
-            data.writeNativeHandle(nh);
-        }
-
         remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp, native_handle_t* handle) {
+        ALOGV("recordingFrameHandleCallbackTimestamp");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraRecordingProxyListener::getInterfaceDescriptor());
+        data.writeInt64(timestamp);
+        data.writeNativeHandle(handle);
+        remote()->transact(RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP, data, &reply,
+                IBinder::FLAG_ONEWAY);
 
         // The native handle is dupped in ICameraClient so we need to free it here.
-        if (nh) {
-            native_handle_close(nh);
-            native_handle_delete(nh);
-        }
+        native_handle_close(handle);
+        native_handle_delete(handle);
     }
 };
 
@@ -78,16 +78,27 @@
             nsecs_t timestamp = data.readInt64();
             int32_t msgType = data.readInt32();
             sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
-
-            if (CameraUtils::isNativeHandleMetadata(imageData)) {
-                VideoNativeHandleMetadata *meta = (VideoNativeHandleMetadata*)(imageData->pointer());
-                meta->pHandle = data.readNativeHandle();
-
-                // The native handle will be freed in
-                // BpCameraRecordingProxyListener::releaseRecordingFrame.
+            dataCallbackTimestamp(timestamp, msgType, imageData);
+            return NO_ERROR;
+        } break;
+        case RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP: {
+            ALOGV("RECORDING_FRAME_HANDLE_CALLBACK_TIMESTAMP");
+            CHECK_INTERFACE(ICameraRecordingProxyListener, data, reply);
+            nsecs_t timestamp;
+            status_t res = data.readInt64(&timestamp);
+            if (res != OK) {
+                ALOGE("%s: Failed to read timestamp: %s (%d)", __FUNCTION__, strerror(-res), res);
+                return BAD_VALUE;
             }
 
-            dataCallbackTimestamp(timestamp, msgType, imageData);
+            native_handle_t* handle = data.readNativeHandle();
+            if (handle == nullptr) {
+                ALOGE("%s: Received a null native handle", __FUNCTION__);
+                return BAD_VALUE;
+            }
+            // The native handle will be freed in
+            // BpCameraRecordingProxy::releaseRecordingFrameHandle.
+            recordingFrameHandleCallbackTimestamp(timestamp, handle);
             return NO_ERROR;
         } break;
         default:
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index b45bbfc..be793a2 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -43,6 +43,7 @@
     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
                           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;
 };
 
 class Camera;
@@ -114,6 +115,9 @@
             // release a recording frame
             void        releaseRecordingFrame(const sp<IMemory>& mem);
 
+            // release a recording frame handle
+            void        releaseRecordingFrameHandle(native_handle_t *handle);
+
             // autoFocus - status returned from callback
             status_t    autoFocus();
 
@@ -161,6 +165,7 @@
     virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
                                      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);
 
     class RecordingProxy : public BnCameraRecordingProxy
     {
@@ -171,6 +176,7 @@
         virtual status_t startRecording(const sp<ICameraRecordingProxyListener>& listener);
         virtual void stopRecording();
         virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+        virtual void releaseRecordingFrameHandle(native_handle_t* handle);
 
     private:
         sp<Camera>         mCamera;
diff --git a/include/camera/ICameraRecordingProxy.h b/include/camera/ICameraRecordingProxy.h
index 2aac284..cb6824a 100644
--- a/include/camera/ICameraRecordingProxy.h
+++ b/include/camera/ICameraRecordingProxy.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_H
 
 #include <binder/IInterface.h>
+#include <cutils/native_handle.h>
 #include <utils/RefBase.h>
 
 namespace android {
@@ -83,6 +84,7 @@
     virtual status_t        startRecording(const sp<ICameraRecordingProxyListener>& listener) = 0;
     virtual void            stopRecording() = 0;
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+    virtual void            releaseRecordingFrameHandle(native_handle_t *handle) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraRecordingProxyListener.h b/include/camera/ICameraRecordingProxyListener.h
index b6c0624..1fee5b9 100644
--- a/include/camera/ICameraRecordingProxyListener.h
+++ b/include/camera/ICameraRecordingProxyListener.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_ICAMERA_RECORDING_PROXY_LISTENER_H
 
 #include <binder/IInterface.h>
+#include <cutils/native_handle.h>
 #include <stdint.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -34,6 +35,9 @@
 
     virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
                                        const sp<IMemory>& data) = 0;
+
+    virtual void recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
+                                                       native_handle_t* handle) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/android/hardware/ICamera.h b/include/camera/android/hardware/ICamera.h
index 322b741..3b12afe 100644
--- a/include/camera/android/hardware/ICamera.h
+++ b/include/camera/android/hardware/ICamera.h
@@ -94,9 +94,13 @@
     // get recording state
     virtual bool            recordingEnabled() = 0;
 
-    // release a recording frame
+    // Release a recording frame that was received via ICameraClient::dataCallbackTimestamp.
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem) = 0;
 
+    // Release a recording frame handle that was received via
+    // ICameraClient::recordingFrameHandleCallbackTimestamp.
+    virtual void            releaseRecordingFrameHandle(native_handle_t *handle) = 0;
+
     // auto focus
     virtual status_t        autoFocus() = 0;
 
diff --git a/include/camera/android/hardware/ICameraClient.h b/include/camera/android/hardware/ICameraClient.h
index d7f9a75..3f835a9 100644
--- a/include/camera/android/hardware/ICameraClient.h
+++ b/include/camera/android/hardware/ICameraClient.h
@@ -36,6 +36,11 @@
     virtual void            dataCallback(int32_t msgType, const sp<IMemory>& data,
                                          camera_frame_metadata_t *metadata) = 0;
     virtual void            dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
+
+    // Invoked to send a recording frame handle with a timestamp. Call
+    // ICamera::releaseRecordingFrameHandle to release the frame handle.
+    virtual void            recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
+                                         native_handle_t* handle) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index c732b41..399f363 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -138,6 +138,8 @@
         ProxyListener(const sp<CameraSource>& source);
         virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
                 const sp<IMemory> &data);
+        virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+                native_handle_t* handle);
 
     private:
         sp<CameraSource> mSource;
@@ -209,6 +211,7 @@
 
     virtual status_t startCameraRecording();
     virtual void releaseRecordingFrame(const sp<IMemory>& frame);
+    virtual void releaseRecordingFrameHandle(native_handle_t* handle);
 
     // Returns true if need to skip the current frame.
     // Called from dataCallbackTimestamp.
@@ -220,6 +223,9 @@
     virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
             const sp<IMemory> &data);
 
+    virtual void recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+            native_handle_t* handle);
+
     // Process a buffer item received in BufferQueueListener.
     virtual void processBufferQueueFrame(BufferItem& buffer);
 
@@ -244,6 +250,8 @@
     // The mode video buffers are received from camera. One of VIDEO_BUFFER_MODE_*.
     int32_t mVideoBufferMode;
 
+    static const uint32_t kDefaultVideoBufferCount = 32;
+
     /**
      * The following variables are used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
      */
@@ -264,6 +272,7 @@
 
     void releaseQueuedFrames();
     void releaseOneRecordingFrame(const sp<IMemory>& frame);
+    void createVideoBufferMemoryHeap(size_t size, uint32_t bufferCount);
 
     status_t init(const sp<hardware::ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
                   int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index f17ec51..871c1d9 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -145,6 +145,14 @@
     virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
             const sp<IMemory> &data);
 
+    // In the video camera case calls skipFrameAndModifyTimeStamp() to modify
+    // timestamp and set mSkipCurrentFrame.
+    // Then it calls the base CameraSource::recordingFrameHandleCallbackTimestamp()
+    // 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);
+
     // 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/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index cb974ae..8e9db93 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -56,6 +56,8 @@
     virtual void postDataTimestamp(
             nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
 
+    virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle);
+
 protected:
     virtual ~CameraSourceListener();
 
@@ -100,6 +102,14 @@
     }
 }
 
+void CameraSourceListener::postRecordingFrameHandleTimestamp(nsecs_t timestamp,
+        native_handle_t* handle) {
+    sp<CameraSource> source = mSource.promote();
+    if (source.get() != nullptr) {
+        source->recordingFrameHandleCallbackTimestamp(timestamp/1000, handle);
+    }
+}
+
 static int32_t getColorFormat(const char* colorFormat) {
     if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
        return OMX_COLOR_FormatYUV420Planar;
@@ -509,6 +519,14 @@
     return err;
 }
 
+void CameraSource::createVideoBufferMemoryHeap(size_t size, uint32_t bufferCount) {
+    mMemoryHeapBase = new MemoryHeapBase(size * bufferCount, 0,
+            "StageFright-CameraSource-BufferHeap");
+    for (uint32_t i = 0; i < bufferCount; i++) {
+        mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * size, size));
+    }
+}
+
 status_t CameraSource::initBufferQueue(uint32_t width, uint32_t height,
         uint32_t format, android_dataspace dataSpace, uint32_t bufferCount) {
     ALOGV("initBufferQueue");
@@ -562,12 +580,7 @@
     }
 
     // Create memory heap to store buffers as VideoNativeMetadata.
-    size_t bufferSize = sizeof(VideoNativeMetadata);
-    mMemoryHeapBase = new MemoryHeapBase(bufferSize * bufferCount, 0,
-            "StageFright-CameraSource-BufferHeap");
-    for (uint32_t i = 0; i < bufferCount; i++) {
-        mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * bufferSize, bufferSize));
-    }
+    createVideoBufferMemoryHeap(sizeof(VideoNativeMetadata), bufferCount);
 
     mBufferQueueListener = new BufferQueueListener(mVideoBufferConsumer, this);
     res = mBufferQueueListener->run("CameraSource-BufferQueueListener");
@@ -718,6 +731,9 @@
             ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
                     mEncoderFormat, mEncoderDataSpace, err);
         }
+
+        // Create memory heap to store buffers as VideoNativeMetadata.
+        createVideoBufferMemoryHeap(sizeof(VideoNativeHandleMetadata), kDefaultVideoBufferCount);
     }
 
     err = OK;
@@ -920,12 +936,33 @@
         mVideoBufferConsumer->releaseBuffer(buffer);
         mMemoryBases.push_back(frame);
         mMemoryBaseAvailableCond.signal();
-    } else if (mCameraRecordingProxy != NULL) {
-        mCameraRecordingProxy->releaseRecordingFrame(frame);
-    } else if (mCamera != NULL) {
-        int64_t token = IPCThreadState::self()->clearCallingIdentity();
-        mCamera->releaseRecordingFrame(frame);
-        IPCThreadState::self()->restoreCallingIdentity(token);
+    } else {
+        native_handle_t* handle = nullptr;
+
+        // Check if frame contains a VideoNativeHandleMetadata.
+        if (frame->size() == sizeof(VideoNativeHandleMetadata)) {
+            VideoNativeHandleMetadata *metadata =
+                (VideoNativeHandleMetadata*)(frame->pointer());
+            if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
+                handle = metadata->pHandle;
+            }
+        }
+
+        if (handle != nullptr) {
+            // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
+            releaseRecordingFrameHandle(handle);
+            mMemoryBases.push_back(frame);
+            mMemoryBaseAvailableCond.signal();
+        } else if (mCameraRecordingProxy != nullptr) {
+            // mCamera is created by application. Return the frame back to camera via camera
+            // recording proxy.
+            mCameraRecordingProxy->releaseRecordingFrame(frame);
+        } else if (mCamera != nullptr) {
+            // mCamera is created by CameraSource. Return the frame directly back to camera.
+            int64_t token = IPCThreadState::self()->clearCallingIdentity();
+            mCamera->releaseRecordingFrame(frame);
+            IPCThreadState::self()->restoreCallingIdentity(token);
+        }
     }
 }
 
@@ -1073,6 +1110,53 @@
     mFrameAvailableCondition.signal();
 }
 
+void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
+    if (mCameraRecordingProxy != nullptr) {
+        mCameraRecordingProxy->releaseRecordingFrameHandle(handle);
+    } else if (mCamera != nullptr) {
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
+        mCamera->releaseRecordingFrameHandle(handle);
+        IPCThreadState::self()->restoreCallingIdentity(token);
+    }
+}
+
+void CameraSource::recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+                native_handle_t* handle) {
+    ALOGV("%s: timestamp %lld us", __FUNCTION__, (long long)timestampUs);
+    Mutex::Autolock autoLock(mLock);
+    if (handle == nullptr) return;
+
+    if (shouldSkipFrameLocked(timestampUs)) {
+        releaseRecordingFrameHandle(handle);
+        return;
+    }
+
+    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);
+            return;
+        }
+    }
+
+    ++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);
+    mFrameAvailableCondition.signal();
+}
+
 CameraSource::BufferQueueListener::BufferQueueListener(const sp<BufferItemConsumer>& consumer,
         const sp<CameraSource>& cameraSource) {
     mConsumer = consumer;
@@ -1178,6 +1262,11 @@
     mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
 }
 
+void CameraSource::ProxyListener::recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
+        native_handle_t* handle) {
+    mSource->recordingFrameHandleCallbackTimestamp(timestamp / 1000, handle);
+}
+
 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 d52567c..390c556 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -308,6 +308,13 @@
     CameraSource::dataCallbackTimestamp(timestampUs, msgType, data);
 }
 
+void CameraSourceTimeLapse::recordingFrameHandleCallbackTimestamp(int64_t timestampUs,
+            native_handle_t* handle) {
+    ALOGV("recordingFrameHandleCallbackTimestamp");
+    mSkipCurrentFrame = skipFrameAndModifyTimeStamp(&timestampUs);
+    CameraSource::recordingFrameHandleCallbackTimestamp(timestampUs, handle);
+}
+
 void CameraSourceTimeLapse::processBufferQueueFrame(BufferItem& buffer) {
     ALOGV("processBufferQueueFrame");
     int64_t timestampUs = buffer.mTimestamp / 1000;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4eb7b03..c8e64fe 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1242,6 +1242,12 @@
     ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
 }
 
+void Camera2Client::releaseRecordingFrameHandle(native_handle_t *handle) {
+    (void)handle;
+    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 12ee157..3cb9e4f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -71,6 +71,7 @@
     virtual void            stopRecording();
     virtual bool            recordingEnabled();
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
+    virtual void            releaseRecordingFrameHandle(native_handle_t *handle);
     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 d2fedf8..266fb03 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -19,6 +19,7 @@
 
 #include <cutils/properties.h>
 #include <gui/Surface.h>
+#include <media/hardware/HardwareAPI.h>
 
 #include "api1/CameraClient.h"
 #include "device1/CameraHardwareInterface.h"
@@ -488,6 +489,39 @@
     mHardware->releaseRecordingFrame(mem);
 }
 
+void CameraClient::releaseRecordingFrameHandle(native_handle_t *handle) {
+    if (handle == nullptr) return;
+
+    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 a native handle.", __FUNCTION__,
+                __LINE__);
+        native_handle_close(handle);
+        native_handle_delete(handle);
+        return;
+    } else if (dataPtr->size() != sizeof(VideoNativeHandleMetadata)) {
+        ALOGE("%s: %d: Callback buffer size doesn't match VideoNativeHandleMetadata", __FUNCTION__,
+                __LINE__);
+        native_handle_close(handle);
+        native_handle_delete(handle);
+        return;
+    }
+
+    VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+    metadata->eType = kMetadataBufferTypeNativeHandleSource;
+    metadata->pHandle = handle;
+
+    mHardware->releaseRecordingFrame(dataPtr);
+}
+
 status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
     LOG1("setVideoBufferMode: %d", videoBufferMode);
     bool enableMetadataInBuffers = false;
@@ -929,8 +963,28 @@
     int32_t msgType, const sp<IMemory>& dataPtr) {
     sp<hardware::ICameraClient> c = mRemoteCallback;
     mLock.unlock();
-    if (c != 0) {
-        c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+    if (c != 0 && dataPtr != nullptr) {
+        native_handle_t* handle = nullptr;
+
+        // Check if dataPtr contains a VideoNativeHandleMetadata.
+        if (dataPtr->size() == sizeof(VideoNativeHandleMetadata)) {
+            VideoNativeHandleMetadata *metadata =
+                (VideoNativeHandleMetadata*)(dataPtr->pointer());
+            if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
+                handle = metadata->pHandle;
+            }
+        }
+
+        // If dataPtr contains a native handle, send it via recordingFrameHandleCallbackTimestamp.
+        if (handle != nullptr) {
+            {
+                Mutex::Autolock l(mAvailableCallbackBuffersLock);
+                mAvailableCallbackBuffers.push_back(dataPtr);
+            }
+            c->recordingFrameHandleCallbackTimestamp(timestamp, handle);
+        } else {
+            c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+        }
     }
 }
 
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 603fd17..4f46fc4 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -49,6 +49,7 @@
     virtual void            stopRecording();
     virtual bool            recordingEnabled();
     virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
+    virtual void            releaseRecordingFrameHandle(native_handle_t *handle);
     virtual status_t        autoFocus();
     virtual status_t        cancelAutoFocus();
     virtual status_t        takePicture(int msgType);
@@ -148,6 +149,12 @@
     // Debugging information
     CameraParameters                mLatestSetParameters;
 
+    // mAvailableCallbackBuffers stores sp<IMemory> that HAL uses to send VideoNativeHandleMetadata.
+    // It will be used to send VideoNativeHandleMetadata back to HAL when camera receives the
+    // native handle from releaseRecordingFrameHandle.
+    Mutex                           mAvailableCallbackBuffersLock;
+    std::vector<sp<IMemory>>        mAvailableCallbackBuffers;
+
     // We need to avoid the deadlock when the incoming command thread and
     // the CameraHardwareInterface callback thread both want to grab mLock.
     // An extra flag is used to tell the callback thread that it should stop