Merge "NuPlayerRenderer: add more info in a log line." into nyc-mr1-dev
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index abfe068..a61ddaa 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -68,11 +68,16 @@
         mMemory = mem;
     }
 
-    // Decrements the reference count and returns the buffer to its
-    // associated MediaBufferGroup if the reference count drops to 0.
+    // If MediaBufferGroup is set, decrement the local reference count;
+    // if the local reference count drops to 0, return the buffer to the
+    // associated MediaBufferGroup.
+    //
+    // If no MediaBufferGroup is set, the local reference count must be zero
+    // when called, whereupon the MediaBuffer is deleted.
     virtual void release();
 
-    // Increments the reference count.
+    // Increments the local reference count.
+    // Use only when MediaBufferGroup is set.
     virtual void add_ref();
 
     void *data() const;
@@ -97,7 +102,28 @@
     // MetaData.
     MediaBuffer *clone();
 
-    int refcount() const;
+    // sum of localRefcount() and remoteRefcount()
+    int refcount() const {
+        return localRefcount() + remoteRefcount();
+    }
+
+    int localRefcount() const {
+        return mRefCount;
+    }
+
+    int remoteRefcount() const {
+        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+        int32_t remoteRefcount =
+                reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
+        // Sanity check so that remoteRefCount() is non-negative.
+        return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
+    }
+
+    // returns old value
+    int addRemoteRefcount(int32_t value) {
+        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+        return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
+    }
 
     bool isDeadObject() const {
         return isDeadObject(mMemory);
@@ -117,25 +143,6 @@
     }
 
 protected:
-    // MediaBuffer remote releases are handled through a
-    // pending release count variable stored in a SharedControl block
-    // at the start of the IMemory.
-
-    // Returns old value of pending release count.
-    inline int32_t addPendingRelease(int32_t value) {
-        return getSharedControl()->addPendingRelease(value);
-    }
-
-    // Issues all pending releases (works in parallel).
-    // Assumes there is a MediaBufferObserver.
-    inline void resolvePendingRelease() {
-        if (mMemory.get() == nullptr) return;
-        while (addPendingRelease(-1) > 0) {
-            release();
-        }
-        addPendingRelease(1);
-    }
-
     // true if MediaBuffer is observed (part of a MediaBufferGroup).
     inline bool isObserved() const {
         return mObserver != nullptr;
@@ -181,18 +188,18 @@
         };
 
         // returns old value
-        inline int32_t addPendingRelease(int32_t value) {
+        inline int32_t addRemoteRefcount(int32_t value) {
             return std::atomic_fetch_add_explicit(
-                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
         }
 
-        inline int32_t getPendingRelease() const {
-            return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst);
+        inline int32_t getRemoteRefcount() const {
+            return std::atomic_load_explicit(&mRemoteRefcount, std::memory_order_seq_cst);
         }
 
-        inline void setPendingRelease(int32_t value) {
+        inline void setRemoteRefcount(int32_t value) {
             std::atomic_store_explicit(
-                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
         }
 
         inline bool isDeadObject() const {
@@ -209,13 +216,13 @@
             std::atomic_store_explicit(
                     &mFlags, (int_least32_t)0, std::memory_order_seq_cst);
             std::atomic_store_explicit(
-                    &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst);
+                    &mRemoteRefcount, (int_least32_t)0, std::memory_order_seq_cst);
         }
 
     private:
         // Caution: atomic_int_fast32_t is 64 bits on LP64.
         std::atomic_int_least32_t mFlags;
-        std::atomic_int_least32_t mPendingRelease;
+        std::atomic_int_least32_t mRemoteRefcount;
         int32_t unused[6]; // additional buffer space
     };
 
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index dfa31b2..3051406 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -53,10 +53,7 @@
 
     size_t buffers() const { return mBuffers.size(); }
 
-    // freeBuffers is the number of free buffers allowed to remain.
-    void gc(size_t freeBuffers = 0);
-
-protected:
+    // If buffer is nullptr, have acquire_buffer() check for remote release.
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
 private:
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 7f131f4..51a1130 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -891,7 +891,7 @@
             readVector(data, keyId);
             readVector(data, message);
             readVector(data, signature);
-            bool match;
+            bool match = false;
             uint32_t result = verify(sessionId, keyId, message, signature, match);
             reply->writeInt32(match);
             reply->writeInt32(result);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index dd94ccf..5289c5f 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -58,9 +58,9 @@
 
 protected:
     virtual ~RemoteMediaBufferWrapper() {
-        // Indicate to MediaBufferGroup to release.
-        int32_t old = addPendingRelease(1);
-        ALOGV("RemoteMediaBufferWrapper: releasing %p, old %d", this, old);
+        // Release our interest in the MediaBuffer's shared memory.
+        int32_t old = addRemoteRefcount(-1);
+        ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
         mMemory.clear(); // don't set the dead object flag.
     }
 };
@@ -296,8 +296,8 @@
         case STOP: {
             ALOGV("stop");
             CHECK_INTERFACE(IMediaSource, data, reply);
+            mGroup->signalBufferReturned(nullptr);
             status_t status = stop();
-            mGroup->gc();
             mIndexCache.reset();
             mBuffersSinceStop = 0;
             return status;
@@ -305,6 +305,7 @@
         case PAUSE: {
             ALOGV("pause");
             CHECK_INTERFACE(IMediaSource, data, reply);
+            mGroup->signalBufferReturned(nullptr);
             return pause();
         }
         case GETFORMAT: {
@@ -336,7 +337,7 @@
                     && len == sizeof(opts)
                     && data.read((void *)&opts, len) == NO_ERROR;
 
-            mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
+            mGroup->signalBufferReturned(nullptr);
             mIndexCache.gc();
             size_t inlineTransferSize = 0;
             status_t ret = NO_ERROR;
@@ -411,10 +412,11 @@
                     reply->writeInt32(offset);
                     reply->writeInt32(length);
                     buf->meta_data()->writeToParcel(*reply);
-                    if (transferBuf != buf) {
-                        buf->release();
-                    } else if (!supportNonblockingRead()) {
-                        maxNumBuffers = 0; // stop readMultiple with one shared buffer.
+                    if (transferBuf == buf) {
+                        buf->addRemoteRefcount(1);
+                        if (!supportNonblockingRead()) {
+                            maxNumBuffers = 0; // stop readMultiple with one shared buffer.
+                        }
                     }
                 } else {
                     ALOGV_IF(buf->mMemory != nullptr,
@@ -423,12 +425,12 @@
                     reply->writeInt32(INLINE_BUFFER);
                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
                     buf->meta_data()->writeToParcel(*reply);
-                    buf->release();
                     inlineTransferSize += length;
                     if (inlineTransferSize > kInlineMaxTransfer) {
                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
                     }
                 }
+                buf->release();
             }
             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
             reply->writeInt32(ret);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index e087249..893da89 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -1117,6 +1117,9 @@
         int64_t token = IPCThreadState::self()->clearCallingIdentity();
         mCamera->releaseRecordingFrameHandle(handle);
         IPCThreadState::self()->restoreCallingIdentity(token);
+    } else {
+        native_handle_close(handle);
+        native_handle_delete(handle);
     }
 }
 
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index 718b7e5..16000ef 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -105,14 +105,7 @@
 
 void MediaBuffer::release() {
     if (mObserver == NULL) {
-        if (mMemory.get() != nullptr) {
-            // See if there is a pending release and there are no observers.
-            // Ideally this never happens.
-            while (addPendingRelease(-1) > 0) {
-                __sync_fetch_and_sub(&mRefCount, 1);
-            }
-            addPendingRelease(1);
-        }
+        // Legacy contract for MediaBuffer without a MediaBufferGroup.
         CHECK_EQ(mRefCount, 0);
         delete this;
         return;
@@ -205,10 +198,6 @@
     mObserver = observer;
 }
 
-int MediaBuffer::refcount() const {
-    return mRefCount;
-}
-
 MediaBuffer *MediaBuffer::clone() {
     CHECK(mGraphicBuffer == NULL);
 
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index cb78879..54f768a 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -51,7 +51,7 @@
 
         for (size_t i = 0; i < buffers; ++i) {
             sp<IMemory> mem = memoryDealer->allocate(augmented_size);
-            if (mem.get() == nullptr) {
+            if (mem.get() == nullptr || mem->pointer() == nullptr) {
                 ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
                 break;
             }
@@ -76,11 +76,24 @@
 
 MediaBufferGroup::~MediaBufferGroup() {
     for (MediaBuffer *buffer : mBuffers) {
-        buffer->resolvePendingRelease();
-        // If we don't release it, perhaps noone will release it.
-        LOG_ALWAYS_FATAL_IF(buffer->refcount() != 0,
-                "buffer refcount %p = %d != 0", buffer, buffer->refcount());
-        // actually delete it.
+        if (buffer->refcount() != 0) {
+            const int localRefcount = buffer->localRefcount();
+            const int remoteRefcount = buffer->remoteRefcount();
+
+            // Fatal if we have a local refcount.
+            LOG_ALWAYS_FATAL_IF(localRefcount != 0,
+                    "buffer(%p) localRefcount %d != 0, remoteRefcount %d",
+                    buffer, localRefcount, remoteRefcount);
+
+            // Log an error if we have a remaining remote refcount,
+            // as the remote process may have died or may have inappropriate behavior.
+            // The shared memory associated with the MediaBuffer will
+            // automatically be reclaimed when there are no remaining fds
+            // associated with it.
+            ALOGE("buffer(%p) has residual remoteRefcount %d",
+                    buffer, remoteRefcount);
+        }
+        // gracefully delete.
         buffer->setObserver(nullptr);
         buffer->release();
     }
@@ -94,32 +107,11 @@
     // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
 }
 
-void MediaBufferGroup::gc(size_t freeBuffers) {
-    Mutex::Autolock autoLock(mLock);
-
-    size_t freeCount = 0;
-    for (auto it = mBuffers.begin(); it != mBuffers.end(); ) {
-        (*it)->resolvePendingRelease();
-        if ((*it)->isDeadObject()) {
-            // The MediaBuffer has been deleted, why is it in the MediaBufferGroup?
-            LOG_ALWAYS_FATAL("buffer(%p) has dead object with refcount %d",
-                    (*it), (*it)->refcount());
-        } else if ((*it)->refcount() == 0 && ++freeCount > freeBuffers) {
-            (*it)->setObserver(nullptr);
-            (*it)->release();
-            it = mBuffers.erase(it);
-        } else {
-            ++it;
-        }
-    }
-}
-
 bool MediaBufferGroup::has_buffers() {
     if (mBuffers.size() < mGrowthLimit) {
         return true; // We can add more buffers internally.
     }
     for (MediaBuffer *buffer : mBuffers) {
-        buffer->resolvePendingRelease();
         if (buffer->refcount() == 0) {
             return true;
         }
@@ -135,7 +127,6 @@
         MediaBuffer *buffer = nullptr;
         auto free = mBuffers.end();
         for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
-            (*it)->resolvePendingRelease();
             if ((*it)->refcount() == 0) {
                 const size_t size = (*it)->size();
                 if (size >= requestedSize) {
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index b4abc60..a8965f0 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -392,8 +392,12 @@
 }
 
 status_t MetaData::writeToParcel(Parcel &parcel) {
+    status_t ret;
     size_t numItems = mItems.size();
-    parcel.writeUint32(uint32_t(numItems));
+    ret = parcel.writeUint32(uint32_t(numItems));
+    if (ret) {
+        return ret;
+    }
     for (size_t i = 0; i < numItems; i++) {
         int32_t key = mItems.keyAt(i);
         const typed_data &item = mItems.valueAt(i);
@@ -401,9 +405,32 @@
         const void *data;
         size_t size;
         item.getData(&type, &data, &size);
-        parcel.writeInt32(key);
-        parcel.writeUint32(type);
-        parcel.writeByteArray(size, (uint8_t*)data);
+        ret = parcel.writeInt32(key);
+        if (ret) {
+            return ret;
+        }
+        ret = parcel.writeUint32(type);
+        if (ret) {
+            return ret;
+        }
+        if (type == TYPE_NONE) {
+            android::Parcel::WritableBlob blob;
+            ret = parcel.writeUint32(static_cast<uint32_t>(size));
+            if (ret) {
+                return ret;
+            }
+            ret = parcel.writeBlob(size, false, &blob);
+            if (ret) {
+                return ret;
+            }
+            memcpy(blob.data(), data, size);
+            blob.release();
+        } else {
+            ret = parcel.writeByteArray(size, (uint8_t*)data);
+            if (ret) {
+                return ret;
+            }
+        }
     }
     return OK;
 }
@@ -422,8 +449,20 @@
             if (ret != OK) {
                 break;
             }
-            // copy data directly from Parcel storage, then advance position
-            setData(key, type, parcel.readInplace(size), size);
+            // copy data from Blob, which may be inline in Parcel storage,
+            // then advance position
+            if (type == TYPE_NONE) {
+                android::Parcel::ReadableBlob blob;
+                ret = parcel.readBlob(size, &blob);
+                if (ret != OK) {
+                    break;
+                }
+                setData(key, type, blob.data(), size);
+                blob.release();
+            } else {
+                // copy data directly from Parcel storage, then advance position
+                setData(key, type, parcel.readInplace(size), size);
+            }
          }
 
         return OK;
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 56ab3f6..94cf15a 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -21,6 +21,7 @@
 #include "OMX.h"
 
 #include <utils/RefBase.h>
+#include <utils/SortedVector.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -151,6 +152,9 @@
     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
@@ -204,6 +208,8 @@
     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);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 4908062..35d5de6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -93,26 +93,34 @@
 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;
         }
 
@@ -123,7 +131,7 @@
     }
 
     void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
+        if (!mCopyToOmx) {
             return;
         }
 
@@ -163,13 +171,19 @@
         return mPortIndex;
     }
 
+    ~BufferMeta() {
+        delete[] mBackup;
+    }
+
 private:
     sp<GraphicBuffer> mGraphicBuffer;
     sp<NativeHandle> mNativeHandle;
     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 &);
@@ -196,6 +210,8 @@
       mHandle(NULL),
       mObserver(observer),
       mDying(false),
+      mSailed(false),
+      mQueriedProhibitedExtensions(false),
       mBufferIDCount(0)
 {
     mName = ADebug::GetDebugName(name);
@@ -355,7 +371,12 @@
 
 status_t OMXNodeInstance::sendCommand(
         OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+    if (cmd == OMX_CommandStateSet) {
+        // We do not support returning from unloaded state, so there are no configurations past
+        // first StateSet command.
+        mSailed = true;
+    }
+    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
     if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
         if (param == OMX_StateIdle) {
             // Initiating transition from Executing -> Idle
@@ -388,10 +409,57 @@
     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.storeANWBufferInMetadata",
+        "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.allocateNativeHandle",
+        "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_IndexParamAudioProfileQuerySupported)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
+        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
@@ -407,6 +475,11 @@
     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);
@@ -417,6 +490,11 @@
         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
@@ -432,6 +510,11 @@
     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);
@@ -534,6 +617,10 @@
 
 status_t OMXNodeInstance::storeMetaDataInBuffers_l(
         OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
     if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
         android_errorWriteLog(0x534e4554, "26324358");
         if (type != NULL) {
@@ -611,6 +698,10 @@
         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);
 
@@ -641,6 +732,10 @@
         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);
 
@@ -688,21 +783,46 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-    if (allottedSize > params->size()) {
+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
         return BAD_VALUE;
     }
 
-    BufferMeta *buffer_meta = new BufferMeta(params, portIndex);
+    // metadata buffers are not connected cross process
+    // use a backup buffer instead of the actual buffer
+    BufferMeta *buffer_meta;
+    bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
+    OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
+    // allocate backup buffer
+    if (useBackup) {
+        data = new (std::nothrow) OMX_U8[allottedSize];
+        if (data == NULL) {
+            return NO_MEMORY;
+        }
+        memset(data, 0, allottedSize);
+
+        // if we are not connecting the buffers, the sizes must match
+        if (allottedSize != params->size()) {
+            CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
+            delete[] data;
+            return BAD_VALUE;
+        }
+
+        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,
-            allottedSize, static_cast<OMX_U8 *>(params->pointer()));
+            allottedSize, data);
 
     if (err != OMX_ErrorNone) {
         CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
-                portIndex, (size_t)allottedSize, params->pointer()));
+                portIndex, (size_t)allottedSize, data));
 
         delete buffer_meta;
         buffer_meta = NULL;
@@ -901,7 +1021,7 @@
     // update backup buffer for input, codec buffer for output
     return updateGraphicBufferInMeta_l(
             portIndex, graphicBuffer, buffer, header,
-            portIndex == kPortIndexOutput /* updateCodecBuffer */);
+            true /* updateCodecBuffer */);
 }
 
 status_t OMXNodeInstance::updateNativeHandleInMeta(
@@ -921,7 +1041,7 @@
     BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
     // update backup buffer for input, codec buffer for output
     sp<ABuffer> data = bufferMeta->getBuffer(
-            header, portIndex == kPortIndexInput /* backup */, false /* limit */);
+            header, false /* backup */, false /* limit */);
     bufferMeta->setNativeHandle(nativeHandle);
     if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource
             && data->capacity() >= sizeof(VideoNativeHandleMetadata)) {
@@ -945,7 +1065,16 @@
         OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
     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) {
         if (portIndex < NELEM(mMetadataType) && type != NULL) {
             *type = mMetadataType[portIndex];
@@ -1141,11 +1270,18 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-    if (allottedSize > params->size()) {
+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
         return BAD_VALUE;
     }
 
-    BufferMeta *buffer_meta = new BufferMeta(params, portIndex, true);
+    // metadata buffers are not connected cross process; only copy if not meta
+    bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
+
+    BufferMeta *buffer_meta = new BufferMeta(
+            params, portIndex,
+            (portIndex == kPortIndexInput) && copy /* copyToOmx */,
+            (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
+            NULL /* data */);
 
     OMX_BUFFERHEADERTYPE *header;
 
@@ -1163,6 +1299,7 @@
     }
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
+    memset(header->pBuffer, 0, header->nAllocLen);
 
     *buffer = makeBufferID(header);
 
@@ -1243,6 +1380,12 @@
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
+    // no emptybuffer if using input surface
+    if (getGraphicBufferSource() != NULL) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
     if (header == NULL) {
         ALOGE("b/25884056");