Make Flattenable not virtual

Fallout from the Flattenable change, update all its uses.

Additionnaly, fix/tighten size checks when (un)flatten()ing
things.

Removed the assumption by some flattenables (e.g.: Fence)
that the size passed to them would be exact (it can
and will be larger in some cases)

The code in Parcel is a bit complicated so that we don't
have to expose the full implementation (and also to
keep the code smallish).

Change-Id: I0bf1c8aca2a3128491b4f45510bc46667e566dde
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 3ff95d2..7a782f5 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -27,8 +27,8 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+template <typename T> class Flattenable;
 template <typename T> class LightFlattenable;
-class Flattenable;
 class IBinder;
 class IPCThreadState;
 class ProcessState;
@@ -37,8 +37,7 @@
 
 struct flat_binder_object;  // defined in support_p/binder_module.h
 
-class Parcel
-{
+class Parcel {
 public:
     class ReadableBlob;
     class WritableBlob;
@@ -102,7 +101,9 @@
     status_t            writeString16(const char16_t* str, size_t len);
     status_t            writeStrongBinder(const sp<IBinder>& val);
     status_t            writeWeakBinder(const wp<IBinder>& val);
-    status_t            write(const Flattenable& val);
+
+    template<typename T>
+    status_t            write(const Flattenable<T>& val);
 
     template<typename T>
     status_t            write(const LightFlattenable<T>& val);
@@ -157,7 +158,9 @@
     const char16_t*     readString16Inplace(size_t* outLen) const;
     sp<IBinder>         readStrongBinder() const;
     wp<IBinder>         readWeakBinder() const;
-    status_t            read(Flattenable& val) const;
+
+    template<typename T>
+    status_t            read(Flattenable<T>& val) const;
 
     template<typename T>
     status_t            read(LightFlattenable<T>& val) const;
@@ -260,6 +263,39 @@
         size_t mSize;
     };
 
+    class FlattenableHelperInterface {
+    protected:
+        ~FlattenableHelperInterface() { }
+    public:
+        virtual size_t getFlattenedSize() const = 0;
+        virtual size_t getFdCount() const = 0;
+        virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const = 0;
+        virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) = 0;
+    };
+
+    template<typename T>
+    class FlattenableHelper : public FlattenableHelperInterface {
+        friend class Parcel;
+        const Flattenable<T>& val;
+        explicit FlattenableHelper(const Flattenable<T>& val) : val(val) { }
+
+    public:
+        virtual size_t getFlattenedSize() const {
+            return val.getFlattenedSize();
+        }
+        virtual size_t getFdCount() const {
+            return val.getFdCount();
+        }
+        virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const {
+            return val.flatten(buffer, size, fds, count);
+        }
+        virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) {
+            return const_cast<Flattenable<T>&>(val).unflatten(buffer, size, fds, count);
+        }
+    };
+    status_t write(const FlattenableHelperInterface& val);
+    status_t read(FlattenableHelperInterface& val) const;
+
 public:
     class ReadableBlob : public Blob {
         friend class Parcel;
@@ -277,8 +313,14 @@
 // ---------------------------------------------------------------------------
 
 template<typename T>
+status_t Parcel::write(const Flattenable<T>& val) {
+    const FlattenableHelper<T> helper(val);
+    return write(helper);
+}
+
+template<typename T>
 status_t Parcel::write(const LightFlattenable<T>& val) {
-    size_t size(val.getSize());
+    size_t size(val.getFlattenedSize());
     if (!val.isFixedSize()) {
         status_t err = writeInt32(size);
         if (err != NO_ERROR) {
@@ -287,17 +329,24 @@
     }
     if (size) {
         void* buffer = writeInplace(size);
-        return buffer == NULL ? NO_MEMORY :
-                val.flatten(buffer);
+        if (buffer == NULL)
+            return NO_MEMORY;
+        return val.flatten(buffer, size);
     }
     return NO_ERROR;
 }
 
 template<typename T>
+status_t Parcel::read(Flattenable<T>& val) const {
+    FlattenableHelper<T> helper(val);
+    return read(helper);
+}
+
+template<typename T>
 status_t Parcel::read(LightFlattenable<T>& val) const {
     size_t size;
     if (val.isFixedSize()) {
-        size = val.getSize();
+        size = val.getFlattenedSize();
     } else {
         int32_t s;
         status_t err = readInt32(&s);
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 9677962..033c727 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -105,7 +105,8 @@
     // and height of the window and current transform applied to buffers,
     // respectively.
 
-    struct QueueBufferInput : public Flattenable {
+    struct QueueBufferInput : public Flattenable<QueueBufferInput> {
+        friend class Flattenable<QueueBufferInput>;
         inline QueueBufferInput(const Parcel& parcel);
         inline QueueBufferInput(int64_t timestamp,
                 const Rect& crop, int scalingMode, uint32_t transform, bool async,
@@ -123,13 +124,11 @@
             *outFence = fence;
         }
 
-        // Flattenable interface
-        virtual size_t getFlattenedSize() const;
-        virtual size_t getFdCount() const;
-        virtual status_t flatten(void* buffer, size_t size,
-                int fds[], size_t count) const;
-        virtual status_t unflatten(void const* buffer, size_t size,
-                int fds[], size_t count);
+        // Flattenable protocol
+        size_t getFlattenedSize() const;
+        size_t getFdCount() const;
+        status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+        status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
     private:
         int64_t timestamp;
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 2af2307..9197372 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -70,8 +70,8 @@
 
     // LightFlattenable protocol
     inline bool isFixedSize() const { return false; }
-    size_t getSize() const;
-    status_t flatten(void* buffer) const;
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
     status_t unflatten(void const* buffer, size_t size);
 
 private:
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 60156e7..20466b6 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -36,7 +36,7 @@
 // ===========================================================================
 
 class Fence
-    : public LightRefBase<Fence>, public Flattenable
+    : public LightRefBase<Fence>, public Flattenable<Fence>
 {
 public:
     static const sp<Fence> NO_FENCE;
@@ -96,15 +96,13 @@
     // Flattenable interface
     size_t getFlattenedSize() const;
     size_t getFdCount() const;
-    status_t flatten(void* buffer, size_t size,
-            int fds[], size_t count) const;
-    status_t unflatten(void const* buffer, size_t size,
-            int fds[], size_t count);
+    status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+    status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
 private:
     // Only allow instantiation using ref counting.
     friend class LightRefBase<Fence>;
-    virtual ~Fence();
+    ~Fence();
 
     // Disallow copying
     Fence(const Fence& rhs);
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index e5ad1e0..8184b7d 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -39,8 +39,9 @@
 
 class GraphicBuffer
     : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,
-      public Flattenable
+      public Flattenable<GraphicBuffer>
 {
+    friend class Flattenable<GraphicBuffer>;
 public:
 
     enum {
@@ -106,7 +107,7 @@
     static void dumpAllocationsToSystemLog();
 
 private:
-    virtual ~GraphicBuffer();
+    ~GraphicBuffer();
 
     enum {
         ownNone   = 0,
@@ -136,13 +137,11 @@
 
     void free_handle();
 
-    // Flattenable interface
+    // Flattenable protocol
     size_t getFlattenedSize() const;
     size_t getFdCount() const;
-    status_t flatten(void* buffer, size_t size,
-            int fds[], size_t count) const;
-    status_t unflatten(void const* buffer, size_t size,
-            int fds[], size_t count);
+    status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+    status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
 
     GraphicBufferMapper& mBufferMapper;
diff --git a/include/ui/Region.h b/include/ui/Region.h
index ce91f3b..d906dbb 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -136,8 +136,8 @@
             void        addRectUnchecked(int l, int t, int r, int b);
 
     inline  bool        isFixedSize() const { return false; }
-            size_t      getSize() const;
-            status_t    flatten(void* buffer) const;
+            size_t      getFlattenedSize() const;
+            status_t    flatten(void* buffer, size_t size) const;
             status_t    unflatten(void const* buffer, size_t size);
 
     void        dump(String8& out, const char* what, uint32_t flags=0) const;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 359742c..7a5919f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -798,13 +798,13 @@
     return status;
 }
 
-status_t Parcel::write(const Flattenable& val)
+status_t Parcel::write(const FlattenableHelperInterface& val)
 {
     status_t err;
 
     // size if needed
-    size_t len = val.getFlattenedSize();
-    size_t fd_count = val.getFdCount();
+    const size_t len = val.getFlattenedSize();
+    const size_t fd_count = val.getFdCount();
 
     err = this->writeInt32(len);
     if (err) return err;
@@ -813,7 +813,7 @@
     if (err) return err;
 
     // payload
-    void* buf = this->writeInplace(PAD_SIZE(len));
+    void* const buf = this->writeInplace(PAD_SIZE(len));
     if (buf == NULL)
         return BAD_VALUE;
 
@@ -1174,14 +1174,14 @@
     return NO_ERROR;
 }
 
-status_t Parcel::read(Flattenable& val) const
+status_t Parcel::read(FlattenableHelperInterface& val) const
 {
     // size
     const size_t len = this->readInt32();
     const size_t fd_count = this->readInt32();
 
     // payload
-    void const* buf = this->readInplace(PAD_SIZE(len));
+    void const* const buf = this->readInplace(PAD_SIZE(len));
     if (buf == NULL)
         return BAD_VALUE;
 
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 2e561df..48b2870 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -270,8 +270,7 @@
     parcel.read(*this);
 }
 
-size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const
-{
+size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
     return sizeof(timestamp)
          + sizeof(crop)
          + sizeof(scalingMode)
@@ -280,38 +279,46 @@
          + fence->getFlattenedSize();
 }
 
-size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const
-{
+size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
     return fence->getFdCount();
 }
 
-status_t IGraphicBufferProducer::QueueBufferInput::flatten(void* buffer, size_t size,
-        int fds[], size_t count) const
+status_t IGraphicBufferProducer::QueueBufferInput::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const
 {
-    status_t err = NO_ERROR;
-    char* p = (char*)buffer;
-    memcpy(p, &timestamp,   sizeof(timestamp));   p += sizeof(timestamp);
-    memcpy(p, &crop,        sizeof(crop));        p += sizeof(crop);
-    memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
-    memcpy(p, &transform,   sizeof(transform));   p += sizeof(transform);
-    memcpy(p, &async,       sizeof(async));       p += sizeof(async);
-    err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
-    return err;
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::write(buffer, size, timestamp);
+    FlattenableUtils::write(buffer, size, crop);
+    FlattenableUtils::write(buffer, size, scalingMode);
+    FlattenableUtils::write(buffer, size, transform);
+    FlattenableUtils::write(buffer, size, async);
+    return fence->flatten(buffer, size, fds, count);
 }
 
-status_t IGraphicBufferProducer::QueueBufferInput::unflatten(void const* buffer,
-        size_t size, int fds[], size_t count)
+status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count)
 {
-    status_t err = NO_ERROR;
-    const char* p = (const char*)buffer;
-    memcpy(&timestamp,   p, sizeof(timestamp));   p += sizeof(timestamp);
-    memcpy(&crop,        p, sizeof(crop));        p += sizeof(crop);
-    memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
-    memcpy(&transform,   p, sizeof(transform));   p += sizeof(transform);
-    memcpy(&async,       p, sizeof(async));       p += sizeof(async);
+    size_t minNeeded =
+              sizeof(timestamp)
+            + sizeof(crop)
+            + sizeof(scalingMode)
+            + sizeof(transform)
+            + sizeof(async);
+
+    if (size < minNeeded) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, timestamp);
+    FlattenableUtils::read(buffer, size, crop);
+    FlattenableUtils::read(buffer, size, scalingMode);
+    FlattenableUtils::read(buffer, size, transform);
+    FlattenableUtils::read(buffer, size, async);
+
     fence = new Fence();
-    err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
-    return err;
+    return fence->unflatten(buffer, size, fds, count);
 }
 
 }; // namespace android
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index c52a88f..d84c370 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -98,85 +98,85 @@
     return mVersion;
 }
 
-size_t Sensor::getSize() const
+size_t Sensor::getFlattenedSize() const
 {
-    return  sizeof(int32_t) + ((mName.length() + 3) & ~3) +
-            sizeof(int32_t) + ((mVendor.length() + 3) & ~3) +
+    size_t fixedSize =
             sizeof(int32_t) * 3 +
             sizeof(float) * 4 +
             sizeof(int32_t);
+
+    size_t variableSize =
+            sizeof(int32_t) + FlattenableUtils::align<4>(mName.length()) +
+            sizeof(int32_t) + FlattenableUtils::align<4>(mVendor.length());
+
+    return fixedSize + variableSize;
 }
 
-static inline
-size_t write(void* buffer, size_t offset, const String8& value) {
-    memcpy(static_cast<char*>(buffer) + offset, value.string(), value.length());
-    return (value.length() + 3) & ~3;
-}
+status_t Sensor::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
 
-static inline
-size_t write(void* buffer, size_t offset, float value) {
-    *reinterpret_cast<float*>(static_cast<char*>(buffer) + offset) = value;
-    return sizeof(float);
-}
+    FlattenableUtils::write(buffer, size, mName.length());
+    memcpy(static_cast<char*>(buffer), mName.string(), mName.length());
+    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(mName.length()));
 
-static inline
-size_t write(void* buffer, size_t offset, int32_t value) {
-    *reinterpret_cast<int32_t*>(static_cast<char*>(buffer) + offset) = value;
-    return sizeof(int32_t);
-}
+    FlattenableUtils::write(buffer, size, mVendor.length());
+    memcpy(static_cast<char*>(buffer), mVendor.string(), mVendor.length());
+    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(mVendor.length()));
 
-status_t Sensor::flatten(void* buffer) const
-{
-    size_t offset = 0;
-    offset += write(buffer, offset, int32_t(mName.length()));
-    offset += write(buffer, offset, mName);
-    offset += write(buffer, offset, int32_t(mVendor.length()));
-    offset += write(buffer, offset, mVendor);
-    offset += write(buffer, offset, mVersion);
-    offset += write(buffer, offset, mHandle);
-    offset += write(buffer, offset, mType);
-    offset += write(buffer, offset, mMinValue);
-    offset += write(buffer, offset, mMaxValue);
-    offset += write(buffer, offset, mResolution);
-    offset += write(buffer, offset, mPower);
-    offset += write(buffer, offset, mMinDelay);
+    FlattenableUtils::write(buffer, size, mVersion);
+    FlattenableUtils::write(buffer, size, mHandle);
+    FlattenableUtils::write(buffer, size, mType);
+    FlattenableUtils::write(buffer, size, mMinValue);
+    FlattenableUtils::write(buffer, size, mMaxValue);
+    FlattenableUtils::write(buffer, size, mResolution);
+    FlattenableUtils::write(buffer, size, mPower);
+    FlattenableUtils::write(buffer, size, mMinDelay);
     return NO_ERROR;
 }
 
-static inline
-size_t read(void const* buffer, size_t offset, String8* value, int32_t len) {
-    value->setTo(static_cast<char const*>(buffer) + offset, len);
-    return (len + 3) & ~3;
-}
+status_t Sensor::unflatten(void const* buffer, size_t size) {
+    size_t len;
 
-static inline
-size_t read(void const* buffer, size_t offset, float* value) {
-    *value = *reinterpret_cast<float const*>(static_cast<char const*>(buffer) + offset);
-    return sizeof(float);
-}
+    if (size < sizeof(size_t)) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::read(buffer, size, len);
+    if (size < len) {
+        return NO_MEMORY;
+    }
+    mName.setTo(static_cast<char const*>(buffer), len);
+    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
 
-static inline
-size_t read(void const* buffer, size_t offset, int32_t* value) {
-    *value = *reinterpret_cast<int32_t const*>(static_cast<char const*>(buffer) + offset);
-    return sizeof(int32_t);
-}
 
-status_t Sensor::unflatten(void const* buffer, size_t size)
-{
-    int32_t len;
-    size_t offset = 0;
-    offset += read(buffer, offset, &len);
-    offset += read(buffer, offset, &mName, len);
-    offset += read(buffer, offset, &len);
-    offset += read(buffer, offset, &mVendor, len);
-    offset += read(buffer, offset, &mVersion);
-    offset += read(buffer, offset, &mHandle);
-    offset += read(buffer, offset, &mType);
-    offset += read(buffer, offset, &mMinValue);
-    offset += read(buffer, offset, &mMaxValue);
-    offset += read(buffer, offset, &mResolution);
-    offset += read(buffer, offset, &mPower);
-    offset += read(buffer, offset, &mMinDelay);
+    if (size < sizeof(size_t)) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::read(buffer, size, len);
+    if (size < len) {
+        return NO_MEMORY;
+    }
+    mVendor.setTo(static_cast<char const*>(buffer), len);
+    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+
+    size_t fixedSize =
+            sizeof(int32_t) * 3 +
+            sizeof(float) * 4 +
+            sizeof(int32_t);
+
+    if (size < fixedSize) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mVersion);
+    FlattenableUtils::read(buffer, size, mHandle);
+    FlattenableUtils::read(buffer, size, mType);
+    FlattenableUtils::read(buffer, size, mMinValue);
+    FlattenableUtils::read(buffer, size, mMaxValue);
+    FlattenableUtils::read(buffer, size, mResolution);
+    FlattenableUtils::read(buffer, size, mPower);
+    FlattenableUtils::read(buffer, size, mMinDelay);
     return NO_ERROR;
 }
 
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 464ee86..93ec0ce 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -127,37 +127,49 @@
 }
 
 size_t Fence::getFlattenedSize() const {
-    return 0;
+    return 1;
 }
 
 size_t Fence::getFdCount() const {
     return isValid() ? 1 : 0;
 }
 
-status_t Fence::flatten(void* buffer, size_t size, int fds[],
-        size_t count) const {
-    if (size != getFlattenedSize() || count != getFdCount()) {
-        return BAD_VALUE;
+status_t Fence::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
+    if (size < getFlattenedSize() || count < getFdCount()) {
+        return NO_MEMORY;
     }
-
+    FlattenableUtils::write(buffer, size, getFdCount());
     if (isValid()) {
-        fds[0] = mFenceFd;
+        *fds++ = mFenceFd;
+        count--;
     }
     return NO_ERROR;
 }
 
-status_t Fence::unflatten(void const* buffer, size_t size, int fds[],
-        size_t count) {
-    if (size != 0 || (count != 0 && count != 1)) {
-        return BAD_VALUE;
-    }
+status_t Fence::unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count) {
     if (mFenceFd != -1) {
         // Don't unflatten if we already have a valid fd.
         return INVALID_OPERATION;
     }
 
-    if (count == 1) {
-        mFenceFd = fds[0];
+    if (size < 1) {
+        return NO_MEMORY;
+    }
+
+    size_t numFds;
+    FlattenableUtils::read(buffer, size, numFds);
+
+    if (numFds > 1) {
+        return BAD_VALUE;
+    }
+
+    if (count < numFds) {
+        return NO_MEMORY;
+    }
+
+    if (numFds) {
+        mFenceFd = *fds++;
+        count--;
     }
 
     return NO_ERROR;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 580788d..1f273e2 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -209,9 +209,7 @@
     return handle ? handle->numFds : 0;
 }
 
-status_t GraphicBuffer::flatten(void* buffer, size_t size,
-        int fds[], size_t count) const
-{
+status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
     if (size < sizeNeeded) return NO_MEMORY;
 
@@ -236,12 +234,16 @@
         memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));
     }
 
+    buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded);
+    size -= sizeNeeded;
+    fds += handle->numFds;
+    count -= handle->numFds;
+
     return NO_ERROR;
 }
 
-status_t GraphicBuffer::unflatten(void const* buffer, size_t size,
-        int fds[], size_t count)
-{
+status_t GraphicBuffer::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
     if (size < 8*sizeof(int)) return NO_MEMORY;
 
     int const* buf = static_cast<int const*>(buffer);
@@ -287,6 +289,11 @@
         }
     }
 
+    buffer = reinterpret_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded);
+    size -= sizeNeeded;
+    fds += numFds;
+    count -= numFds;
+
     return NO_ERROR;
 }
 
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 623f8ed..e5abcf5 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -715,14 +715,17 @@
 
 // ----------------------------------------------------------------------------
 
-size_t Region::getSize() const {
+size_t Region::getFlattenedSize() const {
     return mStorage.size() * sizeof(Rect);
 }
 
-status_t Region::flatten(void* buffer) const {
+status_t Region::flatten(void* buffer, size_t size) const {
 #if VALIDATE_REGIONS
     validate(*this, "Region::flatten");
 #endif
+    if (size < mStorage.size() * sizeof(Rect)) {
+        return NO_MEMORY;
+    }
     Rect* rects = reinterpret_cast<Rect*>(buffer);
     memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
     return NO_ERROR;
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 1607267..b0798a1 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -253,8 +253,7 @@
             return;
         }
 
-        status_t err = mBlobCache->flatten(buf + headerSize, cacheSize, NULL,
-                0);
+        status_t err = mBlobCache->flatten(buf + headerSize, cacheSize);
         if (err != OK) {
             ALOGE("error writing cache contents: %s (%d)", strerror(-err),
                     -err);
@@ -335,8 +334,7 @@
             return;
         }
 
-        status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize, NULL,
-                0);
+        status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize);
         if (err != OK) {
             ALOGE("error reading cache contents: %s (%d)", strerror(-err),
                     -err);