stagefright: enable native handles for secure buffers

- rename IOMX::allocateBuffer to allocateSecureBuffer as ACodec
  only uses allocateBuffer for secure compressed buffers.
- add argument to return native_handle if component supports it.
- rename IOMX::enableGraphicBuffers to enableNativeBuffers.
- add argument to select graphic vs. native handle mode
- request native handles for secure input buffers, but allow
  fallback

Bug: 26782004
Change-Id: Ide9d07f54d2e7e3e6a82dbca011f4db9a5630950
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 27ad694..d6db67a 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -98,8 +98,8 @@
             node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
             OMX_U32 audioHwSync, native_handle_t **sidebandHandle) = 0;
 
-    virtual status_t enableGraphicBuffers(
-            node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
+    virtual status_t enableNativeBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) = 0;
 
     virtual status_t getGraphicBufferUsage(
             node_id node, OMX_U32 port_index, OMX_U32* usage) = 0;
@@ -137,13 +137,14 @@
 
     virtual status_t signalEndOfInputStream(node_id node) = 0;
 
-    // This API clearly only makes sense if the caller lives in the
-    // same process as the callee, i.e. is the media_server, as the
-    // returned "buffer_data" pointer is just that, a pointer into local
-    // address space.
-    virtual status_t allocateBuffer(
+    // Allocate an opaque buffer as a native handle. If component supports returning native
+    // handles, those are returned in *native_handle. Otherwise, the allocated buffer is
+    // returned in *buffer_data. This clearly only makes sense if the caller lives in the
+    // same process as the callee, i.e. is the media_server, as the returned "buffer_data"
+    // pointer is just that, a pointer into local address space.
+    virtual status_t allocateSecureBuffer(
             node_id node, OMX_U32 port_index, size_t size,
-            buffer_id *buffer, void **buffer_data) = 0;
+            buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) = 0;
 
     // Allocate an OMX buffer of size |allotedSize|. Use |params| as the backup buffer, which
     // may be larger.
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 349db64..cc5b486 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -26,6 +26,7 @@
 #include <media/stagefright/CodecBase.h>
 #include <media/stagefright/FrameRenderTracker.h>
 #include <media/stagefright/SkipCutBuffer.h>
+#include <utils/NativeHandle.h>
 #include <OMX_Audio.h>
 
 #define TRACK_BUFFER_TIMING     0
@@ -72,6 +73,7 @@
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
         sp<ABuffer> bufferAt(size_t index) const;
+        sp<NativeHandle> handleAt(size_t index) const;
         sp<RefBase> memRefAt(size_t index) const;
 
     private:
@@ -79,10 +81,13 @@
 
         Vector<IOMX::buffer_id> mBufferIDs;
         Vector<sp<ABuffer> > mBuffers;
+        Vector<sp<NativeHandle> > mHandles;
         Vector<sp<RefBase> > mMemRefs;
 
         PortDescription();
-        void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer, const sp<RefBase> &memRef);
+        void addBuffer(
+                IOMX::buffer_id id, const sp<ABuffer> &buffer,
+                const sp<NativeHandle> &handle, const sp<RefBase> &memRef);
 
         DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
     };
@@ -186,6 +191,7 @@
         sp<ABuffer> mData;
         sp<RefBase> mMemRef;
         sp<GraphicBuffer> mGraphicBuffer;
+        sp<NativeHandle> mNativeHandle;
         int mFenceFd;
         FrameRenderTracker::Info *mRenderInfo;
 
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 01b744b..cbf9839 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -23,6 +23,7 @@
 
 #include <media/MediaCodecInfo.h>
 #include <media/stagefright/foundation/AHandler.h>
+#include <utils/NativeHandle.h>
 
 namespace android {
 
@@ -77,6 +78,7 @@
         virtual size_t countBuffers() = 0;
         virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
         virtual sp<ABuffer> bufferAt(size_t index) const = 0;
+        virtual sp<NativeHandle> handleAt(size_t index) { return NULL; };
         virtual sp<RefBase> memRefAt(size_t index) const { return NULL; }
 
     protected:
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index ea708e3..2bb1291 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -254,6 +254,7 @@
     struct BufferInfo {
         uint32_t mBufferID;
         sp<ABuffer> mData;
+        sp<NativeHandle> mNativeHandle;
         sp<RefBase> mMemRef;
         sp<ABuffer> mEncryptedData;
         sp<IMemory> mSharedEncryptedBuffer;
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 550b506..9a7dff6 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -37,7 +37,7 @@
     GET_CONFIG,
     SET_CONFIG,
     GET_STATE,
-    ENABLE_GRAPHIC_BUFFERS,
+    ENABLE_NATIVE_BUFFERS,
     USE_BUFFER,
     USE_GRAPHIC_BUFFER,
     CREATE_INPUT_SURFACE,
@@ -46,7 +46,7 @@
     SIGNAL_END_OF_INPUT_STREAM,
     STORE_META_DATA_IN_BUFFERS,
     PREPARE_FOR_ADAPTIVE_PLAYBACK,
-    ALLOC_BUFFER,
+    ALLOC_SECURE_BUFFER,
     ALLOC_BUFFER_WITH_BACKUP,
     FREE_BUFFER,
     FILL_BUFFER,
@@ -217,14 +217,15 @@
         return reply.readInt32();
     }
 
-    virtual status_t enableGraphicBuffers(
-            node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+    virtual status_t enableNativeBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
+        data.writeInt32((uint32_t)graphic);
         data.writeInt32((uint32_t)enable);
-        remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply);
+        remote()->transact(ENABLE_NATIVE_BUFFERS, data, &reply);
 
         status_t err = reply.readInt32();
         return err;
@@ -453,26 +454,31 @@
     }
 
 
-    virtual status_t allocateBuffer(
+    virtual status_t allocateSecureBuffer(
             node_id node, OMX_U32 port_index, size_t size,
-            buffer_id *buffer, void **buffer_data) {
+            buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeInt64(size);
-        remote()->transact(ALLOC_BUFFER, data, &reply);
+        remote()->transact(ALLOC_SECURE_BUFFER, data, &reply);
 
         status_t err = reply.readInt32();
         if (err != OK) {
             *buffer = 0;
-
+            *buffer_data = NULL;
+            *native_handle = NULL;
             return err;
         }
 
         *buffer = (buffer_id)reply.readInt32();
         *buffer_data = (void *)reply.readInt64();
-
+        if (*buffer_data == NULL) {
+            *native_handle = reply.readNativeHandle();
+        } else {
+            *native_handle = NULL;
+        }
         return err;
     }
 
@@ -754,15 +760,16 @@
             return NO_ERROR;
         }
 
-        case ENABLE_GRAPHIC_BUFFERS:
+        case ENABLE_NATIVE_BUFFERS:
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
             node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
+            OMX_BOOL graphic = (OMX_BOOL)data.readInt32();
             OMX_BOOL enable = (OMX_BOOL)data.readInt32();
 
-            status_t err = enableGraphicBuffers(node, port_index, enable);
+            status_t err = enableNativeBuffers(node, port_index, graphic, enable);
             reply->writeInt32(err);
 
             return NO_ERROR;
@@ -965,7 +972,7 @@
             OMX_BOOL tunneled = (OMX_BOOL)data.readInt32();
             OMX_U32 audio_hw_sync = data.readInt32();
 
-            native_handle_t *sideband_handle;
+            native_handle_t *sideband_handle = NULL;
             status_t err = configureVideoTunnelMode(
                     node, port_index, tunneled, audio_hw_sync, &sideband_handle);
             reply->writeInt32(err);
@@ -974,7 +981,7 @@
             return NO_ERROR;
         }
 
-        case ALLOC_BUFFER:
+        case ALLOC_SECURE_BUFFER:
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
@@ -989,14 +996,18 @@
             size_t size = data.readInt64();
 
             buffer_id buffer;
-            void *buffer_data;
-            status_t err = allocateBuffer(
-                    node, port_index, size, &buffer, &buffer_data);
+            void *buffer_data = NULL;
+            native_handle_t *native_handle = NULL;
+            status_t err = allocateSecureBuffer(
+                    node, port_index, size, &buffer, &buffer_data, &native_handle);
             reply->writeInt32(err);
 
             if (err == OK) {
                 reply->writeInt32((int32_t)buffer);
                 reply->writeInt64((uintptr_t)buffer_data);
+                if (buffer_data == NULL) {
+                    reply->writeNativeHandle(native_handle);
+                }
             }
 
             return NO_ERROR;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 5f13ebc..0dc5d4c 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -828,6 +828,7 @@
                 info.mStatus = BufferInfo::OWNED_BY_US;
                 info.mFenceFd = -1;
                 info.mRenderInfo = NULL;
+                info.mNativeHandle = NULL;
 
                 uint32_t requiresAllocateBufferBit =
                     (portIndex == kPortIndexInput)
@@ -837,12 +838,22 @@
                 if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
                     mem.clear();
 
-                    void *ptr;
-                    err = mOMX->allocateBuffer(
+                    void *ptr = NULL;
+                    native_handle_t *native_handle = NULL;
+                    err = mOMX->allocateSecureBuffer(
                             mNode, portIndex, bufSize, &info.mBufferID,
-                            &ptr);
+                            &ptr, &native_handle);
 
-                    info.mData = new ABuffer(ptr, bufSize);
+                    // TRICKY: this representation is unorthodox, but ACodec requires
+                    // an ABuffer with a proper size to validate range offsets and lengths.
+                    // Since mData is never referenced for secure input, it is used to store
+                    // either the pointer to the secure buffer, or the opaque handle as on
+                    // some devices ptr is actually an opaque handle, not a pointer.
+
+                    // TRICKY2: use native handle as the base of the ABuffer if received one,
+                    // because Widevine source only receives these base addresses.
+                    info.mData = new ABuffer(ptr != NULL ? ptr : (void *)native_handle, bufSize);
+                    info.mNativeHandle = NativeHandle::create(native_handle, true /* ownsHandle */);
                 } else if (mQuirks & requiresAllocateBufferBit) {
                     err = mOMX->allocateBufferWithBackup(
                             mNode, portIndex, mem, &info.mBufferID, allottedSize);
@@ -876,7 +887,7 @@
 
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
         const BufferInfo &info = mBuffers[portIndex][i];
-        desc->addBuffer(info.mBufferID, info.mData, info.mMemRef);
+        desc->addBuffer(info.mBufferID, info.mData, info.mNativeHandle, info.mMemRef);
     }
 
     notify->setObject("portDesc", desc);
@@ -1774,6 +1785,14 @@
             mFlags |= kFlagIsGrallocUsageProtected;
             mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
         }
+
+        if (mFlags & kFlagIsSecure) {
+            // use native_handles for secure input buffers
+            err = mOMX->enableNativeBuffers(
+                    mNode, kPortIndexInput, OMX_FALSE /* graphic */, OMX_TRUE);
+            ALOGI_IF(err != OK, "falling back to non-native_handles");
+            err = OK; // ignore error for now
+        }
     }
     if (haveNativeWindow) {
         sp<ANativeWindow> nativeWindow =
@@ -1985,7 +2004,8 @@
                         inputFormat->setInt32("adaptive-playback", false);
                     }
                     if (err == OK) {
-                        err = mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_FALSE);
+                        err = mOMX->enableNativeBuffers(
+                                mNode, kPortIndexOutput, OMX_TRUE /* graphic */, OMX_FALSE);
                     }
                     if (mFlags & kFlagIsGrallocUsageProtected) {
                         // fallback is not supported for protected playback
@@ -3879,10 +3899,10 @@
 
 status_t ACodec::initNativeWindow() {
     if (mNativeWindow != NULL) {
-        return mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_TRUE);
+        return mOMX->enableNativeBuffers(mNode, kPortIndexOutput, OMX_TRUE /* graphic */, OMX_TRUE);
     }
 
-    mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_FALSE);
+    mOMX->enableNativeBuffers(mNode, kPortIndexOutput, OMX_TRUE /* graphic */, OMX_FALSE);
     return OK;
 }
 
@@ -4646,9 +4666,11 @@
 }
 
 void ACodec::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<ABuffer> &buffer, const sp<RefBase> &memRef) {
+        IOMX::buffer_id id, const sp<ABuffer> &buffer,
+        const sp<NativeHandle> &handle, const sp<RefBase> &memRef) {
     mBufferIDs.push_back(id);
     mBuffers.push_back(buffer);
+    mHandles.push_back(handle);
     mMemRefs.push_back(memRef);
 }
 
@@ -4664,6 +4686,10 @@
     return mBuffers.itemAt(index);
 }
 
+sp<NativeHandle> ACodec::PortDescription::handleAt(size_t index) const {
+    return mHandles.itemAt(index);
+}
+
 sp<RefBase> ACodec::PortDescription::memRefAt(size_t index) const {
     return mMemRefs.itemAt(index);
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ce67d78..1be9a3e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1357,6 +1357,7 @@
                         info.mBufferID = portDesc->bufferIDAt(i);
                         info.mOwnedByClient = false;
                         info.mData = portDesc->bufferAt(i);
+                        info.mNativeHandle = portDesc->handleAt(i);
                         info.mMemRef = portDesc->memRefAt(i);
 
                         if (portIndex == kPortIndexInput && mCrypto != NULL) {
@@ -2493,6 +2494,9 @@
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
+        // TODO: use different decrypt based on native handle or not
+        // use native handle if we have it; otherwise, use opaque handle
+        void *dst_pointer = (void *)info->mNativeHandle.get() ? : info->mData->base();
         ssize_t result = mCrypto->decrypt(
                 (mFlags & kFlagIsSecure) != 0,
                 key,
@@ -2503,7 +2507,7 @@
                 offset,
                 subSamples,
                 numSubSamples,
-                info->mData->base(),
+                dst_pointer,
                 errorDetailMsg);
 
         if (result < 0) {
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index e69890d..50f235e 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -82,8 +82,8 @@
             node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
             OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
 
-    virtual status_t enableGraphicBuffers(
-            node_id node, OMX_U32 port_index, OMX_BOOL enable);
+    virtual status_t enableNativeBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable);
 
     virtual status_t getGraphicBufferUsage(
             node_id node, OMX_U32 port_index, OMX_U32* usage);
@@ -114,9 +114,9 @@
 
     virtual status_t signalEndOfInputStream(node_id node);
 
-    virtual status_t allocateBuffer(
+    virtual status_t allocateSecureBuffer(
             node_id node, OMX_U32 port_index, size_t size,
-            buffer_id *buffer, void **buffer_data);
+            buffer_id *buffer, void **buffer_data, native_handle_t **native_handle);
 
     virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
@@ -310,9 +310,9 @@
             node, portIndex, enable, audioHwSync, sidebandHandle);
 }
 
-status_t MuxOMX::enableGraphicBuffers(
-        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
-    return getOMX(node)->enableGraphicBuffers(node, port_index, enable);
+status_t MuxOMX::enableNativeBuffers(
+        node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) {
+    return getOMX(node)->enableNativeBuffers(node, port_index, graphic, enable);
 }
 
 status_t MuxOMX::getGraphicBufferUsage(
@@ -366,11 +366,11 @@
     return getOMX(node)->signalEndOfInputStream(node);
 }
 
-status_t MuxOMX::allocateBuffer(
+status_t MuxOMX::allocateSecureBuffer(
         node_id node, OMX_U32 port_index, size_t size,
-        buffer_id *buffer, void **buffer_data) {
-    return getOMX(node)->allocateBuffer(
-            node, port_index, size, buffer, buffer_data);
+        buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) {
+    return getOMX(node)->allocateSecureBuffer(
+            node, port_index, size, buffer, buffer_data, native_handle);
 }
 
 status_t MuxOMX::allocateBufferWithBackup(
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 9f2e5e7..4c27360 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -62,8 +62,8 @@
     virtual status_t getState(
             node_id node, OMX_STATETYPE* state);
 
-    virtual status_t enableGraphicBuffers(
-            node_id node, OMX_U32 port_index, OMX_BOOL enable);
+    virtual status_t enableNativeBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable);
 
     virtual status_t getGraphicBufferUsage(
             node_id node, OMX_U32 port_index, OMX_U32* usage);
@@ -107,9 +107,9 @@
 
     virtual status_t signalEndOfInputStream(node_id node);
 
-    virtual status_t allocateBuffer(
+    virtual status_t allocateSecureBuffer(
             node_id node, OMX_U32 port_index, size_t size,
-            buffer_id *buffer, void **buffer_data);
+            buffer_id *buffer, void **buffer_data, native_handle_t **native_handle);
 
     virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index e5fb45b..732894c 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -54,7 +54,7 @@
 
     status_t getState(OMX_STATETYPE* state);
 
-    status_t enableGraphicBuffers(OMX_U32 portIndex, OMX_BOOL enable);
+    status_t enableNativeBuffers(OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable);
 
     status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage);
 
@@ -95,9 +95,9 @@
 
     status_t signalEndOfInputStream();
 
-    status_t allocateBuffer(
+    status_t allocateSecureBuffer(
             OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
-            void **buffer_data);
+            void **buffer_data, native_handle_t **native_handle);
 
     status_t allocateBufferWithBackup(
             OMX_U32 portIndex, const sp<IMemory> &params,
@@ -165,7 +165,15 @@
     uint32_t mBufferIDCount;
     KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
     KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
+
+    // metadata and secure buffer type tracking
     MetadataBufferType mMetadataType[2];
+    enum SecureBufferType {
+        kSecureBufferTypeUnknown,
+        kSecureBufferTypeOpaque,
+        kSecureBufferTypeNativeHandle,
+    };
+    SecureBufferType mSecureBufferType[2];
 
     // For debug support
     char *mName;
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index b3625b4..a20028b 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -380,15 +380,15 @@
             state);
 }
 
-status_t OMX::enableGraphicBuffers(
-        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+status_t OMX::enableNativeBuffers(
+        node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) {
     OMXNodeInstance *instance = findInstance(node);
 
     if (instance == NULL) {
         return NAME_NOT_FOUND;
     }
 
-    return instance->enableGraphicBuffers(port_index, enable);
+    return instance->enableNativeBuffers(port_index, graphic, enable);
 }
 
 status_t OMX::getGraphicBufferUsage(
@@ -521,17 +521,17 @@
     return instance->signalEndOfInputStream();
 }
 
-status_t OMX::allocateBuffer(
+status_t OMX::allocateSecureBuffer(
         node_id node, OMX_U32 port_index, size_t size,
-        buffer_id *buffer, void **buffer_data) {
+        buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) {
     OMXNodeInstance *instance = findInstance(node);
 
     if (instance == NULL) {
         return NAME_NOT_FOUND;
     }
 
-    return instance->allocateBuffer(
-            port_index, size, buffer, buffer_data);
+    return instance->allocateSecureBuffer(
+            port_index, size, buffer, buffer_data, native_handle);
 }
 
 status_t OMX::allocateBufferWithBackup(
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 9ae238a..3e83f24 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -203,6 +203,8 @@
     mDebugLevelBumpPendingBuffers[1] = 0;
     mMetadataType[0] = kMetadataBufferTypeInvalid;
     mMetadataType[1] = kMetadataBufferTypeInvalid;
+    mSecureBufferType[0] = kSecureBufferTypeUnknown;
+    mSecureBufferType[1] = kSecureBufferTypeUnknown;
     mIsSecure = AString(name).endsWith(".secure");
 }
 
@@ -453,12 +455,14 @@
     return StatusFromOMXError(err);
 }
 
-status_t OMXNodeInstance::enableGraphicBuffers(
-        OMX_U32 portIndex, OMX_BOOL enable) {
+status_t OMXNodeInstance::enableNativeBuffers(
+        OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
     Mutex::Autolock autoLock(mLock);
-    CLOG_CONFIG(enableGraphicBuffers, "%s:%u, %d", portString(portIndex), portIndex, enable);
+    CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
+                graphic ? ", graphic" : "", enable);
     OMX_STRING name = const_cast<OMX_STRING>(
-            "OMX.google.android.index.enableAndroidNativeBuffers");
+            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
+                    : "OMX.google.android.index.allocateNativeHandle");
 
     OMX_INDEXTYPE index;
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
@@ -476,6 +480,14 @@
     err = OMX_SetParameter(mHandle, index, &params);
     CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
             portString(portIndex), portIndex, enable);
+    if (!graphic) {
+        if (err == OK) {
+            mSecureBufferType[portIndex] =
+                enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
+        } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
+            mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
+        }
+    }
     return StatusFromOMXError(err);
 }
 
@@ -996,10 +1008,10 @@
     return bufferSource->signalEndOfInputStream();
 }
 
-status_t OMXNodeInstance::allocateBuffer(
+status_t OMXNodeInstance::allocateSecureBuffer(
         OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
-        void **buffer_data) {
-    if (buffer == NULL || buffer_data == NULL) {
+        void **buffer_data, native_handle_t **native_handle) {
+    if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {
         ALOGE("b/25884056");
         return BAD_VALUE;
     }
@@ -1026,7 +1038,13 @@
     CHECK_EQ(header->pAppPrivate, buffer_meta);
 
     *buffer = makeBufferID(header);
-    *buffer_data = header->pBuffer;
+    if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) {
+        *buffer_data = NULL;
+        *native_handle = (native_handle_t *)header->pBuffer;
+    } else {
+        *buffer_data = header->pBuffer;
+        *native_handle = NULL;
+    }
 
     addActiveBuffer(portIndex, *buffer);
 
@@ -1034,7 +1052,8 @@
     if (bufferSource != NULL && portIndex == kPortIndexInput) {
         bufferSource->addCodecBuffer(header);
     }
-    CLOG_BUFFER(allocateBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p", size, *buffer_data));
+    CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(
+            *buffer, portIndex, "%zu@%p:%p", size, *buffer_data, *native_handle));
 
     return OK;
 }