OSDN Git Service

DO NOT MERGE: IOMX: work against metadata buffer spoofing
authorLajos Molnar <lajos@google.com>
Tue, 2 Aug 2016 14:07:05 +0000 (07:07 -0700)
committerLajos Molnar <lajos@google.com>
Thu, 18 Aug 2016 21:29:49 +0000 (14:29 -0700)
- Prohibit direct set/getParam/Settings for extensions meant for
  OMXNodeInstance alone. This disallows enabling metadata mode
  without the knowledge of OMXNodeInstance.
- Do not share metadata mode buffers cross process.
- Disallow setting up metadata mode/tunneling/input surface
  after first sendCommand. (Except to Idle for OMXCodec quirk.)
- Disallow store-meta for input cross process.
- Disallow emptyBuffer for surface input (via IOMX).
- Fix checking for input surface.

[backported from M]

Bug: 29422020
Change-Id: I801c77b80e703903f62e42d76fd2e76a34e4bc8e

include/media/IOMX.h
media/libmedia/IOMX.cpp
media/libstagefright/ACodec.cpp
media/libstagefright/OMXClient.cpp
media/libstagefright/include/OMX.h
media/libstagefright/include/OMXNodeInstance.h
media/libstagefright/omx/OMX.cpp
media/libstagefright/omx/OMXNodeInstance.cpp

index 595e51f..6e4a4ac 100644 (file)
@@ -99,7 +99,7 @@ public:
 
     virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer) = 0;
+            buffer_id *buffer, OMX_BOOL crossProcess = OMX_FALSE) = 0;
 
     virtual status_t useGraphicBuffer(
             node_id node, OMX_U32 port_index,
@@ -125,7 +125,7 @@ public:
 
     virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer) = 0;
+            buffer_id *buffer, OMX_BOOL crossProcess = OMX_FALSE) = 0;
 
     virtual status_t freeBuffer(
             node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
index 75b99a6..d5a22e9 100644 (file)
@@ -245,7 +245,7 @@ public:
 
     virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer) {
+            buffer_id *buffer, OMX_BOOL /* crossProcess */) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeInt32((int32_t)node);
@@ -415,7 +415,7 @@ public:
 
     virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer) {
+            buffer_id *buffer, OMX_BOOL /* crossProcess */) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeInt32((int32_t)node);
@@ -754,7 +754,8 @@ status_t BnOMX::onTransact(
                 interface_cast<IMemory>(data.readStrongBinder());
 
             buffer_id buffer;
-            status_t err = useBuffer(node, port_index, params, &buffer);
+            status_t err = useBuffer(
+                    node, port_index, params, &buffer, OMX_TRUE /* crossProcess */);
             reply->writeInt32(err);
 
             if (err == OK) {
@@ -842,7 +843,10 @@ status_t BnOMX::onTransact(
             OMX_U32 port_index = data.readInt32();
             OMX_BOOL enable = (OMX_BOOL)data.readInt32();
 
-            status_t err = storeMetaDataInBuffers(node, port_index, enable);
+            status_t err =
+                // only control output metadata via Binder
+                port_index != 1 /* kOutputPortIndex */ ? BAD_VALUE :
+                storeMetaDataInBuffers(node, port_index, enable);
             reply->writeInt32(err);
 
             return NO_ERROR;
@@ -924,7 +928,7 @@ status_t BnOMX::onTransact(
 
             buffer_id buffer;
             status_t err = allocateBufferWithBackup(
-                    node, port_index, params, &buffer);
+                    node, port_index, params, &buffer, OMX_TRUE /* crossProcess */);
 
             reply->writeInt32(err);
 
index f624020..aa0466d 100644 (file)
@@ -997,7 +997,8 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
         VideoDecoderOutputMetaData *metaData =
             reinterpret_cast<VideoDecoderOutputMetaData *>(
                     oldest->mData->base());
-        CHECK_EQ(metaData->eType, kMetadataBufferTypeGrallocSource);
+        // metaData is only readable if codec is in the same process
+        //CHECK_EQ(metaData->eType, kMetadataBufferTypeGrallocSource);
 
         ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)",
                 oldest - &mBuffers[kPortIndexOutput][0],
index ca031aa..0341d03 100644 (file)
@@ -90,7 +90,7 @@ struct MuxOMX : public IOMX {
 
     virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer);
+            buffer_id *buffer, OMX_BOOL crossProcess);
 
     virtual status_t useGraphicBuffer(
             node_id node, OMX_U32 port_index,
@@ -112,7 +112,7 @@ struct MuxOMX : public IOMX {
 
     virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer);
+            buffer_id *buffer, OMX_BOOL crossProcess);
 
     virtual status_t freeBuffer(
             node_id node, OMX_U32 port_index, buffer_id buffer);
@@ -314,8 +314,9 @@ status_t MuxOMX::getGraphicBufferUsage(
 
 status_t MuxOMX::useBuffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-        buffer_id *buffer) {
-    return getOMX(node)->useBuffer(node, port_index, params, buffer);
+        buffer_id *buffer, OMX_BOOL /* crossProcess */) {
+    return getOMX(node)->useBuffer(
+            node, port_index, params, buffer, OMX_FALSE /* crossProcess */);
 }
 
 status_t MuxOMX::useGraphicBuffer(
@@ -353,9 +354,9 @@ status_t MuxOMX::allocateBuffer(
 
 status_t MuxOMX::allocateBufferWithBackup(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-        buffer_id *buffer) {
+        buffer_id *buffer, OMX_BOOL /* crossProcess */) {
     return getOMX(node)->allocateBufferWithBackup(
-            node, port_index, params, buffer);
+            node, port_index, params, buffer, OMX_FALSE /* crossProcess */);
 }
 
 status_t MuxOMX::freeBuffer(
index 2da5c6c..829c38b 100644 (file)
@@ -81,7 +81,7 @@ public:
 
     virtual status_t useBuffer(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer);
+            buffer_id *buffer, OMX_BOOL crossProcess);
 
     virtual status_t useGraphicBuffer(
             node_id node, OMX_U32 port_index,
@@ -103,7 +103,7 @@ public:
 
     virtual status_t allocateBufferWithBackup(
             node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer);
+            buffer_id *buffer, OMX_BOOL crossProcess);
 
     virtual status_t freeBuffer(
             node_id node, OMX_U32 port_index, buffer_id buffer);
index ad50faf..616dda1 100644 (file)
@@ -21,6 +21,7 @@
 #include "OMX.h"
 
 #include <utils/RefBase.h>
+#include <utils/SortedVector.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -68,7 +69,7 @@ struct OMXNodeInstance {
 
     status_t useBuffer(
             OMX_U32 portIndex, const sp<IMemory> &params,
-            OMX::buffer_id *buffer);
+            OMX::buffer_id *buffer, OMX_BOOL crossProcess);
 
     status_t useGraphicBuffer(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
@@ -89,7 +90,7 @@ struct OMXNodeInstance {
 
     status_t allocateBufferWithBackup(
             OMX_U32 portIndex, const sp<IMemory> &params,
-            OMX::buffer_id *buffer);
+            OMX::buffer_id *buffer, OMX_BOOL crossProcess);
 
     status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
 
@@ -133,6 +134,9 @@ private:
     OMX_HANDLETYPE mHandle;
     sp<IOMXObserver> mObserver;
     bool mDying;
+    bool mSailed;  // configuration is set (no more meta-mode changes)
+    bool mQueriedProhibitedExtensions;
+    SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;
     bool mIsSecure;
 
     // Lock only covers mGraphicBufferSource.  We can't always use mLock
@@ -153,6 +157,9 @@ private:
     KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
     KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
 
+    // metadata mode tracking
+    bool mUsingMetadata[2];
+
     // For debug support
     char *mName;
     int DEBUG;
@@ -177,6 +184,8 @@ private:
     OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
     void invalidateBufferID(OMX::buffer_id buffer);
 
+    bool isProhibitedIndex_l(OMX_INDEXTYPE index);
+
     status_t useGraphicBuffer2_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
             OMX::buffer_id *buffer);
index f8a6f17..1faf724 100644 (file)
@@ -361,9 +361,9 @@ status_t OMX::configureVideoTunnelMode(
 
 status_t OMX::useBuffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-        buffer_id *buffer) {
+        buffer_id *buffer, OMX_BOOL crossProcess) {
     return findInstance(node)->useBuffer(
-            port_index, params, buffer);
+            port_index, params, buffer, crossProcess);
 }
 
 status_t OMX::useGraphicBuffer(
@@ -400,9 +400,9 @@ status_t OMX::allocateBuffer(
 
 status_t OMX::allocateBufferWithBackup(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
-        buffer_id *buffer) {
+        buffer_id *buffer, OMX_BOOL crossProcess) {
     return findInstance(node)->allocateBufferWithBackup(
-            port_index, params, buffer);
+            port_index, params, buffer, crossProcess);
 }
 
 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
index df7461c..f091b87 100644 (file)
@@ -100,26 +100,34 @@ static void InitOMXParams(T *params) {
 namespace android {
 
 struct BufferMeta {
-    BufferMeta(const sp<IMemory> &mem, OMX_U32 portIndex, bool is_backup = false)
+    BufferMeta(
+            const sp<IMemory> &mem, OMX_U32 portIndex, bool copyToOmx,
+            bool copyFromOmx, OMX_U8 *backup)
         : mMem(mem),
-          mIsBackup(is_backup),
-          mPortIndex(portIndex) {
+          mCopyFromOmx(copyFromOmx),
+          mCopyToOmx(copyToOmx),
+          mPortIndex(portIndex),
+          mBackup(backup) {
     }
 
     BufferMeta(size_t size, OMX_U32 portIndex)
         : mSize(size),
-          mIsBackup(false),
-          mPortIndex(portIndex) {
+          mCopyFromOmx(false),
+          mCopyToOmx(false),
+          mPortIndex(portIndex),
+          mBackup(NULL) {
     }
 
     BufferMeta(const sp<GraphicBuffer> &graphicBuffer, OMX_U32 portIndex)
         : mGraphicBuffer(graphicBuffer),
-          mIsBackup(false),
-          mPortIndex(portIndex) {
+          mCopyFromOmx(false),
+          mCopyToOmx(false),
+          mPortIndex(portIndex),
+          mBackup(NULL) {
     }
 
     void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
+        if (!mCopyFromOmx) {
             return;
         }
 
@@ -129,7 +137,7 @@ struct BufferMeta {
     }
 
     void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
+        if (!mCopyToOmx) {
             return;
         }
 
@@ -146,12 +154,18 @@ struct BufferMeta {
         return mPortIndex;
     }
 
+    ~BufferMeta() {
+        delete[] mBackup;
+    }
+
 private:
     sp<GraphicBuffer> mGraphicBuffer;
     sp<IMemory> mMem;
     size_t mSize;
-    bool mIsBackup;
+    bool mCopyFromOmx;
+    bool mCopyToOmx;
     OMX_U32 mPortIndex;
+    OMX_U8 *mBackup;
 
     BufferMeta(const BufferMeta &);
     BufferMeta &operator=(const BufferMeta &);
@@ -178,6 +192,8 @@ OMXNodeInstance::OMXNodeInstance(
       mHandle(NULL),
       mObserver(observer),
       mDying(false),
+      mSailed(false),
+      mQueriedProhibitedExtensions(false),
       mBufferIDCount(0)
 {
     mName = ADebug::GetDebugName(name);
@@ -188,6 +204,8 @@ OMXNodeInstance::OMXNodeInstance(
     mNumPortBuffers[1] = 0;
     mDebugLevelBumpPendingBuffers[0] = 0;
     mDebugLevelBumpPendingBuffers[1] = 0;
+    mUsingMetadata[0] = false;
+    mUsingMetadata[1] = false;
     mIsSecure = AString(name).endsWith(".secure");
 }
 
@@ -345,7 +363,12 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
 
 status_t OMXNodeInstance::sendCommand(
         OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+    if (cmd == OMX_CommandStateSet && param != OMX_StateIdle) {
+        // We do not support returning from unloaded state, so there are no configurations past
+        // first StateSet command. However, OMXCodec supports meta configuration past Stateset:Idle.
+        mSailed = true;
+    }
+    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
     if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
         if (param == OMX_StateIdle) {
             // Initiating transition from Executing -> Idle
@@ -378,10 +401,55 @@ status_t OMXNodeInstance::sendCommand(
     return StatusFromOMXError(err);
 }
 
+bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
+    // these extensions can only be used from OMXNodeInstance, not by clients directly.
+    static const char *restricted_extensions[] = {
+        "OMX.google.android.index.storeMetaDataInBuffers",
+        "OMX.google.android.index.prepareForAdaptivePlayback",
+        "OMX.google.android.index.configureVideoTunnelMode",
+        "OMX.google.android.index.useAndroidNativeBuffer2",
+        "OMX.google.android.index.useAndroidNativeBuffer",
+        "OMX.google.android.index.enableAndroidNativeBuffers",
+        "OMX.google.android.index.getAndroidNativeBufferUsage",
+    };
+
+    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
+            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
+            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
+            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
+            || (index > OMX_IndexCommonStartUnused
+                    && index <= OMX_IndexConfigCommonTransitionEffect)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidEac3)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamSliceSegments)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAutoFramerateConversion)) {
+        return false;
+    }
+
+    if (!mQueriedProhibitedExtensions) {
+        for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
+            OMX_INDEXTYPE ext;
+            if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
+                mProhibitedExtensions.add(ext);
+            }
+        }
+        mQueriedProhibitedExtensions = true;
+    }
+
+    return mProhibitedExtensions.indexOf(index) >= 0;
+}
+
 status_t OMXNodeInstance::getParameter(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     // some errors are expected for getParameter
@@ -397,6 +465,11 @@ status_t OMXNodeInstance::setParameter(
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_SetParameter(
             mHandle, index, const_cast<void *>(params));
     CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
@@ -407,6 +480,11 @@ status_t OMXNodeInstance::getConfig(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     // some errors are expected for getConfig
@@ -422,6 +500,11 @@ status_t OMXNodeInstance::setConfig(
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_SetConfig(
             mHandle, index, const_cast<void *>(params));
     CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
@@ -507,6 +590,15 @@ status_t OMXNodeInstance::storeMetaDataInBuffers_l(
         OMX_BOOL enable,
         OMX_BOOL useGraphicBuffer,
         OMX_BOOL *usingGraphicBufferInMetadata) {
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
+        android_errorWriteLog(0x534e4554, "26324358");
+        return BAD_VALUE;
+    }
+
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
             "OMX.google.android.index.storeMetaDataInBuffers");
@@ -541,6 +633,9 @@ status_t OMXNodeInstance::storeMetaDataInBuffers_l(
     // don't log loud error if component does not support metadata mode on the output
     if (err != OMX_ErrorNone) {
         *usingGraphicBufferInMetadata = OMX_FALSE;
+        if (enable) {
+            mUsingMetadata[portIndex] = false;
+        }
         if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
             CLOGW("component does not support metadata mode; using fallback");
         } else if (xerr != OMX_ErrorNone) {
@@ -549,6 +644,8 @@ status_t OMXNodeInstance::storeMetaDataInBuffers_l(
             CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d GB=%d", name, index,
                     portString(portIndex), portIndex, enable, useGraphicBuffer);
         }
+    } else {
+        mUsingMetadata[portIndex] = enable;
     }
     return StatusFromOMXError(err);
 }
@@ -557,6 +654,10 @@ status_t OMXNodeInstance::prepareForAdaptivePlayback(
         OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
         OMX_U32 maxFrameHeight) {
     Mutex::Autolock autolock(mLock);
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
     CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
             portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
 
@@ -587,6 +688,10 @@ status_t OMXNodeInstance::configureVideoTunnelMode(
         OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
         native_handle_t **sidebandHandle) {
     Mutex::Autolock autolock(mLock);
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
     CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
             portString(portIndex), portIndex, tunneled, audioHwSync);
 
@@ -627,16 +732,39 @@ status_t OMXNodeInstance::configureVideoTunnelMode(
 
 status_t OMXNodeInstance::useBuffer(
         OMX_U32 portIndex, const sp<IMemory> &params,
-        OMX::buffer_id *buffer) {
+        OMX::buffer_id *buffer, OMX_BOOL crossProcess) {
     Mutex::Autolock autoLock(mLock);
+    if (portIndex >= NELEM(mUsingMetadata)) {
+        return BAD_VALUE;
+    }
+    // We do not support metadata mode changes past buffer allocation
+    mSailed = true;
+
+    // metadata buffers are not connected cross process
+    BufferMeta *buffer_meta;
+    bool isMeta = mUsingMetadata[portIndex];
+    bool useBackup = crossProcess && isMeta; // use a backup buffer instead of the actual buffer
+    OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
+    // allocate backup buffer
+    if (useBackup) {
+        data = new (std::nothrow) OMX_U8[params->size()];
+        if (data == NULL) {
+            return NO_MEMORY;
+        }
+        memset(data, 0, params->size());
 
-    BufferMeta *buffer_meta = new BufferMeta(params, portIndex);
+        buffer_meta = new BufferMeta(
+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
+    } else {
+        buffer_meta = new BufferMeta(
+                params, portIndex, false /* copyFromOmx */, false /* copyToOmx */, NULL);
+    }
 
     OMX_BUFFERHEADERTYPE *header;
 
     OMX_ERRORTYPE err = OMX_UseBuffer(
             mHandle, &header, portIndex, buffer_meta,
-            params->size(), static_cast<OMX_U8 *>(params->pointer()));
+            params->size(), data);
 
     if (err != OMX_ErrorNone) {
         CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(portIndex, params->size(), params->pointer()));
@@ -802,7 +930,16 @@ status_t OMXNodeInstance::createInputSurface(
     Mutex::Autolock autolock(mLock);
     status_t err;
 
-    const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
+    // only allow graphic source on input port, when there are no allocated buffers yet
+    if (portIndex != kPortIndexInput) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_VALUE;
+    } else if (mNumPortBuffers[portIndex] > 0) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+
+    const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
     if (surfaceCheck != NULL) {
         return ALREADY_EXISTS;
     }
@@ -866,6 +1003,8 @@ status_t OMXNodeInstance::allocateBuffer(
         OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
         void **buffer_data) {
     Mutex::Autolock autoLock(mLock);
+    // We do not support metadata mode changes past buffer allocation
+    mSailed = true;
 
     BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
 
@@ -902,10 +1041,23 @@ status_t OMXNodeInstance::allocateBuffer(
 
 status_t OMXNodeInstance::allocateBufferWithBackup(
         OMX_U32 portIndex, const sp<IMemory> &params,
-        OMX::buffer_id *buffer) {
+        OMX::buffer_id *buffer, OMX_BOOL crossProcess) {
     Mutex::Autolock autoLock(mLock);
+    if (portIndex >= NELEM(mUsingMetadata)) {
+        return BAD_VALUE;
+    }
+    // We do not support metadata mode changes past buffer allocation
+    mSailed = true;
+
+    // metadata buffers are not connected cross process
+    bool isMeta = mUsingMetadata[portIndex];
+    bool copy = !(crossProcess && isMeta);
 
-    BufferMeta *buffer_meta = new BufferMeta(params, portIndex, true);
+    BufferMeta *buffer_meta = new BufferMeta(
+            params, portIndex,
+            (portIndex == kPortIndexInput) && copy /* copyToOmx */,
+            (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
+            NULL /* data */);
 
     OMX_BUFFERHEADERTYPE *header;
 
@@ -924,6 +1076,7 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
     }
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
+    memset(header->pBuffer, 0, header->nAllocLen);
 
     *buffer = makeBufferID(header);
 
@@ -995,13 +1148,17 @@ status_t OMXNodeInstance::emptyBuffer(
         OMX_U32 flags, OMX_TICKS timestamp) {
     Mutex::Autolock autoLock(mLock);
 
-    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
-    if (header == NULL) {
-        return BAD_VALUE;
+    // no emptybuffer if using input surface
+    if (getGraphicBufferSource() != NULL) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
     }
+
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
     // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
     // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
-    if (rangeOffset > header->nAllocLen
+    if (header == NULL
+            || rangeOffset > header->nAllocLen
             || rangeLength > header->nAllocLen - rangeOffset) {
         return BAD_VALUE;
     }