Merge "media: change parameters for OMX_EventOutputRendered" into mnc-dev
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index ddaf54f..3ada1e9 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -60,6 +60,7 @@
     status_t            appendFrom(const Parcel *parcel,
                                    size_t start, size_t len);
 
+    bool                allowFds() const;
     bool                pushAllowFds(bool allowFds);
     void                restoreAllowFds(bool lastValue);
 
@@ -132,9 +133,16 @@
 
     // Writes a blob to the parcel.
     // If the blob is small, then it is stored in-place, otherwise it is
-    // transferred by way of an anonymous shared memory region.
+    // transferred by way of an anonymous shared memory region.  Prefer sending
+    // immutable blobs if possible since they may be subsequently transferred between
+    // processes without further copying whereas mutable blobs always need to be copied.
     // The caller should call release() on the blob after writing its contents.
-    status_t            writeBlob(size_t len, WritableBlob* outBlob);
+    status_t            writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob);
+
+    // Write an existing immutable blob file descriptor to the parcel.
+    // This allows the client to send the same blob to multiple processes
+    // as long as it keeps a dup of the blob file descriptor handy for later.
+    status_t            writeDupImmutableBlobFileDescriptor(int fd);
 
     status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
 
@@ -270,16 +278,19 @@
         Blob();
         ~Blob();
 
+        void clear();
         void release();
         inline size_t size() const { return mSize; }
+        inline int fd() const { return mFd; };
+        inline bool isMutable() const { return mMutable; }
 
     protected:
-        void init(bool mapped, void* data, size_t size);
-        void clear();
+        void init(int fd, void* data, size_t size, bool isMutable);
 
-        bool mMapped;
+        int mFd; // owned by parcel so not closed when released
         void* mData;
         size_t mSize;
+        bool mMutable;
     };
 
     class FlattenableHelperInterface {
@@ -320,6 +331,7 @@
         friend class Parcel;
     public:
         inline const void* data() const { return mData; }
+        inline void* mutableData() { return isMutable() ? mData : NULL; }
     };
 
     class WritableBlob : public Blob {
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index afa7eb1..9754a89 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -178,6 +178,9 @@
     // See IGraphicBufferProducer::setGenerationNumber
     virtual status_t setGenerationNumber(uint32_t generationNumber);
 
+    // See IGraphicBufferProducer::getConsumerName
+    virtual String8 getConsumerName() const override;
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 4ca4cd5..9530de1 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -480,6 +480,9 @@
     // affected and will retain their current generation number. The generation
     // number defaults to 0.
     virtual status_t setGenerationNumber(uint32_t generationNumber) = 0;
+
+    // Returns the name of the connected consumer.
+    virtual String8 getConsumerName() const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 261b07c..72f1067 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -106,6 +106,9 @@
      * See IGBP::setGenerationNumber for more information. */
     status_t setGenerationNumber(uint32_t generationNumber);
 
+    // See IGraphicBufferProducer::getConsumerName
+    String8 getConsumerName() const;
+
 protected:
     virtual ~Surface();
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 58bbb26..2ebf617 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -72,9 +72,6 @@
 // Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
 #define EX_HAS_REPLY_HEADER -128
 
-// Maximum size of a blob to transfer in-place.
-static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024;
-
 // XXX This can be made public if we want to provide
 // support for typed data.
 struct small_flat_data
@@ -89,6 +86,15 @@
 static size_t gParcelGlobalAllocSize = 0;
 static size_t gParcelGlobalAllocCount = 0;
 
+// Maximum size of a blob to transfer in-place.
+static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
+
+enum {
+    BLOB_INPLACE = 0,
+    BLOB_ASHMEM_IMMUTABLE = 1,
+    BLOB_ASHMEM_MUTABLE = 2,
+};
+
 void acquire_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who)
 {
@@ -516,6 +522,11 @@
     return err;
 }
 
+bool Parcel::allowFds() const
+{
+    return mAllowFds;
+}
+
 bool Parcel::pushAllowFds(bool allowFds)
 {
     const bool origValue = mAllowFds;
@@ -886,25 +897,24 @@
     return err;
 }
 
-status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
+status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
 {
-    status_t status;
-
     if (len > INT32_MAX) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
         return BAD_VALUE;
     }
 
-    if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) {
+    status_t status;
+    if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) {
         ALOGV("writeBlob: write in place");
-        status = writeInt32(0);
+        status = writeInt32(BLOB_INPLACE);
         if (status) return status;
 
         void* ptr = writeInplace(len);
         if (!ptr) return NO_MEMORY;
 
-        outBlob->init(false /*mapped*/, ptr, len);
+        outBlob->init(-1, ptr, len, false);
         return NO_ERROR;
     }
 
@@ -922,15 +932,17 @@
         if (ptr == MAP_FAILED) {
             status = -errno;
         } else {
-            result = ashmem_set_prot_region(fd, PROT_READ);
+            if (!mutableCopy) {
+                result = ashmem_set_prot_region(fd, PROT_READ);
+            }
             if (result < 0) {
                 status = result;
             } else {
-                status = writeInt32(1);
+                status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE);
                 if (!status) {
                     status = writeFileDescriptor(fd, true /*takeOwnership*/);
                     if (!status) {
-                        outBlob->init(true /*mapped*/, ptr, len);
+                        outBlob->init(fd, ptr, len, mutableCopy);
                         return NO_ERROR;
                     }
                 }
@@ -942,6 +954,15 @@
     return status;
 }
 
+status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd)
+{
+    // Must match up with what's done in writeBlob.
+    if (!mAllowFds) return FDS_NOT_ALLOWED;
+    status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE);
+    if (status) return status;
+    return writeDupFileDescriptor(fd);
+}
+
 status_t Parcel::write(const FlattenableHelperInterface& val)
 {
     status_t err;
@@ -992,6 +1013,15 @@
 restart_write:
         *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
 
+        // remember if it's a file descriptor
+        if (val.type == BINDER_TYPE_FD) {
+            if (!mAllowFds) {
+                // fail before modifying our object index
+                return FDS_NOT_ALLOWED;
+            }
+            mHasFds = mFdsKnown = true;
+        }
+
         // Need to write meta-data?
         if (nullMetaData || val.binder != 0) {
             mObjects[mObjectsSize] = mDataPos;
@@ -999,14 +1029,6 @@
             mObjectsSize++;
         }
 
-        // remember if it's a file descriptor
-        if (val.type == BINDER_TYPE_FD) {
-            if (!mAllowFds) {
-                return FDS_NOT_ALLOWED;
-            }
-            mHasFds = mFdsKnown = true;
-        }
-
         return finishWrite(sizeof(flat_binder_object));
     }
 
@@ -1354,27 +1376,29 @@
 
 status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
 {
-    int32_t useAshmem;
-    status_t status = readInt32(&useAshmem);
+    int32_t blobType;
+    status_t status = readInt32(&blobType);
     if (status) return status;
 
-    if (!useAshmem) {
+    if (blobType == BLOB_INPLACE) {
         ALOGV("readBlob: read in place");
         const void* ptr = readInplace(len);
         if (!ptr) return BAD_VALUE;
 
-        outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len);
+        outBlob->init(-1, const_cast<void*>(ptr), len, false);
         return NO_ERROR;
     }
 
     ALOGV("readBlob: read from ashmem");
+    bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE);
     int fd = readFileDescriptor();
     if (fd == int(BAD_TYPE)) return BAD_VALUE;
 
-    void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+    void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
+            MAP_SHARED, fd, 0);
     if (ptr == MAP_FAILED) return NO_MEMORY;
 
-    outBlob->init(true /*mapped*/, ptr, len);
+    outBlob->init(fd, ptr, len, isMutable);
     return NO_ERROR;
 }
 
@@ -1890,7 +1914,7 @@
 // --- Parcel::Blob ---
 
 Parcel::Blob::Blob() :
-        mMapped(false), mData(NULL), mSize(0) {
+        mFd(-1), mData(NULL), mSize(0), mMutable(false) {
 }
 
 Parcel::Blob::~Blob() {
@@ -1898,22 +1922,24 @@
 }
 
 void Parcel::Blob::release() {
-    if (mMapped && mData) {
+    if (mFd != -1 && mData) {
         ::munmap(mData, mSize);
     }
     clear();
 }
 
-void Parcel::Blob::init(bool mapped, void* data, size_t size) {
-    mMapped = mapped;
+void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) {
+    mFd = fd;
     mData = data;
     mSize = size;
+    mMutable = isMutable;
 }
 
 void Parcel::Blob::clear() {
-    mMapped = false;
+    mFd = -1;
     mData = NULL;
     mSize = 0;
+    mMutable = false;
 }
 
 }; // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 73d4261..38fb757 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1089,6 +1089,12 @@
     return NO_ERROR;
 }
 
+String8 BufferQueueProducer::getConsumerName() const {
+    ATRACE_CALL();
+    BQ_LOGV("getConsumerName: %s", mConsumerName.string());
+    return mConsumerName;
+}
+
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
     // If we're here, it means that a producer we were connected to died.
     // We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index cfe726b..d7a7885 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -48,6 +48,7 @@
     ALLOCATE_BUFFERS,
     ALLOW_ALLOCATION,
     SET_GENERATION_NUMBER,
+    GET_CONSUMER_NAME,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -296,6 +297,17 @@
         }
         return result;
     }
+
+    virtual String8 getConsumerName() const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_CONSUMER_NAME, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getConsumerName failed to transact: %d", result);
+            return String8("TransactFailed");
+        }
+        return reply.readString8();
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -467,6 +479,11 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case GET_CONSUMER_NAME: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            reply->writeString8(getConsumerName());
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index aeb56e0..df0661c 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -111,6 +111,10 @@
     return result;
 }
 
+String8 Surface::getConsumerName() const {
+    return mGraphicBufferProducer->getConsumerName();
+}
+
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
     Surface* c = getSelf(window);
     return c->setSwapInterval(interval);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 3d1139d..1a54875 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "BufferQueue_test"
 //#define LOG_NDEBUG 0
 
+#include "DummyConsumer.h"
+
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
 #include <gui/IProducerListener.h>
@@ -67,12 +69,6 @@
     sp<IGraphicBufferConsumer> mConsumer;
 };
 
-struct DummyConsumer : public BnConsumerListener {
-    virtual void onFrameAvailable(const BufferItem& /* item */) {}
-    virtual void onBuffersReleased() {}
-    virtual void onSidebandStreamChanged() {}
-};
-
 static const uint32_t TEST_DATA = 0x12345678u;
 
 // XXX: Tests that fork a process to hold the BufferQueue must run before tests
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h
new file mode 100644
index 0000000..0511e16
--- /dev/null
+++ b/libs/gui/tests/DummyConsumer.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/IConsumerListener.h>
+
+namespace android {
+
+struct DummyConsumer : public BnConsumerListener {
+    virtual void onFrameAvailable(const BufferItem& /* item */) {}
+    virtual void onBuffersReleased() {}
+    virtual void onSidebandStreamChanged() {}
+};
+
+} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index cf0043d..3f495f8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "DummyConsumer.h"
+
 #include <gtest/gtest.h>
 
 #include <binder/IMemory.h>
@@ -210,4 +212,20 @@
     ASSERT_EQ(1U, graphicBuffer->getGenerationNumber());
 }
 
+TEST_F(SurfaceTest, GetConsumerName) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
+}
+
 }
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index ee8d41c..ba4c198 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -535,6 +535,10 @@
     return INVALID_OPERATION;
 }
 
+String8 VirtualDisplaySurface::getConsumerName() const {
+    return String8("VirtualDisplaySurface");
+}
+
 void VirtualDisplaySurface::updateQueueBufferOutput(
         const QueueBufferOutput& qbo) {
     uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index ff02290..6298751 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -117,6 +117,7 @@
             PixelFormat format, uint32_t usage);
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
+    virtual String8 getConsumerName() const override;
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 6f25bf5..fb7af97 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -118,6 +118,10 @@
     return mProducer->setGenerationNumber(generationNumber);
 }
 
+String8 MonitoredProducer::getConsumerName() const {
+    return mProducer->getConsumerName();
+}
+
 IBinder* MonitoredProducer::onAsBinder() {
     return IInterface::asBinder(mProducer).get();
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index ff691d8..da95766 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -55,6 +55,7 @@
             PixelFormat format, uint32_t usage);
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
+    virtual String8 getConsumerName() const override;
     virtual IBinder* onAsBinder();
 
 private: