Merge "Track camera and flashlight usage in battery stats." into mnc-dev
diff --git a/include/android/configuration.h b/include/android/configuration.h
index be00066..7573cca 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -78,6 +78,10 @@
     ACONFIGURATION_SCREENLONG_NO = 0x1,
     ACONFIGURATION_SCREENLONG_YES = 0x2,
 
+    ACONFIGURATION_SCREENROUND_ANY = 0x00,
+    ACONFIGURATION_SCREENROUND_NO = 0x1,
+    ACONFIGURATION_SCREENROUND_YES = 0x2,
+
     ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
     ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01,
     ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02,
@@ -115,6 +119,7 @@
     ACONFIGURATION_UI_MODE = 0x1000,
     ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000,
     ACONFIGURATION_LAYOUTDIR = 0x4000,
+    ACONFIGURATION_SCREEN_ROUND = 0x8000,
 
     ACONFIGURATION_MNC_ZERO = 0xffff,
 };
@@ -288,6 +293,16 @@
 void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
 
 /**
+ * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenRound(AConfiguration* config);
+
+/**
+ * Set the current screen round in the configuration.
+ */
+void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound);
+
+/**
  * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration.
  */
 int32_t AConfiguration_getUiModeType(AConfiguration* config);
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index 000ef0e..145efe6 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -72,7 +72,13 @@
     // to set by queueBuffer each time this slot is queued. This value
     // is guaranteed to be monotonically increasing for each newly
     // acquired buffer.
-    int64_t mTimestamp;
+    union {
+        int64_t mTimestamp;
+        struct {
+            uint32_t mTimestampLo;
+            uint32_t mTimestampHi;
+        };
+    };
 
     // mIsAutoTimestamp indicates whether mTimestamp was generated
     // automatically when the buffer was queued.
@@ -84,7 +90,13 @@
     android_dataspace mDataSpace;
 
     // mFrameNumber is the number of the queued frame for this slot.
-    uint64_t mFrameNumber;
+    union {
+        uint64_t mFrameNumber;
+        struct {
+            uint32_t mFrameNumberLo;
+            uint32_t mFrameNumberHi;
+        };
+    };
 
     union {
         // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 930fabf..56c7a3f 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -86,21 +86,6 @@
     status_t releaseBuffer(const BufferItem &item,
             const sp<Fence>& releaseFence = Fence::NO_FENCE);
 
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // requestBuffers when a with and height of zero is requested.
-    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
-
-    // setDefaultBufferFormat allows the BufferQueue to create
-    // GraphicBuffers of a defaultFormat if no format is specified
-    // in dequeueBuffer
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-
-    // setDefaultBufferDataSpace allows the BufferQueue to create
-    // GraphicBuffers of a defaultDataSpace if no data space is specified
-    // in queueBuffer.
-    // The initial default is HAL_DATASPACE_UNKNOWN
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
-
 };
 
 } // namespace android
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 46c603d..9307a26 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -76,6 +76,15 @@
     // See IGraphicBufferConsumer::detachBuffer
     status_t detachBuffer(int slot);
 
+    // See IGraphicBufferConsumer::setDefaultBufferSize
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+    // See IGraphicBufferConsumer::setDefaultBufferFormat
+    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
+
+    // See IGraphicBufferConsumer::setDefaultBufferDataSpace
+    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
+
 private:
     ConsumerBase(const ConsumerBase&);
     void operator=(const ConsumerBase&);
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index c99ab29..3b07a31 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -80,23 +80,6 @@
     // log messages.
     void setName(const String8& name);
 
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // requestBuffers when a width and height of zero is requested.
-    // A call to setDefaultBufferSize() may trigger requestBuffers() to
-    // be called from the client. Default size is 1x1.
-    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
-
-    // setDefaultBufferFormat allows CpuConsumer's BufferQueue to create buffers
-    // of a defaultFormat if no format is specified by producer.
-    // The initial default is PIXEL_FORMAT_RGBA_8888.
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-
-    // setDefaultBufferDataSpace allows the BufferQueue to create
-    // GraphicBuffers of a defaultDataSpace if no data space is specified
-    // in queueBuffer.
-    // The initial default is HAL_DATASPACE_UNKNOWN
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
-
     // Gets the next graphics buffer from the producer and locks it for CPU use,
     // filling out the passed-in locked buffer structure with the native pointer
     // and metadata. Returns BAD_VALUE if no new buffer is available, and
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 015866b..c1cfb1e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -451,7 +451,7 @@
     // Count objects in range
     for (int i = 0; i < (int) size; i++) {
         size_t off = objects[i];
-        if ((off >= offset) && (off < offset + len)) {
+        if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) {
             if (firstIndex == -1) {
                 firstIndex = i;
             }
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 5793d40..8f64ae0 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -46,15 +46,16 @@
 }
 
 size_t BufferItem::getPodSize() const {
-    // Must align<8> before writing these fields for this to be correct
     size_t size = 0;
     addAligned(size, mCrop);
     addAligned(size, mTransform);
     addAligned(size, mScalingMode);
-    addAligned(size, mTimestamp);
+    addAligned(size, mTimestampLo);
+    addAligned(size, mTimestampHi);
     addAligned(size, mIsAutoTimestamp);
     addAligned(size, mDataSpace);
-    addAligned(size, mFrameNumber);
+    addAligned(size, mFrameNumberLo);
+    addAligned(size, mFrameNumberHi);
     addAligned(size, mSlot);
     addAligned(size, mIsDroppable);
     addAligned(size, mAcquireCalled);
@@ -126,9 +127,6 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
-    // Must align<8> so that getPodSize returns the correct value
-    size -= FlattenableUtils::align<8>(buffer);
-
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -137,10 +135,12 @@
     writeAligned(buffer, size, mCrop);
     writeAligned(buffer, size, mTransform);
     writeAligned(buffer, size, mScalingMode);
-    writeAligned(buffer, size, mTimestamp);
+    writeAligned(buffer, size, mTimestampLo);
+    writeAligned(buffer, size, mTimestampHi);
     writeAligned(buffer, size, mIsAutoTimestamp);
     writeAligned(buffer, size, mDataSpace);
-    writeAligned(buffer, size, mFrameNumber);
+    writeAligned(buffer, size, mFrameNumberLo);
+    writeAligned(buffer, size, mFrameNumberHi);
     writeAligned(buffer, size, mSlot);
     writeAligned(buffer, size, mIsDroppable);
     writeAligned(buffer, size, mAcquireCalled);
@@ -183,9 +183,6 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
-    // Must align<8> so that getPodSize returns the correct value
-    size -= FlattenableUtils::align<8>(buffer);
-
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -194,10 +191,12 @@
     readAligned(buffer, size, mCrop);
     readAligned(buffer, size, mTransform);
     readAligned(buffer, size, mScalingMode);
-    readAligned(buffer, size, mTimestamp);
+    readAligned(buffer, size, mTimestampLo);
+    readAligned(buffer, size, mTimestampHi);
     readAligned(buffer, size, mIsAutoTimestamp);
     readAligned(buffer, size, mDataSpace);
-    readAligned(buffer, size, mFrameNumber);
+    readAligned(buffer, size, mFrameNumberLo);
+    readAligned(buffer, size, mFrameNumberHi);
     readAligned(buffer, size, mSlot);
     readAligned(buffer, size, mIsDroppable);
     readAligned(buffer, size, mAcquireCalled);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 194121f..578b8d9 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -100,20 +100,4 @@
     return err;
 }
 
-status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferSize(w, h);
-}
-
-status_t BufferItemConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t BufferItemConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace) {
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 } // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 2cf7433..e318484 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -914,8 +914,8 @@
                     mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
                     listener = mCore->mConsumerListener;
-                } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-                    BQ_LOGE("disconnect(P): still connected to another API "
+                } else {
+                    BQ_LOGE("disconnect(P): connected to another API "
                             "(cur=%d req=%d)", mCore->mConnectedApi, api);
                     status = BAD_VALUE;
                 }
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 0e42daf..04ab06b 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -198,6 +198,22 @@
     return result;
 }
 
+status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferSize(width, height);
+}
+
+status_t ConsumerBase::setDefaultBufferFormat(PixelFormat defaultFormat) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferFormat(defaultFormat);
+}
+
+status_t ConsumerBase::setDefaultBufferDataSpace(
+        android_dataspace defaultDataSpace) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
+}
+
 void ConsumerBase::dump(String8& result) const {
     dump(result, "");
 }
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index eb39469..e29b740 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -56,25 +56,6 @@
     mConsumer->setConsumerName(name);
 }
 
-status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height)
-{
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferSize(width, height);
-}
-
-status_t CpuConsumer::setDefaultBufferFormat(PixelFormat defaultFormat)
-{
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t CpuConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace)
-{
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 static bool isPossiblyYUV(PixelFormat format) {
     switch (static_cast<int>(format)) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index 09b63a1..3009989 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -59,6 +59,9 @@
         if (result == NO_ERROR) {
             graphicBuffer = new GraphicBuffer();
             result = reply.read(*graphicBuffer);
+            if (result != NO_ERROR) {
+                graphicBuffer.clear();
+            }
             // reply.readStrongBinder();
             // here we don't even have to read the BufferReference from
             // the parcel, it'll die with the parcel.
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 35aa7c7..04ac0f4 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -335,10 +335,14 @@
         // the origin being in the bottom-left corner. Here we flip to the
         // convention that the rest of the system uses (top-left corner) by
         // subtracting all top/bottom coordinates from the buffer height.
+        int height = buffer->height;
+        if ((mTransform ^ mStickyTransform) & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+            height = buffer->width;
+        }
         Region flippedRegion;
         for (auto rect : mDirtyRegion) {
-            auto top = buffer->height - rect.bottom;
-            auto bottom = buffer->height - rect.top;
+            auto top = height - rect.bottom;
+            auto bottom = height - rect.top;
             Rect flippedRect{rect.left, top, rect.right, bottom};
             flippedRegion.orSelf(flippedRect);
         }
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index ff58420..4ef9a69 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -299,7 +299,7 @@
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // One past the end of the last 'query' enum value. Update this if we add more enums.
-    const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_DEFAULT_DATASPACE + 1;
+    const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1;
 
     int value;
     // What was out of range
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d750cd0..1a50b24 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -27,6 +27,9 @@
 #include <utils/Log.h>
 #include <utils/Thread.h>
 
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+#define CROP_EXT_STR "EGL_ANDROID_image_crop"
+
 namespace android {
 
 class SurfaceTextureClientTest : public ::testing::Test {
@@ -615,6 +618,18 @@
 }
 
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+    // Query to see if the image crop extension exists
+    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
+    size_t cropExtLen = strlen(CROP_EXT_STR);
+    size_t extsLen = strlen(exts);
+    bool equal = !strcmp(CROP_EXT_STR, exts);
+    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
+    bool atEnd = (cropExtLen+1) < extsLen &&
+            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
+    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
+    bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
+
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
     android_native_rect_t crop;
@@ -633,15 +648,17 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // This accounts for the .5 texel shrink for each edge that's included in the
-    // transform matrix to avoid texturing outside the crop region.
-    EXPECT_EQ(0.5, mtx[0]);
+    // If the egl image crop extension is not present, this accounts for the
+    // .5 texel shrink for each edge that's included in the transform matrix
+    // to avoid texturing outside the crop region. Otherwise the crop is not
+    // included in the transform matrix.
+    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(-0.5, mtx[5]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -650,8 +667,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(0.0625f, mtx[12]);
-    EXPECT_EQ(0.5625f, mtx[13]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index f4c7961..6edbfb8 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -188,10 +188,10 @@
     // This test should have the only reference to buffer 0.
     EXPECT_EQ(1, buffers[0]->getStrongCount());
 
-    // The GLConsumer should hold a single reference to buffer 1 in its
-    // mCurrentBuffer member.  All of the references in the slots should have
-    // been released.
-    EXPECT_EQ(2, buffers[1]->getStrongCount());
+    // The GLConsumer should hold one reference to buffer 1 in its
+    // mCurrentTextureImage member and another reference in mEglSlots. The third
+    // reference is in this test.
+    EXPECT_EQ(3, buffers[1]->getStrongCount());
 }
 
 TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
@@ -235,14 +235,19 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
     mProducerEglSurface = EGL_NO_SURFACE;
 
-    EXPECT_EQ(1, buffers[0]->getStrongCount());
     EXPECT_EQ(1, buffers[1]->getStrongCount());
 
     // Depending on how lazily the GL driver dequeues buffers, we may end up
-    // with either two or three total buffers.  If there are three, make sure
-    // the last one was properly down-ref'd.
+    // with either two or three total buffers.  If there are three, each entry
+    // of the buffers array will be unique and there should only be one
+    // reference (the one in this test). If there are two the first and last
+    // element in the array will be equal meaning that buffer representing both
+    // 0 and 2 will have two references (one for 0 and one for 2).
     if (buffers[2] != buffers[0]) {
+        EXPECT_EQ(1, buffers[0]->getStrongCount());
         EXPECT_EQ(1, buffers[2]->getStrongCount());
+    } else {
+        EXPECT_EQ(2, buffers[0]->getStrongCount());
     }
 }
 
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 85e9675..9b265af 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -104,6 +104,9 @@
     // we have a h/w allocator and h/w buffer is requested
     status_t err;
 
+    // Filter out any usage bits that should not be passed to the gralloc module
+    usage &= GRALLOC_USAGE_ALLOC_MASK;
+
     int outStride = 0;
     err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
             static_cast<int>(height), format, static_cast<int>(usage), handle,
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 1feac8b..593d0c2 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -394,7 +394,13 @@
         depth.width   = width;
         depth.height  = height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            return setError(EGL_BAD_ALLOC, EGL_FALSE);
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             return setError(EGL_BAD_ALLOC, EGL_FALSE);
         }
@@ -548,7 +554,14 @@
                 depth.width   = width;
                 depth.height  = height;
                 depth.stride  = buffer->stride;
-                depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+                uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                        static_cast<uint64_t>(depth.height) * 2;
+                if (depth.stride < 0 || depth.height > INT_MAX ||
+                        allocSize > UINT32_MAX) {
+                    setError(EGL_BAD_ALLOC, EGL_FALSE);
+                    return EGL_FALSE;
+                }
+                depth.data    = (GGLubyte*)malloc(allocSize);
                 if (depth.data == 0) {
                     setError(EGL_BAD_ALLOC, EGL_FALSE);
                     return EGL_FALSE;
@@ -666,7 +679,14 @@
         depth.width   = pixmap->width;
         depth.height  = pixmap->height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
@@ -746,7 +766,14 @@
         depth.width   = pbuffer.width;
         depth.height  = pbuffer.height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
             return;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 7c70fa0..4e0e5bc 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -292,6 +292,44 @@
     return (const GLubyte *)c->gl_extensions.string();
 }
 
+const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
+    // NOTE: returning NULL here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return NULL;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return NULL;
+
+    if (name != GL_EXTENSIONS)
+        return NULL;
+
+    // if index is out of bounds, assume it will be in the default
+    // implementation too, so we don't have to generate a GL error here
+    if (index >= c->tokenized_gl_extensions.size())
+        return NULL;
+
+    return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string();
+}
+
+GLint egl_get_num_extensions_for_current_context() {
+    // NOTE: returning -1 here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return -1;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return -1;
+
+    return (GLint)c->tokenized_gl_extensions.size();
+}
+
 // ----------------------------------------------------------------------------
 
 // this mutex protects:
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 8dd052c..5444631 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -562,15 +562,6 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t * const s = get_surface(surface);
-    ANativeWindow* window = s->win.get();
-    if (window) {
-        int result = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-        if (result != OK) {
-            ALOGE("eglDestroySurface: native_window_api_disconnect (win=%p) "
-                  "failed (%#x)",
-                  window, result);
-        }
-    }
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index d3ee76d..d511940 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -113,6 +113,18 @@
             temp.append(gl_extensions);
             gl_extensions.setTo(temp);
         }
+
+        // tokenize the supported extensions for the glGetStringi() wrapper
+        exts = gl_extensions.string();
+        while (1) {
+            const char *end = strchr(exts, ' ');
+            if (end == NULL) {
+                tokenized_gl_extensions.push(String8(exts));
+                break;
+            }
+            tokenized_gl_extensions.push(String8(exts, end - exts));
+            exts = end + 1;
+        }
     }
 }
 
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 518fdec..f5a9f58 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -27,6 +27,7 @@
 
 #include <utils/threads.h>
 #include <utils/String8.h>
+#include <utils/Vector.h>
 
 #include <system/window.h>
 
@@ -159,6 +160,7 @@
     egl_connection_t const* cnx;
     int version;
     String8 gl_extensions;
+    Vector<String8> tokenized_gl_extensions;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index d5dc012..6034a8e 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -205,13 +205,22 @@
 #undef CALL_GL_API_RETURN
 
 /*
- * glGetString() is special because we expose some extensions in the wrapper
+ * glGetString() and glGetStringi() are special because we expose some
+ * extensions in the wrapper. Also, wrapping glGetXXX() is required because
+ * the value returned for GL_NUM_EXTENSIONS may have been altered by the
+ * injection of the additional extensions.
  */
 
-extern "C" const GLubyte * __glGetString(GLenum name);
+extern "C" {
+    const GLubyte * __glGetString(GLenum name);
+    const GLubyte * __glGetStringi(GLenum name, GLuint index);
+    void __glGetBooleanv(GLenum pname, GLboolean * data);
+    void __glGetFloatv(GLenum pname, GLfloat * data);
+    void __glGetIntegerv(GLenum pname, GLint * data);
+    void __glGetInteger64v(GLenum pname, GLint64 * data);
+}
 
-const GLubyte * glGetString(GLenum name)
-{
+const GLubyte * glGetString(GLenum name) {
     const GLubyte * ret = egl_get_string_for_current_context(name);
     if (ret == NULL) {
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
@@ -219,3 +228,64 @@
     }
     return ret;
 }
+
+const GLubyte * glGetStringi(GLenum name, GLuint index) {
+    const GLubyte * ret = egl_get_string_for_current_context(name, index);
+    if (ret == NULL) {
+        gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+        if(_c) ret = _c->glGetStringi(name, index);
+    }
+    return ret;
+}
+
+void glGetBooleanv(GLenum pname, GLboolean * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = num_exts > 0 ? GL_TRUE : GL_FALSE;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetBooleanv(pname, data);
+}
+
+void glGetFloatv(GLenum pname, GLfloat * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLfloat)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetFloatv(pname, data);
+}
+
+void glGetIntegerv(GLenum pname, GLint * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLint)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetIntegerv(pname, data);
+}
+
+void glGetInteger64v(GLenum pname, GLint64 * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLint64)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetInteger64v(pname, data);
+}
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
index 8363960..09d8b00 100644
--- a/opengl/libs/GLES2/gl2_api.in
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -172,7 +172,7 @@
 GLint API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar * name) {
     CALL_GL_API_RETURN(glGetAttribLocation, program, name);
 }
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean * data) {
+void API_ENTRY(__glGetBooleanv)(GLenum pname, GLboolean * data) {
     CALL_GL_API(glGetBooleanv, pname, data);
 }
 void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint * params) {
@@ -181,13 +181,13 @@
 GLenum API_ENTRY(glGetError)(void) {
     CALL_GL_API_RETURN(glGetError);
 }
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat * data) {
+void API_ENTRY(__glGetFloatv)(GLenum pname, GLfloat * data) {
     CALL_GL_API(glGetFloatv, pname, data);
 }
 void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint * params) {
     CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
 }
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint * data) {
+void API_ENTRY(__glGetIntegerv)(GLenum pname, GLint * data) {
     CALL_GL_API(glGetIntegerv, pname, data);
 }
 void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint * params) {
@@ -604,7 +604,7 @@
 void API_ENTRY(glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
     CALL_GL_API(glClearBufferfi, buffer, drawbuffer, depth, stencil);
 }
-const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) {
+const GLubyte * API_ENTRY(__glGetStringi)(GLenum name, GLuint index) {
     CALL_GL_API_RETURN(glGetStringi, name, index);
 }
 void API_ENTRY(glCopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
@@ -649,7 +649,7 @@
 void API_ENTRY(glWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) {
     CALL_GL_API(glWaitSync, sync, flags, timeout);
 }
-void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 * data) {
+void API_ENTRY(__glGetInteger64v)(GLenum pname, GLint64 * data) {
     CALL_GL_API(glGetInteger64v, pname, data);
 }
 void API_ENTRY(glGetSynciv)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * values) {
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index cb0e908..c0990ec 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -30,6 +30,9 @@
 // ----------------------------------------------------------------------------
 
 EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
+EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name,
+                                                          GLuint index);
+EGLAPI GLint egl_get_num_extensions_for_current_context();
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py
index ed6b451..9b30fd1 100755
--- a/opengl/tools/glgen2/glgen.py
+++ b/opengl/tools/glgen2/glgen.py
@@ -86,11 +86,25 @@
     return ', '.join(['"%s", %s' % (p[0], p[1]) for p in params])
 
 
-def overrideSymbolName(sym):
-    # The wrapper intercepts glGetString and (sometimes) calls the generated
-    # __glGetString thunk which dispatches to the driver's glGetString
-    if sym == 'glGetString':
-        return '__glGetString'
+def overrideSymbolName(sym, apiname):
+    # The wrapper intercepts various glGet and glGetString functions and
+    # (sometimes) calls the generated thunk which dispatches to the
+    # driver's implementation
+    wrapped_get_syms = {
+        'gles1' : [
+            'glGetString'
+        ],
+        'gles2' : [
+            'glGetString',
+            'glGetStringi',
+            'glGetBooleanv',
+            'glGetFloatv',
+            'glGetIntegerv',
+            'glGetInteger64v',
+        ],
+    }
+    if sym in wrapped_get_syms.get(apiname):
+        return '__' + sym
     else:
         return sym
 
@@ -115,8 +129,8 @@
         print('%s API_ENTRY(%s)(%s) {\n'
               '    %s(%s%s%s);\n'
               '}'
-              % (rtype, overrideSymbolName(fname), fmtParams(params),
-                 call, fname,
+              % (rtype, overrideSymbolName(fname, self.genOpts.apiname),
+                 fmtParams(params), call, fname,
                  ', ' if len(params) > 0 else '',
                  fmtArgs(params)),
               file=self.outFile)
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 96efc34..67142b6 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -139,7 +139,7 @@
     enum { MAX_RESYNC_SAMPLES = 32 };
     enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
     enum { NUM_PRESENT_SAMPLES = 8 };
-    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 };
+    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
 
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 579b39e..02c31ff 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -305,13 +305,16 @@
 }
 
 void HWComposer::hotplug(int disp, int connected) {
-    if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) {
+    if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
         ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
                 disp, connected);
         return;
     }
     queryDisplayProperties(disp);
-    mEventHandler.onHotplugReceived(disp, bool(connected));
+    // Do not teardown or recreate the primary display
+    if (disp != HWC_DISPLAY_PRIMARY) {
+        mEventHandler.onHotplugReceived(disp, bool(connected));
+    }
 }
 
 static float getDefaultDensity(uint32_t width, uint32_t height) {
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 1adcd1f..0dab872 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -88,5 +88,9 @@
     mColorMatrixEnabled = (mtx != identity);
 }
 
+const mat4& Description::getColorMatrix() const {
+    return mColorMatrix;
+}
+
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 43b835f..8a3447c 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -66,6 +66,7 @@
     void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
+    const mat4& getColorMatrix() const;
 
 private:
     bool mUniformsDirty;
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 2e6af49..1a9f59b 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -262,14 +262,6 @@
     }
 }
 
-void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) {
-    // doesn't do anything in GLES 1.1
-}
-
-void GLES11RenderEngine::endGroup() {
-    // doesn't do anything in GLES 1.1
-}
-
 void GLES11RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 87eb3e4..08de646 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -62,9 +62,6 @@
 
     virtual void drawMesh(const Mesh& mesh);
 
-    virtual void beginGroup(const mat4& colorTransform);
-    virtual void endGroup();
-
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
 };
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 8712c9a..1fabaf5 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -169,6 +169,12 @@
     mState.setTexture(texture);
 }
 
+mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+    mat4 oldTransform = mState.getColorMatrix();
+    mState.setColorMatrix(colorTransform);
+    return oldTransform;
+}
+
 void GLES20RenderEngine::disableTexturing() {
     mState.disableTexture();
 }
@@ -237,78 +243,6 @@
     }
 }
 
-void GLES20RenderEngine::beginGroup(const mat4& colorTransform) {
-
-    GLuint tname, name;
-    // create the texture
-    glGenTextures(1, &tname);
-    glBindTexture(GL_TEXTURE_2D, tname);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
-    // create a Framebuffer Object to render into
-    glGenFramebuffers(1, &name);
-    glBindFramebuffer(GL_FRAMEBUFFER, name);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
-    Group group;
-    group.texture = tname;
-    group.fbo = name;
-    group.width = mVpWidth;
-    group.height = mVpHeight;
-    group.colorTransform = colorTransform;
-
-    mGroupStack.push(group);
-}
-
-void GLES20RenderEngine::endGroup() {
-
-    const Group group(mGroupStack.top());
-    mGroupStack.pop();
-
-    // activate the previous render target
-    GLuint fbo = 0;
-    if (!mGroupStack.isEmpty()) {
-        fbo = mGroupStack.top().fbo;
-    }
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-
-    // set our state
-    Texture texture(Texture::TEXTURE_2D, group.texture);
-    texture.setDimensions(group.width, group.height);
-    glBindTexture(GL_TEXTURE_2D, group.texture);
-
-    mState.setPlaneAlpha(1.0f);
-    mState.setPremultipliedAlpha(true);
-    mState.setOpaque(false);
-    mState.setTexture(texture);
-    mState.setColorMatrix(group.colorTransform);
-    glDisable(GL_BLEND);
-
-    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
-    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>());
-    position[0] = vec2(0, 0);
-    position[1] = vec2(group.width, 0);
-    position[2] = vec2(group.width, group.height);
-    position[3] = vec2(0, group.height);
-    texCoord[0] = vec2(0, 0);
-    texCoord[1] = vec2(1, 0);
-    texCoord[2] = vec2(1, 1);
-    texCoord[3] = vec2(0, 1);
-    drawMesh(mesh);
-
-    // reset color matrix
-    mState.setColorMatrix(mat4());
-
-    // free our fbo and texture
-    glDeleteFramebuffers(1, &group.fbo);
-    glDeleteTextures(1, &group.texture);
-}
-
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 3d6243e..819356a 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,14 +72,12 @@
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
     virtual void setupFillWithColor(float r, float g, float b, float a);
+    virtual mat4 setupColorTransform(const mat4& colorTransform);
     virtual void disableTexturing();
     virtual void disableBlending();
 
     virtual void drawMesh(const Mesh& mesh);
 
-    virtual void beginGroup(const mat4& colorTransform);
-    virtual void endGroup();
-
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
 };
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8d7529c..31a961e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -99,18 +99,16 @@
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
 
+    virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
+        return mat4();
+    }
+
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
-    // grouping
-    // creates a color-transform group, everything drawn in the group will be
-    // transformed by the given color transform when endGroup() is called.
-    virtual void beginGroup(const mat4& colorTransform) = 0;
-    virtual void endGroup() = 0;
-
     // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0d57ae5..1388ce8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1872,9 +1872,9 @@
         if (mDaltonize) {
             colorMatrix = colorMatrix * mDaltonizer();
         }
-        engine.beginGroup(colorMatrix);
+        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
         doComposeSurfaces(hw, dirtyRegion);
-        engine.endGroup();
+        engine.setupColorTransform(oldMatrix);
     }
 
     // update the swap region and clear the dirty region
@@ -3337,8 +3337,8 @@
     sp<Surface> sur = new Surface(producer, false);
     ANativeWindow* window = sur.get();
 
-    status_t result = NO_ERROR;
-    if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) {
+    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+    if (result == NO_ERROR) {
         uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
                         GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
 
@@ -3428,7 +3428,7 @@
                     result = BAD_VALUE;
                 }
                 // queueBuffer takes ownership of syncFd
-                window->queueBuffer(window, buffer, syncFd);
+                result = window->queueBuffer(window, buffer, syncFd);
             }
         } else {
             result = BAD_VALUE;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4d363c8..dcde512 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include <android/native_window.h>
+
 #include <binder/IMemory.h>
 
 #include <gui/ISurfaceComposer.h>
@@ -53,21 +55,23 @@
 class ScreenCapture : public RefBase {
 public:
     static void captureScreen(sp<ScreenCapture>* sc) {
-        sp<IMemoryHeap> heap;
-        uint32_t w=0, h=0;
-        PixelFormat fmt=0;
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-        ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0,
-                0, INT_MAX));
-        ASSERT_TRUE(heap != NULL);
-        ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
-        *sc = new ScreenCapture(w, h, heap);
+        sp<IBinder> display(sf->getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+        ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
+                0, INT_MAX, false));
+        *sc = new ScreenCapture(cpuConsumer);
     }
 
     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
-        const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
-        const uint8_t* pixel = img + (4 * (y*mWidth + x));
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format);
+        const uint8_t* img = static_cast<const uint8_t*>(mBuf.data);
+        const uint8_t* pixel = img + (4 * (y * mBuf.stride + x));
         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
             String8 err(String8::format("pixel @ (%3d, %3d): "
                     "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
@@ -77,15 +81,17 @@
     }
 
 private:
-    ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
-        mWidth(w),
-        mHeight(h),
-        mHeap(heap)
-    {}
+    ScreenCapture(const sp<CpuConsumer>& cc) :
+        mCC(cc) {
+        EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf));
+    }
 
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    sp<IMemoryHeap> mHeap;
+    ~ScreenCapture() {
+        mCC->unlockBuffer(mBuf);
+    }
+
+    sp<CpuConsumer> mCC;
+    CpuConsumer::LockedBuffer mBuf;
 };
 
 class LayerUpdateTest : public ::testing::Test {