am 8b435c07: am 7b2b968d: am 33c3c1bd: Merge "Revert "do not dumpstate raft BUG: 24159112"" into cw-e-dev

* commit '8b435c07eece971ab032d450777e0e1723299de1':
  Revert "do not dumpstate raft BUG: 24159112"
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 3155766..ddf3aa8 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -207,7 +207,7 @@
     sp<GLConsumer> glc = new GLConsumer(consumer, name,
             GL_TEXTURE_EXTERNAL_OES, false, true);
     glc->setDefaultBufferSize(w, h);
-    glc->setDefaultMaxBufferCount(3);
+    producer->setMaxDequeuedBufferCount(2);
     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
 
     sp<ANativeWindow> anw = new Surface(producer);
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index e73516d..7154fab 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -7,4 +7,5 @@
     onrestart restart zygote
     onrestart restart media
     onrestart restart surfaceflinger
+    onrestart restart inputflinger
     onrestart restart drm
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 421abe5..ac07190 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -732,9 +732,23 @@
     AKEYCODE_STEM_2 = 266,
     /** Generic stem key 3 for Wear */
     AKEYCODE_STEM_3 = 267,
+    /** Directional Pad Up-Left */
+    AKEYCODE_DPAD_UP_LEFT    = 268,
+    /** Directional Pad Down-Left */
+    AKEYCODE_DPAD_DOWN_LEFT  = 269,
+    /** Directional Pad Up-Right */
+    AKEYCODE_DPAD_UP_RIGHT   = 270,
+    /** Directional Pad Down-Right */
+    AKEYCODE_DPAD_DOWN_RIGHT = 271,
+    /** Skip forward media key */
     AKEYCODE_MEDIA_SKIP_FORWARD = 272,
+    /** Skip backward media key */
     AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
+    /** Step forward media key.
+     * Steps media forward one from at a time. */
     AKEYCODE_MEDIA_STEP_FORWARD = 274,
+    /** Step backward media key.
+     * Steps media backward one from at a time. */
     AKEYCODE_MEDIA_STEP_BACKWARD = 275,
     /** Put device to sleep unless a wakelock is held. */
     AKEYCODE_SOFT_SLEEP = 276
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index 145efe6..504ac64 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -98,13 +98,8 @@
         };
     };
 
-    union {
-        // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
-        int mSlot;
-
-        // mBuf is the former name for mSlot
-        int mBuf;
-    };
+    // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
+    int mSlot;
 
     // mIsDroppable whether this buffer was queued with the
     // property that it can be replaced by a new buffer for the purpose of
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index cde302f..b2daae4 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -100,20 +100,8 @@
     // is 1x1.
     virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height);
 
-    // setDefaultMaxBufferCount sets the default value for the maximum buffer
-    // count (the initial default is 2). If the producer has requested a
-    // buffer count using setBufferCount, the default buffer count will only
-    // take effect if the producer sets the count back to zero.
-    //
-    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
-    virtual status_t setDefaultMaxBufferCount(int bufferCount);
-
-    // disableAsyncBuffer disables the extra buffer used in async mode
-    // (when both producer and consumer have set their "isControlledByApp"
-    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
-    //
-    // This can only be called before connect().
-    virtual status_t disableAsyncBuffer();
+    // see IGraphicBufferConsumer::setMaxBufferCount
+    virtual status_t setMaxBufferCount(int bufferCount);
 
     // setMaxAcquiredBufferCount sets the maximum number of buffers that can
     // be acquired by the consumer at one time (default 1).  This call will
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 99134ea..36cd238 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -85,31 +85,25 @@
     // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
     // that must remain in a state other than DEQUEUED. The async parameter
     // tells whether we're in asynchronous mode.
-    int getMinUndequeuedBufferCountLocked(bool async) const;
+    int getMinUndequeuedBufferCountLocked() const;
 
     // getMinMaxBufferCountLocked returns the minimum number of buffers allowed
     // given the current BufferQueue state. The async parameter tells whether
     // we're in asynchonous mode.
-    int getMinMaxBufferCountLocked(bool async) const;
+    int getMinMaxBufferCountLocked() const;
 
     // getMaxBufferCountLocked returns the maximum number of buffers that can be
     // allocated at once. This value depends on the following member variables:
     //
-    //     mDequeueBufferCannotBlock
+    //     mMaxDequeuedBufferCount
     //     mMaxAcquiredBufferCount
-    //     mDefaultMaxBufferCount
-    //     mOverrideMaxBufferCount
-    //     async parameter
+    //     mMaxBufferCount
+    //     mAsyncMode
+    //     mDequeueBufferCannotBlock
     //
     // Any time one of these member variables is changed while a producer is
     // connected, mDequeueCondition must be broadcast.
-    int getMaxBufferCountLocked(bool async) const;
-
-    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
-    // that will be used if the producer does not override the buffer slot
-    // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The
-    // initial default is 2.
-    status_t setDefaultMaxBufferCountLocked(int count);
+    int getMaxBufferCountLocked() const;
 
     // freeBufferLocked frees the GraphicBuffer and sync resources for the
     // given slot.
@@ -192,21 +186,10 @@
     // a buffer attached
     std::list<int> mFreeBuffers;
 
-    // mOverrideMaxBufferCount is the limit on the number of buffers that will
-    // be allocated at one time. This value is set by the producer by calling
-    // setBufferCount. The default is 0, which means that the producer doesn't
-    // care about the number of buffers in the pool. In that case,
-    // mDefaultMaxBufferCount is used as the limit.
-    int mOverrideMaxBufferCount;
-
     // mDequeueCondition is a condition variable used for dequeueBuffer in
     // synchronous mode.
     mutable Condition mDequeueCondition;
 
-    // mUseAsyncBuffer indicates whether an extra buffer is used in async mode
-    // to prevent dequeueBuffer from blocking.
-    bool mUseAsyncBuffer;
-
     // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
     // block. This flag is set during connect when both the producer and
     // consumer are controlled by the application.
@@ -229,11 +212,9 @@
     // is specified.
     android_dataspace mDefaultBufferDataSpace;
 
-    // mDefaultMaxBufferCount is the default limit on the number of buffers that
-    // will be allocated at one time. This default limit is set by the consumer.
-    // The limit (as opposed to the default limit) may be overriden by the
-    // producer.
-    int mDefaultMaxBufferCount;
+    // mMaxBufferCount is the limit on the number of buffers that will be
+    // allocated at one time. This limit can be set by the consumer.
+    int mMaxBufferCount;
 
     // mMaxAcquiredBufferCount is the number of buffers that the consumer may
     // acquire at one time. It defaults to 1, and can be changed by the consumer
@@ -242,6 +223,11 @@
     // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.
     int mMaxAcquiredBufferCount;
 
+    // mMaxDequeuedBufferCount is the number of buffers that the producer may
+    // dequeue at one time. It defaults to 1, and can be changed by the producer
+    // via setMaxDequeuedBufferCount.
+    int mMaxDequeuedBufferCount;
+
     // mBufferHasBeenQueued is true once a buffer has been queued. It is reset
     // when something causes all buffers to be freed (e.g., changing the buffer
     // count).
@@ -280,6 +266,11 @@
     // number will fail.
     uint32_t mGenerationNumber;
 
+    // mAsyncMode indicates whether or not async mode is enabled.
+    // In async mode an extra buffer will be allocated to allow the producer to
+    // enqueue buffers without blocking.
+    bool mAsyncMode;
+
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 9754a89..6e16a60 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -39,22 +39,11 @@
     // flags indicating that previously-returned buffers are no longer valid.
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
 
-    // setBufferCount updates the number of available buffer slots.  If this
-    // method succeeds, buffer slots will be both unallocated and owned by
-    // the BufferQueue object (i.e. they are not owned by the producer or
-    // consumer).
-    //
-    // This will fail if the producer has dequeued any buffers, or if
-    // bufferCount is invalid.  bufferCount must generally be a value
-    // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS
-    // (inclusive).  It may also be set to zero (the default) to indicate
-    // that the producer does not wish to set a value.  The minimum value
-    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-    // ...).
-    //
-    // This may only be called by the producer.  The consumer will be told
-    // to discard buffers through the onBuffersReleased callback.
-    virtual status_t setBufferCount(int bufferCount);
+    // see IGraphicsBufferProducer::setMaxDequeuedBufferCount
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+
+    // see IGraphicsBufferProducer::setAsyncMode
+    virtual status_t setAsyncMode(bool async);
 
     // dequeueBuffer gets the next buffer slot index for the producer to use.
     // If a buffer slot is available then that slot index is written to the
@@ -92,7 +81,7 @@
     // In both cases, the producer will need to call requestBuffer to get a
     // GraphicBuffer handle for the returned slot.
     virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
-            bool async, uint32_t width, uint32_t height, PixelFormat format,
+            uint32_t width, uint32_t height, PixelFormat format,
             uint32_t usage);
 
     // See IGraphicBufferProducer::detachBuffer
@@ -128,7 +117,7 @@
     //
     // The buffer will not be overwritten until the fence signals.  The fence
     // will usually be the one obtained from dequeueBuffer.
-    virtual void cancelBuffer(int slot, const sp<Fence>& fence);
+    virtual status_t cancelBuffer(int slot, const sp<Fence>& fence);
 
     // Query native window attributes.  The "what" values are enumerated in
     // window.h (e.g. NATIVE_WINDOW_FORMAT).
@@ -169,7 +158,7 @@
     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
 
     // See IGraphicBufferProducer::allocateBuffers
-    virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
+    virtual void allocateBuffers(uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage);
 
     // See IGraphicBufferProducer::allowAllocation
@@ -190,8 +179,8 @@
     // mode (producer and consumer controlled by the application). If it blocks,
     // it will release mCore->mMutex while blocked so that other operations on
     // the BufferQueue may succeed.
-    status_t waitForFreeSlotThenRelock(const char* caller, bool async,
-            int* found, status_t* returnFlags) const;
+    status_t waitForFreeSlotThenRelock(const char* caller, int* found,
+            status_t* returnFlags) const;
 
     sp<BufferQueueCore> mCore;
 
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 3b07a31..f9d0e7d 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -67,6 +67,25 @@
         uint8_t    *dataCr;
         uint32_t    chromaStride;
         uint32_t    chromaStep;
+
+        LockedBuffer() :
+            data(NULL),
+            width(0),
+            height(0),
+            format(PIXEL_FORMAT_NONE),
+            stride(0),
+            crop(0, 0, 0, 0),
+            transform(0),
+            scalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+            timestamp(0),
+            dataSpace(HAL_DATASPACE_UNKNOWN),
+            frameNumber(0),
+            flexFormat(PIXEL_FORMAT_NONE),
+            dataCb(NULL),
+            dataCr(NULL),
+            chromaStride(0),
+            chromaStep(0)
+        {}
     };
 
     // Create a new CPU consumer. The maxLockedBuffers parameter specifies
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index c35c7be..0e4acee 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -112,11 +112,6 @@
     // union fence.
     void setReleaseFence(const sp<Fence>& fence);
 
-    // setDefaultMaxBufferCount sets the default limit on the maximum number
-    // of buffers that will be allocated at one time. The image producer may
-    // override the limit.
-    status_t setDefaultMaxBufferCount(int bufferCount);
-
     // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
     // associated with the texture image set by the most recent call to
     // updateTexImage.
@@ -201,6 +196,7 @@
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
     status_t setConsumerUsageBits(uint32_t usage);
     status_t setTransformHint(uint32_t hint);
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // detachFromContext detaches the GLConsumer from the calling thread's
     // current OpenGL ES context.  This context must be the same as the context
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 60ec9cc..d4c9ee5 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -188,32 +188,28 @@
     // * BAD_VALUE - either w or h was zero
     virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
 
-    // setDefaultMaxBufferCount sets the default value for the maximum buffer
-    // count (the initial default is 2). If the producer has requested a
-    // buffer count using setBufferCount, the default buffer count will only
-    // take effect if the producer sets the count back to zero.
+    // setMaxBufferCount sets the maximum value for the number of buffers used
+    // in the buffer queue (the initial default is NUM_BUFFER_SLOTS). If a call
+    // to setMaxAcquiredBufferCount (by the consumer), or a call to setAsyncMode
+    // or setMaxDequeuedBufferCount (by the producer), would cause this value to
+    // be exceeded then that call will fail. This call will fail if a producer
+    // is connected to the BufferQueue.
     //
-    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count
+    // cannot be less than maxAcquiredBufferCount.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - bufferCount was out of range (see above).
-    virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0;
-
-    // disableAsyncBuffer disables the extra buffer used in async mode
-    // (when both producer and consumer have set their "isControlledByApp"
-    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
-    //
-    // This can only be called before consumerConnect().
-    //
-    // Return of a value other than NO_ERROR means an error has occurred:
-    // * INVALID_OPERATION - attempting to call this after consumerConnect.
-    virtual status_t disableAsyncBuffer() = 0;
+    // * INVALID_OPERATION - attempting to call this after a producer connected.
+    virtual status_t setMaxBufferCount(int bufferCount) = 0;
 
     // setMaxAcquiredBufferCount sets the maximum number of buffers that can
     // be acquired by the consumer at one time (default 1).  This call will
     // fail if a producer is connected to the BufferQueue.
     //
-    // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS.
+    // maxAcquiredBuffers must be (inclusive) between 1 and
+    // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
+    // to be exceeded.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - maxAcquiredBuffers was out of range (see above).
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 9530de1..b8cba2f 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -74,33 +74,50 @@
     // The slot must be in the range of [0, NUM_BUFFER_SLOTS).
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
     // * BAD_VALUE - one of the two conditions occurred:
     //              * slot was out of range (see above)
     //              * buffer specified by the slot is not dequeued
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
 
-    // setBufferCount sets the number of buffer slots available. Calling this
-    // will also cause all buffer slots to be emptied. The caller should empty
-    // its mirrored copy of the buffer slots when calling this method.
+    // setMaxDequeuedBufferCount sets the maximum number of buffers that can be
+    // dequeued by the producer at one time. If this method succeeds, buffer
+    // slots will be both unallocated and owned by the BufferQueue object (i.e.
+    // they are not owned by the producer or consumer). Calling this will also
+    // cause all buffer slots to be emptied. If the caller is caching the
+    // contents of the buffer slots, it should empty that cache after calling
+    // this method.
     //
-    // This function should not be called when there are any dequeued buffer
-    // slots, doing so will result in a BAD_VALUE error returned.
+    // This function should not be called when there are any currently dequeued
+    // buffer slots. Doing so will result in a BAD_VALUE error.
     //
-    // The buffer count should be at most NUM_BUFFER_SLOTS (inclusive), but at least
-    // the minimum undequeued buffer count (exclusive). The minimum value
-    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS).
-    // In particular the range is (minUndequeudBuffers, NUM_BUFFER_SLOTS].
-    //
-    // The buffer count may also be set to 0 (the default), to indicate that
-    // the producer does not wish to set a value.
+    // The buffer count should be at least 1 (inclusive), but at most
+    // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
+    // minimum undequeued buffer count can be obtained by calling
+    // query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS).
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * NO_INIT - the buffer queue has been abandoned.
     // * BAD_VALUE - one of the below conditions occurred:
-    //              * bufferCount was out of range (see above)
-    //              * client has one or more buffers dequeued
-    virtual status_t setBufferCount(int bufferCount) = 0;
+    //     * bufferCount was out of range (see above)
+    //     * client has one or more buffers dequeued
+    //     * this call would cause the maxBufferCount value to be exceeded
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
+
+    // Set the async flag if the producer intends to asynchronously queue
+    // buffers without blocking. Typically this is used for triple-buffering
+    // and/or when the swap interval is set to zero.
+    //
+    // Enabling async mode will internally allocate an additional buffer to
+    // allow for the asynchronous behavior. If it is not enabled queue/dequeue
+    // calls may block.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned.
+    // * BAD_VALUE - this call would cause the maxBufferCount value to be
+    //               exceeded
+    virtual status_t setAsyncMode(bool async) = 0;
 
     // dequeueBuffer requests a new buffer slot for the client to use. Ownership
     // of the slot is transfered to the client, meaning that the server will not
@@ -126,9 +143,6 @@
     // fence signals. If the fence is Fence::NO_FENCE, the buffer may be written
     // immediately.
     //
-    // The async parameter sets whether we're in asynchronous mode for this
-    // dequeueBuffer() call.
-    //
     // The width and height parameters must be no greater than the minimum of
     // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
     // An error due to invalid dimensions might not be reported until
@@ -150,7 +164,8 @@
     // success.
     //
     // Return of a negative means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
     // * BAD_VALUE - both in async mode and buffer count was less than the
     //               max numbers of buffers that can be allocated at once.
     // * INVALID_OPERATION - cannot attach the buffer because it would cause
@@ -165,8 +180,8 @@
     //
     // All other negative values are an unknown error returned downstream
     // from the graphics allocator (typically errno).
-    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
-            uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) = 0;
+    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+            uint32_t h, PixelFormat format, uint32_t usage) = 0;
 
     // detachBuffer attempts to remove all ownership of the buffer in the given
     // slot from the buffer queue. If this call succeeds, the slot will be
@@ -178,7 +193,8 @@
     // requestBuffer).
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
     // * BAD_VALUE - the given slot number is invalid, either because it is
     //               out of the range [0, NUM_BUFFER_SLOTS), or because the slot
     //               it refers to is not currently dequeued and requested.
@@ -198,7 +214,8 @@
     // equivalent to fence from the dequeueBuffer call.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
     // * BAD_VALUE - either outBuffer or outFence were NULL.
     // * NO_MEMORY - no slots were found that were both free and contained a
     //               GraphicBuffer.
@@ -217,7 +234,8 @@
     // success.
     //
     // Return of a negative value means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
     // * BAD_VALUE - outSlot or buffer were NULL, invalid combination of
     //               async mode and buffer count override, or the generation
     //               number of the buffer did not match the buffer queue.
@@ -251,7 +269,8 @@
     // (refer to the documentation below).
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
     // * BAD_VALUE - one of the below conditions occurred:
     //              * fence was NULL
     //              * scaling mode was unknown
@@ -271,23 +290,21 @@
         // crop - a crop rectangle that's used as a hint to the consumer
         // scalingMode - a set of flags from NATIVE_WINDOW_SCALING_* in <window.h>
         // transform - a set of flags from NATIVE_WINDOW_TRANSFORM_* in <window.h>
-        // async - if the buffer is queued in asynchronous mode
         // fence - a fence that the consumer must wait on before reading the buffer,
         //         set this to Fence::NO_FENCE if the buffer is ready immediately
         // sticky - the sticky transform set in Surface (only used by the LEGACY
         //          camera mode).
         inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp,
                 android_dataspace dataSpace, const Rect& crop, int scalingMode,
-                uint32_t transform, bool async, const sp<Fence>& fence,
-                uint32_t sticky = 0)
+                uint32_t transform, const sp<Fence>& fence, uint32_t sticky = 0)
                 : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp),
                   dataSpace(dataSpace), crop(crop), scalingMode(scalingMode),
-                  transform(transform), stickyTransform(sticky),
-                  async(async), fence(fence), surfaceDamage() { }
+                  transform(transform), stickyTransform(sticky), fence(fence),
+                  surfaceDamage() { }
         inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
                 android_dataspace* outDataSpace,
                 Rect* outCrop, int* outScalingMode,
-                uint32_t* outTransform, bool* outAsync, sp<Fence>* outFence,
+                uint32_t* outTransform, sp<Fence>* outFence,
                 uint32_t* outStickyTransform = NULL) const {
             *outTimestamp = timestamp;
             *outIsAutoTimestamp = bool(isAutoTimestamp);
@@ -295,7 +312,6 @@
             *outCrop = crop;
             *outScalingMode = scalingMode;
             *outTransform = transform;
-            *outAsync = bool(async);
             *outFence = fence;
             if (outStickyTransform != NULL) {
                 *outStickyTransform = stickyTransform;
@@ -319,7 +335,6 @@
         int scalingMode;
         uint32_t transform;
         uint32_t stickyTransform;
-        int async;
         sp<Fence> fence;
         Region surfaceDamage;
     };
@@ -355,8 +370,8 @@
         uint32_t numPendingBuffers;
     };
 
-    virtual status_t queueBuffer(int slot,
-            const QueueBufferInput& input, QueueBufferOutput* output) = 0;
+    virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
+            QueueBufferOutput* output) = 0;
 
     // cancelBuffer indicates that the client does not wish to fill in the
     // buffer associated with slot and transfers ownership of the slot back to
@@ -364,9 +379,19 @@
     //
     // The buffer is not queued for use by the consumer.
     //
+    // The slot must be in the range of [0, NUM_BUFFER_SLOTS).
+    //
     // The buffer will not be overwritten until the fence signals.  The fence
     // will usually be the one obtained from dequeueBuffer.
-    virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0;
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned or the producer is not
+    //             connected.
+    // * BAD_VALUE - one of the below conditions occurred:
+    //              * fence was NULL
+    //              * slot index was out of range (see above).
+    //              * the slot was not in the dequeued state
+    virtual status_t cancelBuffer(int slot, const sp<Fence>& fence) = 0;
 
     // query retrieves some information for this surface
     // 'what' tokens allowed are that of NATIVE_WINDOW_* in <window.h>
@@ -457,7 +482,7 @@
     // allocated. This is most useful to avoid an allocation delay during
     // dequeueBuffer. If there are already the maximum number of buffers
     // allocated, this function has no effect.
-    virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
+    virtual void allocateBuffers(uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage) = 0;
 
     // Sets whether dequeueBuffer is allowed to allocate new buffers.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 72f1067..ed2331b 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -183,6 +183,8 @@
     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
 
 public:
+    virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual int setAsyncMode(bool async);
     virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
     virtual int unlockAndPost();
 
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index f0a6238..efc1687 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -307,6 +307,10 @@
     DEFINE_KEYCODE(STEM_1),
     DEFINE_KEYCODE(STEM_2),
     DEFINE_KEYCODE(STEM_3),
+    DEFINE_KEYCODE(DPAD_UP_LEFT),
+    DEFINE_KEYCODE(DPAD_DOWN_LEFT),
+    DEFINE_KEYCODE(DPAD_UP_RIGHT),
+    DEFINE_KEYCODE(DPAD_DOWN_RIGHT),
     DEFINE_KEYCODE(MEDIA_SKIP_FORWARD),
     DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD),
     DEFINE_KEYCODE(MEDIA_STEP_FORWARD),
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index cbe8733..b2574d0 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -58,11 +58,10 @@
         :   what(0),
             x(0), y(0), z(0), w(0), h(0), layerStack(0),
             alpha(0), flags(0), mask(0),
-            reserved(0)
+            reserved(0), crop(Rect::INVALID_RECT)
     {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
-        crop.makeInvalid();
     }
 
     status_t    write(Parcel& output) const;
@@ -117,6 +116,8 @@
         eDisplaySizeChanged         = 0x08
     };
 
+    DisplayState();
+
     uint32_t what;
     sp<IBinder> token;
     sp<IGraphicBufferProducer> surface;
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 8c190dd..84eb100 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -72,7 +72,7 @@
     }
 
     void operator()(region_rasterizer& rasterizer) {
-        RECT current;
+        RECT current(Rect::EMPTY_RECT);
         do {
             SpannerInner spannerInner(spanner.lhs, spanner.rhs);
             int inside = spanner.next(current.top, current.bottom);
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index 3886f93..6310502 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -32,13 +32,12 @@
     typedef ARect::value_type value_type;
 
     static const Rect INVALID_RECT;
+    static const Rect EMPTY_RECT;
 
     // we don't provide copy-ctor and operator= on purpose
     // because we want the compiler generated versions
 
-    inline Rect() {
-      left = right = top = bottom = 0;
-    }
+    inline Rect() : Rect(INVALID_RECT) {}
 
     inline Rect(int32_t w, int32_t h) {
         left = top = 0;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 45191f5..8315c58 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -350,13 +350,11 @@
 
 size_t Parcel::dataAvail() const
 {
-    // TODO: decide what to do about the possibility that this can
-    // report an available-data size that exceeds a Java int's max
-    // positive value, causing havoc.  Fortunately this will only
-    // happen if someone constructs a Parcel containing more than two
-    // gigabytes of data, which on typical phone hardware is simply
-    // not possible.
-    return dataSize() - dataPosition();
+    size_t result = dataSize() - dataPosition();
+    if (result > INT32_MAX) {
+        abort();
+    }
+    return result;
 }
 
 size_t Parcel::dataPosition() const
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 8f64ae0..6a883cf 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -24,6 +24,7 @@
 namespace android {
 
 BufferItem::BufferItem() :
+    mCrop(Rect::INVALID_RECT),
     mTransform(0),
     mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mTimestamp(0),
@@ -34,7 +35,6 @@
     mIsDroppable(false),
     mAcquireCalled(false),
     mTransformToDisplayInverse(false) {
-    mCrop.makeInvalid();
 }
 
 BufferItem::~BufferItem() {}
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 578b8d9..6f4c89d 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -78,7 +78,7 @@
         }
     }
 
-    item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
+    item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer;
 
     return OK;
 }
@@ -89,9 +89,9 @@
 
     Mutex::Autolock _l(mMutex);
 
-    err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence);
+    err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
 
-    err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY,
+    err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY,
             EGL_NO_SYNC_KHR);
     if (err != OK) {
         BI_LOGE("Failed to release buffer: %s (%d)",
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index bb3e1b0..d52b47f 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -482,24 +482,29 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) {
+status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
-    return mCore->setDefaultMaxBufferCountLocked(bufferCount);
-}
 
-status_t BufferQueueConsumer::disableAsyncBuffer() {
-    ATRACE_CALL();
+    if (bufferCount < 1 || bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("setMaxBufferCount: invalid count %d", bufferCount);
+        return BAD_VALUE;
+    }
 
     Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mConsumerListener != NULL) {
-        BQ_LOGE("disableAsyncBuffer: consumer already connected");
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("setMaxBufferCount: producer is already connected");
         return INVALID_OPERATION;
     }
 
-    BQ_LOGV("disableAsyncBuffer");
-    mCore->mUseAsyncBuffer = false;
+    if (bufferCount < mCore->mMaxAcquiredBufferCount) {
+        BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
+                "mMaxAcquiredBufferCount (%d)", bufferCount,
+                mCore->mMaxAcquiredBufferCount);
+        return BAD_VALUE;
+    }
+
+    mCore->mMaxBufferCount = bufferCount;
     return NO_ERROR;
 }
 
@@ -521,6 +526,17 @@
         return INVALID_OPERATION;
     }
 
+    if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
+            (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
+            mCore->mMaxBufferCount) {
+        BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would exceed "
+                "the maxBufferCount (%d) (maxDequeued %d async %d)",
+                maxAcquiredBuffers, mCore->mMaxBufferCount,
+                mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
+                mCore->mDequeueBufferCannotBlock);
+        return BAD_VALUE;
+    }
+
     BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
     mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
     return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 851a396..b1cbc86 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -30,9 +30,6 @@
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
-template <typename T>
-static inline T max(T a, T b) { return a > b ? a : b; }
-
 namespace android {
 
 static String8 getUniqueName() {
@@ -55,16 +52,15 @@
     mQueue(),
     mFreeSlots(),
     mFreeBuffers(),
-    mOverrideMaxBufferCount(0),
     mDequeueCondition(),
-    mUseAsyncBuffer(true),
     mDequeueBufferCannotBlock(false),
     mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
     mDefaultWidth(1),
     mDefaultHeight(1),
     mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
-    mDefaultMaxBufferCount(2),
+    mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
     mMaxAcquiredBufferCount(1),
+    mMaxDequeuedBufferCount(1),
     mBufferHasBeenQueued(false),
     mFrameCounter(0),
     mTransformHint(0),
@@ -72,7 +68,8 @@
     mIsAllocatingCondition(),
     mAllowAllocation(true),
     mBufferAge(0),
-    mGenerationNumber(0)
+    mGenerationNumber(0),
+    mAsyncMode(false)
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -104,11 +101,13 @@
     }
 
     result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
-            "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
-            "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n",
-            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock,
-            mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
-            mQueue.size(), fifo.string());
+            "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
+            "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
+            "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix,
+            mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
+            mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
+            mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
+            fifo.string());
 
     // Trim the free buffers so as to not spam the dump
     int maxBufferCount = 0;
@@ -139,32 +138,26 @@
     }
 }
 
-int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const {
+int BufferQueueCore::getMinUndequeuedBufferCountLocked() const {
     // If dequeueBuffer is allowed to error out, we don't have to add an
     // extra buffer.
-    if (!mUseAsyncBuffer) {
-        return mMaxAcquiredBufferCount;
-    }
-
-    if (mDequeueBufferCannotBlock || async) {
+    if (mAsyncMode || mDequeueBufferCannotBlock) {
         return mMaxAcquiredBufferCount + 1;
     }
 
     return mMaxAcquiredBufferCount;
 }
 
-int BufferQueueCore::getMinMaxBufferCountLocked(bool async) const {
-    return getMinUndequeuedBufferCountLocked(async) + 1;
+int BufferQueueCore::getMinMaxBufferCountLocked() const {
+    return getMinUndequeuedBufferCountLocked() + 1;
 }
 
-int BufferQueueCore::getMaxBufferCountLocked(bool async) const {
-    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+int BufferQueueCore::getMaxBufferCountLocked() const {
+    int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
+            (mAsyncMode || mDequeueBufferCannotBlock ? 1 : 0);
 
-    int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount);
-    if (mOverrideMaxBufferCount != 0) {
-        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
-        maxBufferCount = mOverrideMaxBufferCount;
-    }
+    // limit maxBufferCount by mMaxBufferCount always
+    maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
 
     // Any buffers that are dequeued by the producer or sitting in the queue
     // waiting to be consumed need to have their slots preserved. Such buffers
@@ -180,22 +173,6 @@
     return maxBufferCount;
 }
 
-status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) {
-    const int minBufferCount = mUseAsyncBuffer ? 2 : 1;
-    if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
-        BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in "
-                "[%d, %d]",
-                count, minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    }
-
-    BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count);
-    mDefaultMaxBufferCount = count;
-    mDequeueCondition.broadcast();
-
-    return NO_ERROR;
-}
-
 void BufferQueueCore::freeBufferLocked(int slot) {
     BQ_LOGV("freeBufferLocked: slot %d", slot);
     bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 87e5b4d..0cb018c 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -57,6 +57,11 @@
         return NO_INIT;
     }
 
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("requestBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
         BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)",
                 slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
@@ -72,9 +77,11 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueProducer::setBufferCount(int bufferCount) {
+status_t BufferQueueProducer::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
     ATRACE_CALL();
-    BQ_LOGV("setBufferCount: count = %d", bufferCount);
+    BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
+            maxDequeuedBuffers);
 
     sp<IConsumerListener> listener;
     { // Autolock scope
@@ -82,34 +89,41 @@
         mCore->waitWhileAllocatingLocked();
 
         if (mCore->mIsAbandoned) {
-            BQ_LOGE("setBufferCount: BufferQueue has been abandoned");
+            BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been "
+                    "abandoned");
             return NO_INIT;
         }
 
-        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
-            BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)",
-                    bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
-            return BAD_VALUE;
-        }
-
         // There must be no dequeued buffers when changing the buffer count.
         for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
             if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
-                BQ_LOGE("setBufferCount: buffer owned by producer");
+                BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
                 return BAD_VALUE;
             }
         }
 
-        if (bufferCount == 0) {
-            mCore->mOverrideMaxBufferCount = 0;
-            mCore->mDequeueCondition.broadcast();
-            return NO_ERROR;
+        int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
+        bufferCount += maxDequeuedBuffers;
+
+        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large "
+                    "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
         }
 
-        const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false);
+        const int minBufferSlots = mCore->getMinMaxBufferCountLocked();
         if (bufferCount < minBufferSlots) {
-            BQ_LOGE("setBufferCount: requested buffer count %d is less than "
-                    "minimum %d", bufferCount, minBufferSlots);
+            BQ_LOGE("setMaxDequeuedBufferCount: requested buffer count %d is "
+                    "less than minimum %d", bufferCount, minBufferSlots);
+            return BAD_VALUE;
+        }
+
+        if (bufferCount > mCore->mMaxBufferCount) {
+            BQ_LOGE("setMaxDequeuedBufferCount: %d dequeued buffers would "
+                    "exceed the maxBufferCount (%d) (maxAcquired %d async %d "
+                    "mDequeuedBufferCannotBlock %d)", maxDequeuedBuffers,
+                    mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount,
+                    mCore->mAsyncMode, mCore->mDequeueBufferCannotBlock);
             return BAD_VALUE;
         }
 
@@ -118,7 +132,7 @@
         // clear the queue, however, so that currently queued buffers still
         // get displayed.
         mCore->freeAllBuffersLocked();
-        mCore->mOverrideMaxBufferCount = bufferCount;
+        mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
         mCore->mDequeueCondition.broadcast();
         listener = mCore->mConsumerListener;
     } // Autolock scope
@@ -131,8 +145,46 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::setAsyncMode(bool async) {
+    ATRACE_CALL();
+    BQ_LOGV("setAsyncMode: async = %d", async);
+
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("setAsyncMode: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if ((mCore->mMaxAcquiredBufferCount + mCore->mMaxDequeuedBufferCount +
+                (async || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
+                mCore->mMaxBufferCount) {
+            BQ_LOGE("setAsyncMode(%d): this call would cause the "
+                    "maxBufferCount (%d) to be exceeded (maxAcquired %d "
+                    "maxDequeued %d mDequeueBufferCannotBlock %d)", async,
+                    mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount,
+                    mCore->mMaxDequeuedBufferCount,
+                    mCore->mDequeueBufferCannotBlock);
+            return BAD_VALUE;
+        }
+
+        mCore->mAsyncMode = async;
+        mCore->mDequeueCondition.broadcast();
+        listener = mCore->mConsumerListener;
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+    return NO_ERROR;
+}
+
 status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
-        bool async, int* found, status_t* returnFlags) const {
+        int* found, status_t* returnFlags) const {
     bool tryAgain = true;
     while (tryAgain) {
         if (mCore->mIsAbandoned) {
@@ -140,17 +192,7 @@
             return NO_INIT;
         }
 
-        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
-        if (async && mCore->mOverrideMaxBufferCount) {
-            // FIXME: Some drivers are manually setting the buffer count
-            // (which they shouldn't), so we do this extra test here to
-            // handle that case. This is TEMPORARY until we get this fixed.
-            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
-                BQ_LOGE("%s: async mode is invalid with buffer count override",
-                        caller);
-                return BAD_VALUE;
-            }
-        }
+        const int maxBufferCount = mCore->getMaxBufferCountLocked();
 
         // Free up any buffers that are in slots beyond the max buffer count
         for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
@@ -176,33 +218,16 @@
             }
         }
 
-        // Producers are not allowed to dequeue more than one buffer if they
-        // did not set a buffer count
-        if (!mCore->mOverrideMaxBufferCount && dequeuedCount) {
-            BQ_LOGE("%s: can't dequeue multiple buffers without setting the "
-                    "buffer count", caller);
+        // Producers are not allowed to dequeue more than
+        // mMaxDequeuedBufferCount buffers.
+        // This check is only done if a buffer has already been queued
+        if (mCore->mBufferHasBeenQueued &&
+                dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
+            BQ_LOGE("%s: attempting to exceed the max dequeued buffer count "
+                    "(%d)", caller, mCore->mMaxDequeuedBufferCount);
             return INVALID_OPERATION;
         }
 
-        // See whether a buffer has been queued since the last
-        // setBufferCount so we know whether to perform the min undequeued
-        // buffers check below
-        if (mCore->mBufferHasBeenQueued) {
-            // Make sure the producer is not trying to dequeue more buffers
-            // than allowed
-            const int newUndequeuedCount =
-                maxBufferCount - (dequeuedCount + 1);
-            const int minUndequeuedCount =
-                mCore->getMinUndequeuedBufferCountLocked(async);
-            if (newUndequeuedCount < minUndequeuedCount) {
-                BQ_LOGE("%s: min undequeued buffer count (%d) exceeded "
-                        "(dequeued=%d undequeued=%d)",
-                        caller, minUndequeuedCount,
-                        dequeuedCount, newUndequeuedCount);
-                return INVALID_OPERATION;
-            }
-        }
-
         *found = BufferQueueCore::INVALID_BUFFER_SLOT;
 
         // If we disconnect and reconnect quickly, we can be in a state where
@@ -241,7 +266,7 @@
             // buffer (which could cause us to have to wait here), which is
             // okay, since it is only used to implement an atomic acquire +
             // release (e.g., in GLConsumer::updateTexImage())
-            if (mCore->mDequeueBufferCannotBlock &&
+            if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
                     (acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
                 return WOULD_BLOCK;
             }
@@ -253,16 +278,26 @@
 }
 
 status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
-        sp<android::Fence> *outFence, bool async,
-        uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) {
+        sp<android::Fence> *outFence, uint32_t width, uint32_t height,
+        PixelFormat format, uint32_t usage) {
     ATRACE_CALL();
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mConsumerName = mCore->mConsumerName;
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
     } // Autolock scope
 
-    BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x",
-            async ? "true" : "false", width, height, format, usage);
+    BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height,
+            format, usage);
 
     if ((width && !height) || (!width && height)) {
         BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
@@ -293,8 +328,8 @@
 
         int found = BufferItem::INVALID_BUFFER_SLOT;
         while (found == BufferItem::INVALID_BUFFER_SLOT) {
-            status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
-                    &found, &returnFlags);
+            status_t status = waitForFreeSlotThenRelock("dequeueBuffer", &found,
+                    &returnFlags);
             if (status != NO_ERROR) {
                 return status;
             }
@@ -426,6 +461,11 @@
         return NO_INIT;
     }
 
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("detachBuffer(P): BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
         BQ_LOGE("detachBuffer(P): slot index %d out of range [0, %d)",
                 slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
@@ -460,13 +500,19 @@
     }
 
     Mutex::Autolock lock(mCore->mMutex);
-    mCore->waitWhileAllocatingLocked();
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
         return NO_INIT;
     }
 
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    mCore->waitWhileAllocatingLocked();
+
     if (mCore->mFreeBuffers.empty()) {
         return NO_MEMORY;
     }
@@ -497,7 +543,16 @@
     }
 
     Mutex::Autolock lock(mCore->mMutex);
-    mCore->waitWhileAllocatingLocked();
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("attachBuffer(P): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("attachBuffer(P): BufferQueue has no connected producer");
+        return NO_INIT;
+    }
 
     if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
         BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
@@ -506,13 +561,12 @@
         return BAD_VALUE;
     }
 
+    mCore->waitWhileAllocatingLocked();
+
     status_t returnFlags = NO_ERROR;
     int found;
-    // TODO: Should we provide an async flag to attachBuffer? It seems
-    // unlikely that buffers which we are attaching to a BufferQueue will
-    // be asynchronous (droppable), but it may not be impossible.
-    status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false,
-            &found, &returnFlags);
+    status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", &found,
+            &returnFlags);
     if (status != NO_ERROR) {
         return status;
     }
@@ -547,14 +601,13 @@
     int64_t timestamp;
     bool isAutoTimestamp;
     android_dataspace dataSpace;
-    Rect crop;
+    Rect crop(Rect::EMPTY_RECT);
     int scalingMode;
     uint32_t transform;
     uint32_t stickyTransform;
-    bool async;
     sp<Fence> fence;
     input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode,
-            &transform, &async, &fence, &stickyTransform);
+            &transform, &fence, &stickyTransform);
     Region surfaceDamage = input.getSurfaceDamage();
 
     if (fence == NULL) {
@@ -585,18 +638,13 @@
             return NO_INIT;
         }
 
-        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
-        if (async && mCore->mOverrideMaxBufferCount) {
-            // FIXME: Some drivers are manually setting the buffer count
-            // (which they shouldn't), so we do this extra test here to
-            // handle that case. This is TEMPORARY until we get this fixed.
-            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
-                BQ_LOGE("queueBuffer: async mode is invalid with "
-                        "buffer count override");
-                return BAD_VALUE;
-            }
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("queueBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
         }
 
+        const int maxBufferCount = mCore->getMaxBufferCountLocked();
+
         if (slot < 0 || slot >= maxBufferCount) {
             BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
                     slot, maxBufferCount);
@@ -619,7 +667,7 @@
 
         const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
         Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
-        Rect croppedRect;
+        Rect croppedRect(Rect::EMPTY_RECT);
         crop.intersect(bufferRect, &croppedRect);
         if (croppedRect != crop) {
             BQ_LOGE("queueBuffer: crop rect is not contained within the "
@@ -651,7 +699,8 @@
         item.mFrameNumber = mCore->mFrameCounter;
         item.mSlot = slot;
         item.mFence = fence;
-        item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;
+        item.mIsDroppable = mCore->mAsyncMode ||
+                mCore->mDequeueBufferCannotBlock;
         item.mSurfaceDamage = surfaceDamage;
 
         mStickyTransform = stickyTransform;
@@ -731,27 +780,32 @@
     return NO_ERROR;
 }
 
-void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
     ATRACE_CALL();
     BQ_LOGV("cancelBuffer: slot %d", slot);
     Mutex::Autolock lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("cancelBuffer: BufferQueue has been abandoned");
-        return;
+        return NO_INIT;
+    }
+
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("cancelBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
     }
 
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
         BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)",
                 slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return;
+        return BAD_VALUE;
     } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
         BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
                 "(state = %d)", slot, mSlots[slot].mBufferState);
-        return;
+        return BAD_VALUE;
     } else if (fence == NULL) {
         BQ_LOGE("cancelBuffer: fence is NULL");
-        return;
+        return BAD_VALUE;
     }
 
     mCore->mFreeBuffers.push_front(slot);
@@ -759,6 +813,8 @@
     mSlots[slot].mFence = fence;
     mCore->mDequeueCondition.broadcast();
     mCore->validateConsistencyLocked();
+
+    return NO_ERROR;
 }
 
 int BufferQueueProducer::query(int what, int *outValue) {
@@ -787,7 +843,7 @@
             value = static_cast<int32_t>(mCore->mDefaultBufferFormat);
             break;
         case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-            value = mCore->getMinUndequeuedBufferCountLocked(false);
+            value = mCore->getMinUndequeuedBufferCountLocked();
             break;
         case NATIVE_WINDOW_STICKY_TRANSFORM:
             value = static_cast<int32_t>(mStickyTransform);
@@ -877,8 +933,8 @@
     }
 
     mCore->mBufferHasBeenQueued = false;
-    mCore->mDequeueBufferCannotBlock =
-            mCore->mConsumerControlledByApp && producerControlledByApp;
+    mCore->mDequeueBufferCannotBlock =  mCore->mConsumerControlledByApp &&
+            producerControlledByApp;
     mCore->mAllowAllocation = true;
 
     return status;
@@ -957,8 +1013,8 @@
     return NO_ERROR;
 }
 
-void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
-        uint32_t height, PixelFormat format, uint32_t usage) {
+void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
+        PixelFormat format, uint32_t usage) {
     ATRACE_CALL();
     while (true) {
         Vector<int> freeSlots;
@@ -992,7 +1048,7 @@
                 }
             }
 
-            int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+            int maxBufferCount = mCore->getMaxBufferCountLocked();
             BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
                     currentBufferCount, maxBufferCount);
             if (maxBufferCount <= currentBufferCount)
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 04ab06b..d01187f 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -239,14 +239,14 @@
     }
 
     if (item->mGraphicBuffer != NULL) {
-        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
+        mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
     }
 
-    mSlots[item->mBuf].mFrameNumber = item->mFrameNumber;
-    mSlots[item->mBuf].mFence = item->mFence;
+    mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
+    mSlots[item->mSlot].mFence = item->mFence;
 
     CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
-            item->mBuf, item->mFrameNumber);
+            item->mSlot, item->mFrameNumber);
 
     return OK;
 }
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index e29b740..7ed3d0f 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -106,22 +106,22 @@
         }
     }
 
-    int buf = b.mBuf;
+    int slot = b.mSlot;
 
     void *bufferPointer = NULL;
     android_ycbcr ycbcr = android_ycbcr();
 
-    PixelFormat format = mSlots[buf].mGraphicBuffer->getPixelFormat();
+    PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat();
     PixelFormat flexFormat = format;
     if (isPossiblyYUV(format)) {
         if (b.mFence.get()) {
-            err = mSlots[buf].mGraphicBuffer->lockAsyncYCbCr(
+            err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr(
                 GraphicBuffer::USAGE_SW_READ_OFTEN,
                 b.mCrop,
                 &ycbcr,
                 b.mFence->dup());
         } else {
-            err = mSlots[buf].mGraphicBuffer->lockYCbCr(
+            err = mSlots[slot].mGraphicBuffer->lockYCbCr(
                 GraphicBuffer::USAGE_SW_READ_OFTEN,
                 b.mCrop,
                 &ycbcr);
@@ -141,13 +141,13 @@
 
     if (bufferPointer == NULL) { // not flexible YUV
         if (b.mFence.get()) {
-            err = mSlots[buf].mGraphicBuffer->lockAsync(
+            err = mSlots[slot].mGraphicBuffer->lockAsync(
                 GraphicBuffer::USAGE_SW_READ_OFTEN,
                 b.mCrop,
                 &bufferPointer,
                 b.mFence->dup());
         } else {
-            err = mSlots[buf].mGraphicBuffer->lock(
+            err = mSlots[slot].mGraphicBuffer->lock(
                 GraphicBuffer::USAGE_SW_READ_OFTEN,
                 b.mCrop,
                 &bufferPointer);
@@ -169,19 +169,19 @@
     assert(lockedIdx < mMaxLockedBuffers);
 
     AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = buf;
+    ab.mSlot = slot;
     ab.mBufferPointer = bufferPointer;
-    ab.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+    ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
 
     nativeBuffer->data   =
             reinterpret_cast<uint8_t*>(bufferPointer);
-    nativeBuffer->width  = mSlots[buf].mGraphicBuffer->getWidth();
-    nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight();
+    nativeBuffer->width  = mSlots[slot].mGraphicBuffer->getWidth();
+    nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight();
     nativeBuffer->format = format;
     nativeBuffer->flexFormat = flexFormat;
     nativeBuffer->stride = (ycbcr.y != NULL) ?
             static_cast<uint32_t>(ycbcr.ystride) :
-            mSlots[buf].mGraphicBuffer->getStride();
+            mSlots[slot].mGraphicBuffer->getStride();
 
     nativeBuffer->crop        = b.mCrop;
     nativeBuffer->transform   = b.mTransform;
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 757e08a..1572a89 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -130,6 +130,7 @@
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
+    mCurrentCrop(Rect::EMPTY_RECT),
     mCurrentTransform(0),
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
@@ -157,6 +158,7 @@
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
         bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
+    mCurrentCrop(Rect::EMPTY_RECT),
     mCurrentTransform(0),
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
@@ -181,12 +183,6 @@
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
 }
 
-status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) {
-    Mutex::Autolock lock(mMutex);
-    return mConsumer->setDefaultMaxBufferCount(bufferCount);
-}
-
-
 status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
     Mutex::Autolock lock(mMutex);
@@ -355,7 +351,7 @@
     // before, so any prior EglImage created is using a stale buffer. This
     // replaces any old EglImage with a new one (using the new buffer).
     if (item->mGraphicBuffer != NULL) {
-        int slot = item->mBuf;
+        int slot = item->mSlot;
         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
     }
 
@@ -379,12 +375,12 @@
 {
     status_t err = NO_ERROR;
 
-    int buf = item.mBuf;
+    int slot = item.mSlot;
 
     if (!mAttached) {
         GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
                 "ES context");
-        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                 mEglDisplay, EGL_NO_SYNC_KHR);
         return INVALID_OPERATION;
     }
@@ -392,7 +388,7 @@
     // Confirm state.
     err = checkAndUpdateEglStateLocked();
     if (err != NO_ERROR) {
-        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                 mEglDisplay, EGL_NO_SYNC_KHR);
         return err;
     }
@@ -402,11 +398,11 @@
     // ConsumerBase.
     // We may have to do this even when item.mGraphicBuffer == NULL (which
     // means the buffer was previously acquired).
-    err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
     if (err != NO_ERROR) {
         GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
-                mEglDisplay, buf);
-        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+                mEglDisplay, slot);
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                 mEglDisplay, EGL_NO_SYNC_KHR);
         return UNKNOWN_ERROR;
     }
@@ -418,7 +414,7 @@
         // release the old buffer, so instead we just drop the new frame.
         // As we are still under lock since acquireBuffer, it is safe to
         // release by slot.
-        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                 mEglDisplay, EGL_NO_SYNC_KHR);
         return err;
     }
@@ -426,7 +422,7 @@
     GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
             mCurrentTexture, mCurrentTextureImage != NULL ?
                     mCurrentTextureImage->graphicBufferHandle() : 0,
-            buf, mSlots[buf].mGraphicBuffer->handle);
+            slot, mSlots[slot].mGraphicBuffer->handle);
 
     // release old buffer
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
@@ -442,8 +438,8 @@
     }
 
     // Update the GLConsumer state.
-    mCurrentTexture = buf;
-    mCurrentTextureImage = mEglSlots[buf].mEglImage;
+    mCurrentTexture = slot;
+    mCurrentTextureImage = mEglSlots[slot].mEglImage;
     mCurrentCrop = item.mCrop;
     mCurrentTransform = item.mTransform;
     mCurrentScalingMode = item.mScalingMode;
@@ -1046,6 +1042,11 @@
     return mConsumer->setTransformHint(hint);
 }
 
+status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    Mutex::Autolock lock(mMutex);
+    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+}
+
 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
 {
     result.appendFormat(
@@ -1083,7 +1084,8 @@
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
-    mEglDisplay(EGL_NO_DISPLAY) {
+    mEglDisplay(EGL_NO_DISPLAY),
+    mCropRect(Rect::EMPTY_RECT) {
 }
 
 GLConsumer::EglImage::~EglImage() {
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index b86f4c5..d2f482e 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -43,8 +43,7 @@
     CONSUMER_DISCONNECT,
     GET_RELEASED_BUFFERS,
     SET_DEFAULT_BUFFER_SIZE,
-    SET_DEFAULT_MAX_BUFFER_COUNT,
-    DISABLE_ASYNC_BUFFER,
+    SET_MAX_BUFFER_COUNT,
     SET_MAX_ACQUIRED_BUFFER_COUNT,
     SET_CONSUMER_NAME,
     SET_DEFAULT_BUFFER_FORMAT,
@@ -172,21 +171,11 @@
         return reply.readInt32();
     }
 
-    virtual status_t setDefaultMaxBufferCount(int bufferCount) {
+    virtual status_t setMaxBufferCount(int bufferCount) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
         data.writeInt32(bufferCount);
-        status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t disableAsyncBuffer() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply);
+        status_t result = remote()->transact(SET_MAX_BUFFER_COUNT, data, &reply);
         if (result != NO_ERROR) {
             return result;
         }
@@ -363,16 +352,10 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_DEFAULT_MAX_BUFFER_COUNT: {
+        case SET_MAX_BUFFER_COUNT: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             int bufferCount = data.readInt32();
-            status_t result = setDefaultMaxBufferCount(bufferCount);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case DISABLE_ASYNC_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            status_t result = disableAsyncBuffer();
+            status_t result = setMaxBufferCount(bufferCount);
             reply->writeInt32(result);
             return NO_ERROR;
         }
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8bdbc22..8ab963d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -34,7 +34,6 @@
 
 enum {
     REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-    SET_BUFFER_COUNT,
     DEQUEUE_BUFFER,
     DETACH_BUFFER,
     DETACH_NEXT_BUFFER,
@@ -49,6 +48,8 @@
     ALLOW_ALLOCATION,
     SET_GENERATION_NUMBER,
     GET_CONSUMER_NAME,
+    SET_MAX_DEQUEUED_BUFFER_COUNT,
+    SET_ASYNC_MODE
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -82,12 +83,13 @@
         return result;
     }
 
-    virtual status_t setBufferCount(int bufferCount)
-    {
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
         Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeInt32(bufferCount);
-        status_t result =remote()->transact(SET_BUFFER_COUNT, data, &reply);
+        data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(maxDequeuedBuffers);
+        status_t result = remote()->transact(SET_MAX_DEQUEUED_BUFFER_COUNT,
+                data, &reply);
         if (result != NO_ERROR) {
             return result;
         }
@@ -95,12 +97,24 @@
         return result;
     }
 
-    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
-            uint32_t width, uint32_t height, PixelFormat format,
-            uint32_t usage) {
+    virtual status_t setAsyncMode(bool async) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(async);
+        status_t result = remote()->transact(SET_ASYNC_MODE,
+                data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
+            uint32_t height, PixelFormat format, uint32_t usage) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeInt32(static_cast<int32_t>(async));
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
@@ -190,12 +204,17 @@
         return result;
     }
 
-    virtual void cancelBuffer(int buf, const sp<Fence>& fence) {
+    virtual status_t cancelBuffer(int buf, const sp<Fence>& fence) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
         data.writeInt32(buf);
         data.write(*fence.get());
-        remote()->transact(CANCEL_BUFFER, data, &reply);
+        status_t result = remote()->transact(CANCEL_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
     }
 
     virtual int query(int what, int* value) {
@@ -260,11 +279,10 @@
         return result;
     }
 
-    virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
+    virtual void allocateBuffers(uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeInt32(static_cast<int32_t>(async));
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
@@ -334,24 +352,30 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_BUFFER_COUNT: {
+        case SET_MAX_DEQUEUED_BUFFER_COUNT: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            int bufferCount = data.readInt32();
-            int result = setBufferCount(bufferCount);
+            int maxDequeuedBuffers = data.readInt32();
+            int result = setMaxDequeuedBufferCount(maxDequeuedBuffers);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
+        case SET_ASYNC_MODE: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            bool async = data.readInt32();
+            int result = setAsyncMode(async);
             reply->writeInt32(result);
             return NO_ERROR;
         }
         case DEQUEUE_BUFFER: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            bool async = static_cast<bool>(data.readInt32());
             uint32_t width = data.readUint32();
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
             uint32_t usage = data.readUint32();
             int buf = 0;
             sp<Fence> fence;
-            int result = dequeueBuffer(&buf, &fence, async, width, height,
-                    format, usage);
+            int result = dequeueBuffer(&buf, &fence, width, height, format,
+                    usage);
             reply->writeInt32(buf);
             reply->writeInt32(fence != NULL);
             if (fence != NULL) {
@@ -411,7 +435,8 @@
             int buf = data.readInt32();
             sp<Fence> fence = new Fence();
             data.read(*fence.get());
-            cancelBuffer(buf, fence);
+            status_t result = cancelBuffer(buf, fence);
+            reply->writeInt32(result);
             return NO_ERROR;
         }
         case QUERY: {
@@ -457,12 +482,11 @@
         }
         case ALLOCATE_BUFFERS: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            bool async = static_cast<bool>(data.readInt32());
             uint32_t width = data.readUint32();
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
             uint32_t usage = data.readUint32();
-            allocateBuffers(async, width, height, format, usage);
+            allocateBuffers(width, height, format, usage);
             return NO_ERROR;
         }
         case ALLOW_ALLOCATION: {
@@ -502,7 +526,6 @@
          + sizeof(scalingMode)
          + sizeof(transform)
          + sizeof(stickyTransform)
-         + sizeof(async)
          + fence->getFlattenedSize()
          + surfaceDamage.getFlattenedSize();
 }
@@ -524,7 +547,6 @@
     FlattenableUtils::write(buffer, size, scalingMode);
     FlattenableUtils::write(buffer, size, transform);
     FlattenableUtils::write(buffer, size, stickyTransform);
-    FlattenableUtils::write(buffer, size, async);
     status_t result = fence->flatten(buffer, size, fds, count);
     if (result != NO_ERROR) {
         return result;
@@ -542,8 +564,7 @@
             + sizeof(crop)
             + sizeof(scalingMode)
             + sizeof(transform)
-            + sizeof(stickyTransform)
-            + sizeof(async);
+            + sizeof(stickyTransform);
 
     if (size < minNeeded) {
         return NO_MEMORY;
@@ -556,7 +577,6 @@
     FlattenableUtils::read(buffer, size, scalingMode);
     FlattenableUtils::read(buffer, size, transform);
     FlattenableUtils::read(buffer, size, stickyTransform);
-    FlattenableUtils::read(buffer, size, async);
 
     fence = new Fence();
     status_t result = fence->unflatten(buffer, size, fds, count);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 78886d5..b4cbf84 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -353,7 +353,7 @@
             sp<IBinder> display = data.readStrongBinder();
             sp<IGraphicBufferProducer> producer =
                     interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
-            Rect sourceCrop;
+            Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             uint32_t reqWidth = data.readUint32();
             uint32_t reqHeight = data.readUint32();
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 00323dc..eafda86 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -77,6 +77,16 @@
 }
 
 
+DisplayState::DisplayState() :
+    what(0),
+    layerStack(0),
+    orientation(eOrientationDefault),
+    viewport(Rect::EMPTY_RECT),
+    frame(Rect::EMPTY_RECT),
+    width(0),
+    height(0) {
+}
+
 status_t DisplayState::write(Parcel& output) const {
     output.writeStrongBinder(token);
     output.writeStrongBinder(IInterface::asBinder(surface));
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 4b3603e..81c0549 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -38,7 +38,8 @@
 Sensor::Sensor()
     : mHandle(0), mType(0),
       mMinValue(0), mMaxValue(0), mResolution(0),
-      mPower(0), mMinDelay(0), mFifoReservedEventCount(0), mFifoMaxEventCount(0),
+      mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
+      mFifoMaxEventCount(0), mRequiredAppOp(0),
       mMaxDelay(0), mFlags(0)
 {
 }
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 43f9214..bafe947 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -132,7 +132,7 @@
     ALOGV("acquired buffer %#" PRIx64 " from input",
             bufferItem.mGraphicBuffer->getId());
 
-    status = mInput->detachBuffer(bufferItem.mBuf);
+    status = mInput->detachBuffer(bufferItem.mSlot);
     LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
             "detaching buffer from input failed (%d)", status);
 
@@ -144,8 +144,7 @@
             bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
             bufferItem.mDataSpace, bufferItem.mCrop,
             static_cast<int32_t>(bufferItem.mScalingMode),
-            bufferItem.mTransform, bufferItem.mIsDroppable,
-            bufferItem.mFence);
+            bufferItem.mTransform, bufferItem.mFence);
 
     // Attach and queue the buffer to each of the outputs
     Vector<sp<IGraphicBufferProducer> >::iterator output = mOutputs.begin();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 4b76f98..a31876b 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,6 +43,7 @@
         const sp<IGraphicBufferProducer>& bufferProducer,
         bool controlledByApp)
     : mGraphicBufferProducer(bufferProducer),
+      mCrop(Rect::EMPTY_RECT),
       mGenerationNumber(0)
 {
     // Initialize the ANativeWindow function pointers.
@@ -67,7 +68,6 @@
     mReqUsage = 0;
     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
     mDataSpace = HAL_DATASPACE_UNKNOWN;
-    mCrop.clear();
     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
     mTransform = 0;
     mStickyTransform = 0;
@@ -99,8 +99,8 @@
 void Surface::allocateBuffers() {
     uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
     uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
-    mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth,
-            reqHeight, mReqFormat, mReqUsage);
+    mGraphicBufferProducer->allocateBuffers(reqWidth, reqHeight,
+            mReqFormat, mReqUsage);
 }
 
 status_t Surface::setGenerationNumber(uint32_t generation) {
@@ -184,7 +184,9 @@
     va_list args;
     va_start(args, operation);
     Surface* c = getSelf(window);
-    return c->perform(operation, args);
+    int result = c->perform(operation, args);
+    va_end(args);
+    return result;
 }
 
 int Surface::setSwapInterval(int interval) {
@@ -200,6 +202,7 @@
         interval = maxSwapInterval;
 
     mSwapIntervalZero = (interval == 0);
+    mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero);
 
     return NO_ERROR;
 }
@@ -210,7 +213,6 @@
 
     uint32_t reqWidth;
     uint32_t reqHeight;
-    bool swapIntervalZero;
     PixelFormat reqFormat;
     uint32_t reqUsage;
 
@@ -220,20 +222,19 @@
         reqWidth = mReqWidth ? mReqWidth : mUserWidth;
         reqHeight = mReqHeight ? mReqHeight : mUserHeight;
 
-        swapIntervalZero = mSwapIntervalZero;
         reqFormat = mReqFormat;
         reqUsage = mReqUsage;
     } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
 
     int buf = -1;
     sp<Fence> fence;
-    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
+    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
             reqWidth, reqHeight, reqFormat, reqUsage);
 
     if (result < 0) {
-        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)"
-             "failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat,
-             reqUsage, result);
+        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
+                "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat,
+                reqUsage, result);
         return result;
     }
 
@@ -332,14 +333,14 @@
 
 
     // Make sure the crop rectangle is entirely inside the buffer.
-    Rect crop;
+    Rect crop(Rect::EMPTY_RECT);
     mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
 
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
             mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
-            mSwapIntervalZero, fence, mStickyTransform);
+            fence, mStickyTransform);
 
     if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
         input.setSurfaceDamage(Region::INVALID_REGION);
@@ -779,7 +780,7 @@
 {
     ATRACE_CALL();
 
-    Rect realRect;
+    Rect realRect(Rect::EMPTY_RECT);
     if (rect == NULL || rect->isEmpty()) {
         realRect.clear();
     } else {
@@ -800,9 +801,54 @@
     ALOGV("Surface::setBufferCount");
     Mutex::Autolock lock(mMutex);
 
-    status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
+    status_t err = NO_ERROR;
+    if (bufferCount == 0) {
+        err = mGraphicBufferProducer->setMaxDequeuedBufferCount(1);
+    } else {
+        int minUndequeuedBuffers = 0;
+        err = mGraphicBufferProducer->query(
+                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
+        if (err == NO_ERROR) {
+            err = mGraphicBufferProducer->setMaxDequeuedBufferCount(
+                    bufferCount - minUndequeuedBuffers);
+        }
+    }
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
     ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
-            bufferCount, strerror(-err));
+             bufferCount, strerror(-err));
+
+    return err;
+}
+
+int Surface::setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
+    ATRACE_CALL();
+    ALOGV("Surface::setMaxDequeuedBufferCount");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount(
+            maxDequeuedBuffers);
+    ALOGE_IF(err, "IGraphicBufferProducer::setMaxDequeuedBufferCount(%d) "
+            "returned %s", maxDequeuedBuffers, strerror(-err));
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
+    return err;
+}
+
+int Surface::setAsyncMode(bool async) {
+    ATRACE_CALL();
+    ALOGV("Surface::setAsyncMode");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mGraphicBufferProducer->setAsyncMode(async);
+    ALOGE_IF(err, "IGraphicBufferProducer::setAsyncMode(%d) returned %s",
+            async, strerror(-err));
 
     if (err == NO_ERROR) {
         freeAllBuffers();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6ad47d8..9167a0c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -310,9 +310,9 @@
     layer_state_t* s = getLayerStateLocked(client, id);
     if (!s)
         return BAD_INDEX;
-    if (mask & layer_state_t::eLayerOpaque ||
-            mask & layer_state_t::eLayerHidden ||
-            mask & layer_state_t::eLayerSecure) {
+    if ((mask & layer_state_t::eLayerOpaque) ||
+            (mask & layer_state_t::eLayerHidden) ||
+            (mask & layer_state_t::eLayerSecure)) {
         s->what |= layer_state_t::eFlagsChanged;
     }
     s->flags &= ~mask;
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 1a54875..5244d82 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -113,7 +113,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
@@ -125,7 +125,7 @@
 
     IGraphicBufferProducer::QueueBufferInput input(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
-            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
 
     BufferItem item;
@@ -145,19 +145,19 @@
     IGraphicBufferProducer::QueueBufferOutput qbo;
     mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
             &qbo);
-    mProducer->setBufferCount(4);
+    mProducer->setMaxDequeuedBufferCount(3);
 
     int slot;
     sp<Fence> fence;
     sp<GraphicBuffer> buf;
     IGraphicBufferProducer::QueueBufferInput qbi(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
-            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     BufferItem item;
 
     for (int i = 0; i < 2; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-                mProducer->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
+                mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
                     GRALLOC_USAGE_SW_READ_OFTEN));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
@@ -165,7 +165,7 @@
     }
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
                 GRALLOC_USAGE_SW_READ_OFTEN));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
@@ -189,6 +189,9 @@
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100));
+
+    EXPECT_EQ(OK, mConsumer->setMaxBufferCount(5));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(5));
 }
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
@@ -206,6 +209,28 @@
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
 }
 
+TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mConsumer->consumerConnect(dc, false);
+
+    // Test single buffer mode
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+}
+
+TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mConsumer->consumerConnect(dc, false);
+
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(0));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(
+            BufferQueue::NUM_BUFFER_SLOTS + 1));
+
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(5));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(3));
+}
+
 TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) {
     createBufferQueue();
     sp<DummyConsumer> dc(new DummyConsumer);
@@ -223,7 +248,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
@@ -247,7 +272,7 @@
     ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer));
     IGraphicBufferProducer::QueueBufferInput input(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
-            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output));
 
     BufferItem item;
@@ -272,12 +297,12 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     IGraphicBufferProducer::QueueBufferInput input(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
-            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
 
     ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(-1)); // Index too low
@@ -288,8 +313,8 @@
     BufferItem item;
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0)));
 
-    ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf));
-    ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(item.mBuf)); // Not acquired
+    ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot));
+    ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(item.mSlot)); // Not acquired
 
     uint32_t* dataIn;
     ASSERT_EQ(OK, item.mGraphicBuffer->lock(
@@ -308,7 +333,7 @@
             EGL_NO_SYNC_KHR, Fence::NO_FENCE));
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
@@ -331,7 +356,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
@@ -343,12 +368,12 @@
 
     IGraphicBufferProducer::QueueBufferInput input(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
-            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
 
     BufferItem item;
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0)));
-    ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf));
+    ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot));
 
     int newSlot;
     ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, item.mGraphicBuffer));
@@ -380,13 +405,13 @@
     sp<GraphicBuffer> buffer;
     // This should return an error since it would require an allocation
     ASSERT_EQ(OK, mProducer->allowAllocation(false));
-    ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, 0, 0,
+    ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0,
             0, GRALLOC_USAGE_SW_WRITE_OFTEN));
 
     // This should succeed, now that we've lifted the prohibition
     ASSERT_EQ(OK, mProducer->allowAllocation(true));
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
             GRALLOC_USAGE_SW_WRITE_OFTEN));
 
     // Release the previous buffer back to the BufferQueue
@@ -394,7 +419,7 @@
 
     // This should fail since we're requesting a different size
     ASSERT_EQ(OK, mProducer->allowAllocation(false));
-    ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false,
+    ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence,
             WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
 }
 
@@ -412,7 +437,7 @@
     int slot;
     sp<Fence> fence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
 
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 2dc9ccc..289cc74 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -444,19 +444,14 @@
     }
 }
 
-void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
-        const android_native_rect_t& rect);
-
-void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride);
-
-void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
-        uint8_t g, uint8_t b, uint8_t a);
-
 // Configures the ANativeWindow producer-side interface based on test parameters
 void configureANW(const sp<ANativeWindow>& anw,
         const CpuConsumerTestParams& params,
         int maxBufferSlack) {
     status_t err;
+    err = native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU);
+    ASSERT_NO_ERROR(err, "connect error: ");
+
     err = native_window_set_buffers_dimensions(anw.get(),
             params.width, params.height);
     ASSERT_NO_ERROR(err, "set_buffers_dimensions error: ");
diff --git a/libs/gui/tests/GLTest.h b/libs/gui/tests/GLTest.h
index d3c4a95..f0d27a8 100644
--- a/libs/gui/tests/GLTest.h
+++ b/libs/gui/tests/GLTest.h
@@ -35,9 +35,11 @@
 
 protected:
     GLTest() :
+            mDisplaySecs(0),
             mEglDisplay(EGL_NO_DISPLAY),
             mEglSurface(EGL_NO_SURFACE),
-            mEglContext(EGL_NO_CONTEXT) {
+            mEglContext(EGL_NO_CONTEXT),
+            mGlConfig(NULL) {
     }
 
     virtual void SetUp();
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 4ef9a69..882b14c 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -61,7 +61,6 @@
     const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT);
     const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0;
     const int QUEUE_BUFFER_INPUT_TRANSFORM = 0;
-    const bool QUEUE_BUFFER_INPUT_ASYNC = false;
     const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
 }; // namespace anonymous
 
@@ -131,7 +130,6 @@
            crop = QUEUE_BUFFER_INPUT_RECT;
            scalingMode = QUEUE_BUFFER_INPUT_SCALING_MODE;
            transform = QUEUE_BUFFER_INPUT_TRANSFORM;
-           async = QUEUE_BUFFER_INPUT_ASYNC;
            fence = QUEUE_BUFFER_INPUT_FENCE;
         }
 
@@ -143,7 +141,6 @@
                     crop,
                     scalingMode,
                     transform,
-                    async,
                     fence);
         }
 
@@ -177,11 +174,6 @@
             return *this;
         }
 
-        QueueBufferInputBuilder& setAsync(bool async) {
-            this->async = async;
-            return *this;
-        }
-
         QueueBufferInputBuilder& setFence(sp<Fence> fence) {
             this->fence = fence;
             return *this;
@@ -194,7 +186,6 @@
         Rect crop;
         int scalingMode;
         uint32_t transform;
-        int async;
         sp<Fence> fence;
     }; // struct QueueBufferInputBuilder
 
@@ -204,8 +195,28 @@
         sp<Fence> fence;
     };
 
-    status_t dequeueBuffer(bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) {
-        return mProducer->dequeueBuffer(&result->slot, &result->fence, async, w, h, format, usage);
+    status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) {
+        return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage);
+    }
+
+    void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
+            sp<GraphicBuffer> *buffer)
+    {
+        ASSERT_TRUE(slot != NULL);
+        ASSERT_TRUE(fence != NULL);
+        ASSERT_TRUE(buffer != NULL);
+
+        ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH,
+                DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)));
+
+        EXPECT_LE(0, *slot);
+        EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot);
+
+        // Request the buffer (pre-requisite for queueing)
+        ASSERT_OK(mProducer->requestBuffer(*slot, buffer));
     }
 
 private: // hide from test body
@@ -334,12 +345,11 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
 
-    // XX: OK to assume first call returns this flag or not? Not really documented.
-    ASSERT_EQ(OK | IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                     QUEUE_BUFFER_INPUT_ASYNC,
+
+    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+            (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                      DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS));
+                                     TEST_PRODUCER_USAGE_BITS)));
 
     EXPECT_LE(0, dequeuedSlot);
     EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
@@ -400,11 +410,10 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
 
-    ASSERT_EQ(OK | IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                     QUEUE_BUFFER_INPUT_ASYNC,
+    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+            (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                      DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS));
+                                     TEST_PRODUCER_USAGE_BITS)));
 
     // Slot was enqueued without requesting a buffer
     {
@@ -470,30 +479,28 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
 
-    ASSERT_EQ(OK | IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                     QUEUE_BUFFER_INPUT_ASYNC,
+    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+            (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                      DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS));
+                                     TEST_PRODUCER_USAGE_BITS)));
 
     // No return code, but at least test that it doesn't blow up...
     // TODO: add a return code
     mProducer->cancelBuffer(dequeuedSlot, dequeuedFence);
 }
 
-TEST_F(IGraphicBufferProducerTest, SetBufferCount_Succeeds) {
+TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
+    ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+    int minUndequeuedBuffers;
+    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+            &minUndequeuedBuffers));
 
-    // The producer does not wish to set a buffer count
-    EXPECT_OK(mProducer->setBufferCount(0)) << "bufferCount: " << 0;
-    // TODO: how to test "0" buffer count?
+    const int minBuffers = 1;
+    const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
 
-    int minBuffers;
-    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minBuffers));
-
-    // The MIN_UNDEQUEUED_BUFFERS limit is exclusive, so need to increment by at least 1
-    minBuffers++;
-
-    ASSERT_OK(mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers;
+    ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false;
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers))
+            << "bufferCount: " << minBuffers;
 
     std::vector<DequeueBufferResult> dequeueList;
 
@@ -501,72 +508,217 @@
     for (int i = 0; i < minBuffers; ++i) {
         DequeueBufferResult result;
 
-        EXPECT_LE(OK,
-                dequeueBuffer(QUEUE_BUFFER_INPUT_ASYNC,
-                              DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                              TEST_PRODUCER_USAGE_BITS, &result))
+        EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                (dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                              TEST_PRODUCER_USAGE_BITS, &result)))
                 << "iteration: " << i << ", slot: " << result.slot;
 
         dequeueList.push_back(result);
     }
 
     // Cancel every buffer, so we can set buffer count again
-    for (int i = 0; i < minBuffers; ++i) {
-        DequeueBufferResult& result = dequeueList[i];
+    for (auto& result : dequeueList) {
         mProducer->cancelBuffer(result.slot, result.fence);
     }
 
-    ASSERT_OK(mProducer->setBufferCount(BufferQueue::NUM_BUFFER_SLOTS));
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers));
 
-    // Should now be able to dequeue up to NUM_BUFFER_SLOTS times
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; ++i) {
+    // Should now be able to dequeue up to maxBuffers times
+    for (int i = 0; i < maxBuffers; ++i) {
         int dequeuedSlot = -1;
         sp<Fence> dequeuedFence;
 
-        EXPECT_LE(OK,
-                mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                         QUEUE_BUFFER_INPUT_ASYNC,
-                                         DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                         TEST_PRODUCER_USAGE_BITS))
+        EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                                         DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                         DEFAULT_FORMAT,
+                                         TEST_PRODUCER_USAGE_BITS)))
                 << "iteration: " << i << ", slot: " << dequeuedSlot;
     }
 }
 
-TEST_F(IGraphicBufferProducerTest, SetBufferCount_Fails) {
-    int minBuffers;
-    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minBuffers));
+TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
+    ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+    int minUndequeuedBuffers;
+    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                               &minUndequeuedBuffers));
 
-    // The MIN_UNDEQUEUED_BUFFERS limit is exclusive, so need to increment by at least 1
-    minBuffers++;
+    const int minBuffers = 1;
+    const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
 
+    ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false;
     // Buffer count was out of range
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(-1)) << "bufferCount: " << -1;
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(minBuffers - 1)) << "bufferCount: " << minBuffers - 1;
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(BufferQueue::NUM_BUFFER_SLOTS + 1))
-            << "bufferCount: " << BufferQueue::NUM_BUFFER_SLOTS + 1;
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0))
+            << "bufferCount: " << 0;
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
+            << "bufferCount: " << maxBuffers + 1;
 
-    // Pre-requisite to fail out a valid setBufferCount call
+    // Prerequisite to fail out a valid setBufferCount call
     {
         int dequeuedSlot = -1;
         sp<Fence> dequeuedFence;
 
-        ASSERT_LE(OK,
-                mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                         QUEUE_BUFFER_INPUT_ASYNC,
-                                         DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                         TEST_PRODUCER_USAGE_BITS))
+        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                                         DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                         DEFAULT_FORMAT,
+                                         TEST_PRODUCER_USAGE_BITS)))
                 << "slot: " << dequeuedSlot;
     }
 
     // Client has one or more buffers dequeued
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers;
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(minBuffers))
+            << "bufferCount: " << minBuffers;
 
     // Abandon buffer queue
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // Fail because the buffer queue was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers;
+    EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
+            << "bufferCount: " << minBuffers;
 
 }
 
+TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+    ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
+    ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+    ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1)) << "maxDequeue: " << 1;
+
+    int dequeuedSlot = -1;
+    sp<Fence> dequeuedFence;
+    IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<GraphicBuffer> dequeuedBuffer;
+
+    // Should now be able to queue/dequeue as many buffers as we want without
+    // blocking
+    for (int i = 0; i < 5; ++i) {
+        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                TEST_PRODUCER_USAGE_BITS))) << "slot : " << dequeuedSlot;
+        ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer));
+        ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
+    }
+}
+
+TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
+    ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+    // Prerequisite to fail out a valid setBufferCount call
+    {
+        int dequeuedSlot = -1;
+        sp<Fence> dequeuedFence;
+
+        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot;
+    }
+
+    // Abandon buffer queue
+    ASSERT_OK(mConsumer->consumerDisconnect());
+
+    // Fail because the buffer queue was abandoned
+    EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: "
+            << false;
+}
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_dequeueBuffer) {
+    int slot = -1;
+    sp<Fence> fence;
+
+    ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
+            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS));
+}
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_detachNextBuffer) {
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
+}
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_requestBuffer) {
+    ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+    int slot = -1;
+    sp<Fence> fence;
+
+    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+            (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
+            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)));
+
+    EXPECT_LE(0, slot);
+    EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot);
+
+    ASSERT_OK(mProducer->disconnect(TEST_API));
+
+    sp<GraphicBuffer> buffer;
+
+    ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer));
+}
+
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_detachBuffer) {
+    int slot = -1;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    setupDequeueRequestBuffer(&slot, &fence, &buffer);
+
+    ASSERT_OK(mProducer->disconnect(TEST_API));
+
+    ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
+}
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_queueBuffer) {
+    int slot = -1;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    setupDequeueRequestBuffer(&slot, &fence, &buffer);
+
+    ASSERT_OK(mProducer->disconnect(TEST_API));
+
+    // A generic "valid" input
+    IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+    IGraphicBufferProducer::QueueBufferOutput output;
+
+    ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output));
+}
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_cancelBuffer) {
+    int slot = -1;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    setupDequeueRequestBuffer(&slot, &fence, &buffer);
+
+    ASSERT_OK(mProducer->disconnect(TEST_API));
+
+    ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence));
+}
+
+TEST_F(IGraphicBufferProducerTest,
+        DisconnectedProducerReturnsError_attachBuffer) {
+    int slot = -1;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    setupDequeueRequestBuffer(&slot, &fence, &buffer);
+
+    ASSERT_OK(mProducer->detachBuffer(slot));
+
+    ASSERT_OK(mProducer->disconnect(TEST_API));
+
+    ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+}
+
 } // namespace android
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index 00cc39d..c7ce263 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -103,7 +103,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
@@ -114,9 +114,8 @@
     ASSERT_EQ(OK, buffer->unlock());
 
     IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
-            HAL_DATASPACE_UNKNOWN,
-            Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false,
-            Fence::NO_FENCE);
+            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
 
     BufferItem item;
@@ -128,11 +127,11 @@
     ASSERT_EQ(*dataOut, TEST_DATA);
     ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
 
-    ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
+    ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
             EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
 
     ASSERT_EQ(1, allocator->getAllocCount());
@@ -170,7 +169,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
@@ -181,9 +180,8 @@
     ASSERT_EQ(OK, buffer->unlock());
 
     IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
-            HAL_DATASPACE_UNKNOWN,
-            Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false,
-            Fence::NO_FENCE);
+            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
 
     for (int output = 0; output < NUM_OUTPUTS; ++output) {
@@ -196,13 +194,13 @@
         ASSERT_EQ(*dataOut, TEST_DATA);
         ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
 
-        ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mBuf,
+        ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mSlot,
                     item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
                     Fence::NO_FENCE));
     }
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
 
     ASSERT_EQ(1, allocator->getAllocCount());
@@ -231,7 +229,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
                     GRALLOC_USAGE_SW_WRITE_OFTEN));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
@@ -239,14 +237,13 @@
     outputConsumer->consumerDisconnect();
 
     IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
-            HAL_DATASPACE_UNKNOWN,
-            Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false,
-            Fence::NO_FENCE);
+            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
     ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
 
     // Input should be abandoned
-    ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, false, 0, 0,
-            0, GRALLOC_USAGE_SW_WRITE_OFTEN));
+    ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
+            GRALLOC_USAGE_SW_WRITE_OFTEN));
 }
 
 } // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 1a50b24..2356f54 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -37,7 +37,8 @@
     SurfaceTextureClientTest():
             mEglDisplay(EGL_NO_DISPLAY),
             mEglSurface(EGL_NO_SURFACE),
-            mEglContext(EGL_NO_CONTEXT) {
+            mEglContext(EGL_NO_CONTEXT),
+            mEglConfig(NULL) {
     }
 
     virtual void SetUp() {
@@ -215,6 +216,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ANativeWindowBuffer* buf;
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
     EXPECT_EQ(1, buf->width);
@@ -224,6 +226,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
     EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565));
@@ -235,6 +238,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0));
     EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565));
@@ -246,6 +250,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
     EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
@@ -257,6 +262,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
     EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
@@ -275,6 +281,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0));
     EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565));
@@ -292,6 +299,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     sp<GLConsumer> st(mST);
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
@@ -304,6 +312,7 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
     ANativeWindowBuffer* buf[2];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -324,6 +333,7 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
     ANativeWindowBuffer* buf[2];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -350,6 +360,7 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
     android_native_buffer_t* buf[3];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 0));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
 
@@ -373,6 +384,7 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
     android_native_buffer_t* buf[3];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -393,6 +405,7 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
     android_native_buffer_t* buf[3];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -413,8 +426,8 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
     android_native_buffer_t* buf[3];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
-
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
     EXPECT_EQ(OK, mST->updateTexImage());
@@ -438,6 +451,7 @@
 TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
     android_native_buffer_t* buf[3];
     android_native_buffer_t* firstBuf;
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
     ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
@@ -457,6 +471,7 @@
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
     android_native_buffer_t* buf[3];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
 
     // We should be able to dequeue all the buffers before we've queued mANWy.
@@ -482,6 +497,7 @@
 }
 
 TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     android_native_rect_t rect = {-2, -13, 40, 18};
     native_window_set_crop(mANW.get(), &rect);
 
@@ -536,6 +552,7 @@
     };
 
     android_native_buffer_t* buf[3];
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
     // dequeue/queue/update so we have a current buffer
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -559,6 +576,7 @@
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
@@ -589,6 +607,7 @@
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) {
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
@@ -638,6 +657,7 @@
     crop.right = 5;
     crop.bottom = 5;
 
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
     ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 8));
     ASSERT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index c243fc0..0606839 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -27,6 +27,8 @@
     const int texWidth = 64;
     const int texHeight = 64;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
index 9776733..c4d0aaa 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
@@ -31,6 +31,8 @@
         }
     };
 
+    SetUpWindowAndContext();
+
     runProducerThread(new PT());
 
     mFC->waitForFrame();
@@ -50,6 +52,8 @@
         }
     };
 
+    SetUpWindowAndContext();
+
     runProducerThread(new PT());
 
     mFC->waitForFrame();
@@ -75,6 +79,8 @@
         }
     };
 
+    SetUpWindowAndContext();
+
     runProducerThread(new PT());
 
     for (int i = 0; i < NUM_ITERATIONS; i++) {
@@ -104,6 +110,8 @@
         }
     };
 
+    SetUpWindowAndContext();
+
     runProducerThread(new PT());
 
     for (int i = 0; i < NUM_ITERATIONS; i++) {
@@ -134,7 +142,7 @@
         }
     };
 
-    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
+    SetUpWindowAndContext();
 
     runProducerThread(new PT());
 
diff --git a/libs/gui/tests/SurfaceTextureGLToGL.h b/libs/gui/tests/SurfaceTextureGLToGL.h
index 5a2eff3..5d43a48 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLToGL.h
@@ -34,7 +34,9 @@
 
     virtual void SetUp() {
         SurfaceTextureGLTest::SetUp();
+    }
 
+    void SetUpWindowAndContext() {
         mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
                 mANW.get(), NULL);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index 6edbfb8..c28b4d1 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -29,8 +29,11 @@
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
 
     // This test requires 3 buffers to avoid deadlock because we're
-    // both producer and consumer, and only using one thread.
-    mST->setDefaultMaxBufferCount(3);
+    // both producer and consumer, and only using one thread. Set max dequeued
+    // to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+
+    SetUpWindowAndContext();
 
     // Do the producer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -81,7 +84,10 @@
     mST->setDefaultBufferSize(texWidth, texHeight);
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+
+    SetUpWindowAndContext();
 
     // Do the producer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -150,6 +156,7 @@
 }
 
 TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
+    SetUpWindowAndContext();
     sp<GraphicBuffer> buffers[2];
 
     // This test requires async mode to run on a single thread.
@@ -195,6 +202,7 @@
 }
 
 TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
+    SetUpWindowAndContext();
     sp<GraphicBuffer> buffers[3];
 
     // This test requires async mode to run on a single thread.
@@ -252,6 +260,7 @@
 }
 
 TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) {
+    SetUpWindowAndContext();
     sp<GraphicBuffer> buffer;
 
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -289,6 +298,7 @@
 }
 
 TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) {
+    SetUpWindowAndContext();
     sp<GraphicBuffer> buffer;
 
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -330,7 +340,10 @@
     enum { texHeight = 64 };
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+
+    SetUpWindowAndContext();
 
     // Set the user buffer size.
     native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
@@ -387,7 +400,10 @@
     enum { texHeight = 16 };
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+
+    SetUpWindowAndContext();
 
     // Set the transform hint.
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -448,7 +464,10 @@
     enum { texHeight = 16 };
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+
+    SetUpWindowAndContext();
 
     // Set the transform hint.
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index fad133f..1a904b5 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -28,6 +28,8 @@
     const int texWidth = 64;
     const int texHeight = 66;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -76,6 +78,8 @@
     const int texWidth = 64;
     const int texHeight = 64;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -124,6 +128,8 @@
     const int texWidth = 64;
     const int texHeight = 66;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -190,7 +196,8 @@
     enum { texHeight = 16 };
     enum { numFrames = 1024 };
 
-    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -334,6 +341,8 @@
     const int texWidth = 64;
     const int texHeight = 66;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -378,6 +387,8 @@
     const int texWidth = 64;
     const int texHeight = 64;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -436,7 +447,10 @@
         virtual bool threadLoop() {
             ANativeWindowBuffer* anb;
 
-            native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL);
+            if (native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU) !=
+                    NO_ERROR) {
+                return false;
+            }
 
             for (int numFrames =0 ; numFrames < 2; numFrames ++) {
 
@@ -453,7 +467,10 @@
                 }
             }
 
-            native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL);
+            if (native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU)
+                    != NO_ERROR) {
+                return false;
+            }
 
             return false;
         }
@@ -487,7 +504,7 @@
 // attempt to release a buffer that it does not owned
 TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
     ASSERT_EQ(OK, native_window_api_connect(mANW.get(),
-            NATIVE_WINDOW_API_EGL));
+            NATIVE_WINDOW_API_CPU));
 
     ANativeWindowBuffer *anb;
 
@@ -501,9 +518,9 @@
     EXPECT_EQ(OK,mST->updateTexImage());
 
     ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(),
-            NATIVE_WINDOW_API_EGL));
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(OK, native_window_api_connect(mANW.get(),
-            NATIVE_WINDOW_API_EGL));
+            NATIVE_WINDOW_API_CPU));
 
     EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
@@ -513,7 +530,7 @@
     EXPECT_EQ(OK,mST->updateTexImage());
 
     ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(),
-            NATIVE_WINDOW_API_EGL));
+            NATIVE_WINDOW_API_CPU));
 }
 
 TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
@@ -615,6 +632,11 @@
             Mutex::Autolock lock(mMutex);
             ANativeWindowBuffer* anb;
 
+            if (native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU) !=
+                    NO_ERROR) {
+                return false;
+            }
+
             // Frame 1
             if (native_window_dequeue_buffer_and_wait(mANW.get(),
                     &anb) != NO_ERROR) {
@@ -658,8 +680,6 @@
         Mutex mMutex;
     };
 
-    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
-
     sp<Thread> pt(new ProducerThread(mANW));
     pt->run();
 
@@ -681,6 +701,9 @@
     int texHeight = 16;
     ANativeWindowBuffer* anb;
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(),
+            NATIVE_WINDOW_API_CPU));
+
     GLint maxTextureSize;
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 
diff --git a/libs/gui/tests/SurfaceTextureMultiContextGL.h b/libs/gui/tests/SurfaceTextureMultiContextGL.h
index 7934bbc..3cca035 100644
--- a/libs/gui/tests/SurfaceTextureMultiContextGL.h
+++ b/libs/gui/tests/SurfaceTextureMultiContextGL.h
@@ -27,7 +27,8 @@
     enum { THIRD_TEX_ID = 456 };
 
     SurfaceTextureMultiContextGLTest():
-            mSecondEglContext(EGL_NO_CONTEXT) {
+            mSecondEglContext(EGL_NO_CONTEXT),
+            mThirdEglContext(EGL_NO_CONTEXT) {
     }
 
     virtual void SetUp() {
diff --git a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
index 1cd101e..5b02dcf 100644
--- a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
@@ -26,6 +26,7 @@
 namespace android {
 
 TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -40,6 +41,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -55,6 +57,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         DetachFromContextSucceedsAfterProducerDisconnect) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -70,6 +73,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -82,6 +86,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -96,6 +101,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -112,6 +118,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -128,6 +135,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Detach from the primary context.
@@ -139,6 +147,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -169,6 +178,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         AttachToContextSucceedsAfterProducerDisconnect) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -200,6 +210,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         AttachToContextSucceedsBeforeUpdateTexImage) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Detach from the primary context.
@@ -230,6 +241,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -247,6 +259,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -259,6 +272,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         AttachToContextFailsWhenAttachedBeforeUpdateTexImage) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Attempt to attach to the primary context.
@@ -266,6 +280,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -285,6 +300,7 @@
 }
 
 TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Latch the texture contents on the primary context.
@@ -323,6 +339,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         AttachToContextSucceedsTwiceBeforeUpdateTexImage) {
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
     // Detach from the primary context.
@@ -361,7 +378,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
-    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
 
     // produce two frames and consume them both on the primary context
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
@@ -388,7 +405,7 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
        AttachAfterDisplayTerminatedSucceeds) {
-    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
+    ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
 
     // produce two frames and consume them both on the primary context
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3f495f8..6f0104a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -100,6 +100,8 @@
     ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
+            NATIVE_WINDOW_API_CPU));
     // Set the PROTECTED usage bit and verify that the screenshot fails.  Note
     // that we need to dequeue a buffer in order for it to actually get
     // allocated in SurfaceFlinger.
@@ -190,6 +192,8 @@
     // Allocate a buffer with a generation number of 0
     ANativeWindowBuffer* buffer;
     int fenceFd;
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(),
+            NATIVE_WINDOW_API_CPU));
     ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd));
     ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd));
 
diff --git a/libs/gui/tests/TextureRenderer.cpp b/libs/gui/tests/TextureRenderer.cpp
index 90951b3..e822e6e 100644
--- a/libs/gui/tests/TextureRenderer.cpp
+++ b/libs/gui/tests/TextureRenderer.cpp
@@ -28,7 +28,8 @@
 namespace android {
 
 TextureRenderer::TextureRenderer(GLuint texName,
-        const sp<GLConsumer>& st) : mTexName(texName), mST(st) {
+        const sp<GLConsumer>& st) : mTexName(texName), mST(st), mPgm(0),
+        mPositionHandle(-1), mTexSamplerHandle(-1), mTexMatrixHandle(-1) {
 }
 
 void TextureRenderer::SetUp() {
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 3ead25c..59db157 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -74,7 +74,7 @@
  */
 
 FramebufferNativeWindow::FramebufferNativeWindow()
-    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
+    : BASE(), fbDev(0), grDev(0), mCurrentBufferIndex(0), mUpdateOnDemand(false)
 {
     hw_module_t const* module;
     if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index e55db30..4fe0946 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -43,7 +43,7 @@
 
 GraphicBuffer::GraphicBuffer()
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId())
+      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
 {
     width  =
     height =
@@ -56,7 +56,7 @@
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
         PixelFormat inFormat, uint32_t inUsage)
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId())
+      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
 {
     width  =
     height =
@@ -72,7 +72,7 @@
         native_handle_t* inHandle, bool keepOwnership)
     : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
       mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId())
+      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
 {
     width  = static_cast<int>(inWidth);
     height = static_cast<int>(inHeight);
@@ -85,7 +85,8 @@
 GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
     : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
       mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId())
+      mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId()),
+      mGenerationNumber(0)
 {
     width  = buffer->width;
     height = buffer->height;
@@ -112,6 +113,7 @@
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
     }
+    handle = NULL;
     mWrappedBuffer = 0;
 }
 
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index dcce21f..99cbedc 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -20,6 +20,7 @@
 namespace android {
 
 const Rect Rect::INVALID_RECT{0, 0, -1, -1};
+const Rect Rect::EMPTY_RECT{0, 0, 0, 0};
 
 static inline int32_t min(int32_t a, int32_t b) {
     return (a < b) ? a : b;
@@ -110,7 +111,7 @@
 }
 
 Rect Rect::reduce(const Rect& exclude) const {
-    Rect result;
+    Rect result(Rect::EMPTY_RECT);
 
     uint32_t mask = 0;
     mask |= (exclude.left   > left)   ? 1 : 0;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index a3558bd..ac37990 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -798,7 +798,7 @@
     Region result;
     result.mStorage.clear();
     for (size_t r = 0; r < numRects; ++r) {
-        Rect rect;
+        Rect rect(Rect::EMPTY_RECT);
         status_t status = rect.unflatten(buffer, size);
         if (status != NO_ERROR) {
             return status;
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
index b828175..0a7fc27 100644
--- a/services/inputflinger/host/Android.mk
+++ b/services/inputflinger/host/Android.mk
@@ -58,5 +58,6 @@
 	libutils
 
 LOCAL_MODULE := inputflinger
+LOCAL_INIT_RC := inputflinger.rc
 
 include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 630a596..bd11d56 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
+#include <functional>
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
+#include <vector>
 
 #define LOG_TAG "InputDriver"
 
@@ -25,11 +28,64 @@
 #include "InputHost.h"
 
 #include <hardware/input.h>
+#include <input/InputDevice.h>
 #include <utils/Log.h>
+#include <utils/PropertyMap.h>
 #include <utils/String8.h>
 
 #define INDENT2 "    "
 
+struct input_property_map {
+    android::PropertyMap* propertyMap;
+};
+
+struct input_property {
+    android::String8 key;
+    android::String8 value;
+};
+
+struct input_device_identifier {
+    const char* name;
+    const char* uniqueId;
+    input_bus_t bus;
+    int32_t     vendorId;
+    int32_t     productId;
+    int32_t     version;
+};
+
+struct input_device_definition {
+    std::vector<input_report_definition*> reportDefs;
+};
+
+struct input_device_handle {
+    input_device_identifier_t* id;
+    input_device_definition_t* def;
+};
+
+struct input_int_usage {
+    input_usage_t usage;
+    int32_t min;
+    int32_t max;
+    float   resolution;
+};
+
+struct input_collection {
+    int32_t arity;
+    std::vector<input_int_usage> intUsages;
+    std::vector<input_usage_t> boolUsages;
+};
+
+struct InputCollectionIdHasher {
+    std::size_t operator()(const input_collection_id& id) const {
+        return std::hash<int>()(static_cast<int>(id));
+    }
+};
+
+struct input_report_definition {
+    std::unordered_map<input_collection_id_t, input_collection, InputCollectionIdHasher> collections;
+};
+
+
 namespace android {
 
 static input_host_callbacks_t kCallbacks = {
@@ -37,6 +93,7 @@
     .create_device_definition = create_device_definition,
     .create_input_report_definition = create_input_report_definition,
     .create_output_report_definition = create_output_report_definition,
+    .free_report_definition = free_report_definition,
     .input_device_definition_add_report = input_device_definition_add_report,
     .input_report_definition_add_collection = input_report_definition_add_collection,
     .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
@@ -61,86 +118,295 @@
     mHal = reinterpret_cast<const input_module_t*>(module);
 }
 
-void InputDriver::init(InputHostInterface* host) {
-    mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks);
+void InputDriver::init() {
+    mHal->init(mHal, static_cast<input_host_t*>(this), kCallbacks);
+}
+
+input_device_identifier_t* InputDriver::createDeviceIdentifier(
+            const char* name, int32_t productId, int32_t vendorId,
+            input_bus_t bus, const char* uniqueId) {
+    auto identifier = new ::input_device_identifier {
+        .name = name,
+        .productId = productId,
+        .vendorId = vendorId,
+        .bus = bus,
+        .uniqueId = uniqueId,
+    };
+    // TODO: store this identifier somewhere
+    return identifier;
+}
+
+input_device_definition_t* InputDriver::createDeviceDefinition() {
+    return new ::input_device_definition;
+}
+
+input_report_definition_t* InputDriver::createInputReportDefinition() {
+    return new ::input_report_definition;
+}
+
+input_report_definition_t* InputDriver::createOutputReportDefinition() {
+    return new ::input_report_definition;
+}
+
+void InputDriver::freeReportDefinition(input_report_definition_t* reportDef) {
+    delete reportDef;
+}
+
+void InputDriver::inputDeviceDefinitionAddReport(input_device_definition_t* d,
+        input_report_definition_t* r) {
+    d->reportDefs.push_back(r);
+}
+
+void InputDriver::inputReportDefinitionAddCollection(input_report_definition_t* report,
+        input_collection_id_t id, int32_t arity) {
+    report->collections[id] = {.arity = arity};
+}
+
+void InputDriver::inputReportDefinitionDeclareUsageInt(input_report_definition_t* report,
+        input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max,
+        float resolution) {
+    if (report->collections.find(id) != report->collections.end()) {
+        report->collections[id].intUsages.push_back({
+                .usage = usage, .min = min, .max = max, .resolution = resolution});
+    }
+}
+
+void InputDriver::inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report,
+        input_collection_id_t id, input_usage_t* usage, size_t usageCount) {
+    if (report->collections.find(id) != report->collections.end()) {
+        for (size_t i = 0; i < usageCount; ++i) {
+            report->collections[id].boolUsages.push_back(usage[i]);
+        }
+    }
+}
+
+input_device_handle_t* InputDriver::registerDevice(input_device_identifier_t* id,
+        input_device_definition_t* d) {
+    ALOGD("Registering device %s with %zu input reports", id->name, d->reportDefs.size());
+    // TODO: save this device handle
+    return new input_device_handle{ .id = id, .def = d };
+}
+
+void InputDriver::unregisterDevice(input_device_handle_t* handle) {
+    delete handle;
+}
+
+input_report_t* InputDriver::inputAllocateReport(input_report_definition_t* r) {
+    ALOGD("Allocating input report for definition %p", r);
+    return nullptr;
+}
+
+void InputDriver::inputReportSetUsageInt(input_report_t* r, input_collection_id_t id,
+        input_usage_t usage, int32_t value, int32_t arity_index) {
+}
+
+void InputDriver::inputReportSetUsageBool(input_report_t* r, input_collection_id_t id,
+        input_usage_t usage, bool value, int32_t arity_index) {
+}
+
+void InputDriver::reportEvent(input_device_handle_t* d, input_report_t* report) {
+    ALOGD("report_event %p for handle %p", report, d);
+}
+
+input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identifier_t* id) {
+    InputDeviceIdentifier idi;
+    idi.name = id->name;
+    idi.uniqueId = id->uniqueId;
+    idi.bus = id->bus;
+    idi.vendor = id->vendorId;
+    idi.product = id->productId;
+    idi.version = id->version;
+
+    String8 configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
+            idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
+    if (configFile.isEmpty()) {
+        ALOGD("No input device configuration file found for device '%s'.",
+                idi.name.string());
+    } else {
+        auto propMap = new input_property_map_t();
+        status_t status = PropertyMap::load(configFile, &propMap->propertyMap);
+        if (status) {
+            ALOGE("Error loading input device configuration file for device '%s'. "
+                    "Using default configuration.",
+                    idi.name.string());
+            delete propMap;
+            return nullptr;
+        }
+        return propMap;
+    }
+    return nullptr;
+}
+
+input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map,
+        const char* key) {
+    String8 keyString(key);
+    if (map != nullptr) {
+        if (map->propertyMap->hasProperty(keyString)) {
+            auto prop = new input_property_t();
+            if (!map->propertyMap->tryGetProperty(keyString, prop->value)) {
+                delete prop;
+                return nullptr;
+            }
+            prop->key = keyString;
+            return prop;
+        }
+    }
+    return nullptr;
+}
+
+const char* InputDriver::inputGetPropertyKey(input_property_t* property) {
+    if (property != nullptr) {
+        return property->key.string();
+    }
+    return nullptr;
+}
+
+const char* InputDriver::inputGetPropertyValue(input_property_t* property) {
+    if (property != nullptr) {
+        return property->value.string();
+    }
+    return nullptr;
+}
+
+void InputDriver::inputFreeDeviceProperty(input_property_t* property) {
+    if (property != nullptr) {
+        delete property;
+    }
+}
+
+void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) {
+    if (map != nullptr) {
+        delete map->propertyMap;
+        delete map;
+    }
 }
 
 void InputDriver::dump(String8& result) {
     result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string());
 }
 
+} // namespace android
 
 // HAL wrapper functions
 
-input_device_identifier_t* create_device_identifier(input_host_t* host,
+namespace android {
+
+::input_device_identifier_t* create_device_identifier(input_host_t* host,
         const char* name, int32_t product_id, int32_t vendor_id,
         input_bus_t bus, const char* unique_id) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->createDeviceIdentifier(name, product_id, vendor_id, bus, unique_id);
 }
 
 input_device_definition_t* create_device_definition(input_host_t* host) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->createDeviceDefinition();
 }
 
 input_report_definition_t* create_input_report_definition(input_host_t* host) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->createInputReportDefinition();
 }
 
 input_report_definition_t* create_output_report_definition(input_host_t* host) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->createOutputReportDefinition();
+}
+
+void free_report_definition(input_host_t* host, input_report_definition_t* report_def) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->freeReportDefinition(report_def);
 }
 
 void input_device_definition_add_report(input_host_t* host,
-        input_device_definition_t* d, input_report_definition_t* r) { }
+        input_device_definition_t* d, input_report_definition_t* r) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputDeviceDefinitionAddReport(d, r);
+}
 
 void input_report_definition_add_collection(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
+        input_report_definition_t* report, input_collection_id_t id, int32_t arity) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputReportDefinitionAddCollection(report, id, arity);
+}
 
 void input_report_definition_declare_usage_int(input_host_t* host,
         input_report_definition_t* report, input_collection_id_t id,
-        input_usage_t usage, int32_t min, int32_t max, float resolution) { }
+        input_usage_t usage, int32_t min, int32_t max, float resolution) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputReportDefinitionDeclareUsageInt(report, id, usage, min, max, resolution);
+}
 
 void input_report_definition_declare_usages_bool(input_host_t* host,
         input_report_definition_t* report, input_collection_id_t id,
-        input_usage_t* usage, size_t usage_count) { }
-
+        input_usage_t* usage, size_t usage_count) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputReportDefinitionDeclareUsagesBool(report, id, usage, usage_count);
+}
 
 input_device_handle_t* register_device(input_host_t* host,
         input_device_identifier_t* id, input_device_definition_t* d) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->registerDevice(id, d);
+}
+
+void unregister_device(input_host_t* host, input_device_handle_t* handle) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->unregisterDevice(handle);
 }
 
 input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->inputAllocateReport(r);
 }
+
 void input_report_set_usage_int(input_host_t* host, input_report_t* r,
-        input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { }
+        input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputReportSetUsageInt(r, id, usage, value, arity_index);
+}
 
 void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
-        input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { }
+        input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputReportSetUsageBool(r, id, usage, value, arity_index);
+}
 
-void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->reportEvent(d, report);
+}
 
 input_property_map_t* input_get_device_property_map(input_host_t* host,
         input_device_identifier_t* id) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->inputGetDevicePropertyMap(id);
 }
 
 input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
         const char* key) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->inputGetDeviceProperty(map, key);
 }
 
 const char* input_get_property_key(input_host_t* host, input_property_t* property) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->inputGetPropertyKey(property);
 }
 
 const char* input_get_property_value(input_host_t* host, input_property_t* property) {
-    return nullptr;
+    auto driver = static_cast<InputDriverInterface*>(host);
+    return driver->inputGetPropertyValue(property);
 }
 
-void input_free_device_property(input_host_t* host, input_property_t* property) { }
+void input_free_device_property(input_host_t* host, input_property_t* property) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputFreeDeviceProperty(property);
+}
 
-void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { }
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map) {
+    auto driver = static_cast<InputDriverInterface*>(host);
+    driver->inputFreeDevicePropertyMap(map);
+}
 
 } // namespace android
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
index 7734ac2..8d5a31e 100644
--- a/services/inputflinger/host/InputDriver.h
+++ b/services/inputflinger/host/InputDriver.h
@@ -26,17 +26,56 @@
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 
+// Declare a concrete type for the HAL
+struct input_host {
+};
+
 namespace android {
 
-class InputHostInterface;
-
-class InputDriverInterface : public virtual RefBase {
+class InputDriverInterface : public input_host_t, public virtual RefBase {
 protected:
     InputDriverInterface() = default;
     virtual ~InputDriverInterface() = default;
 
 public:
-    virtual void init(InputHostInterface* host) = 0;
+    virtual void init() = 0;
+
+    virtual input_device_identifier_t* createDeviceIdentifier(
+            const char* name, int32_t productId, int32_t vendorId,
+            input_bus_t bus, const char* uniqueId) = 0;
+    virtual input_device_definition_t* createDeviceDefinition() = 0;
+    virtual input_report_definition_t* createInputReportDefinition() = 0;
+    virtual input_report_definition_t* createOutputReportDefinition() = 0;
+    virtual void freeReportDefinition(input_report_definition_t* reportDef) = 0;
+
+    virtual void inputDeviceDefinitionAddReport(input_device_definition_t* d,
+            input_report_definition_t* r) = 0;
+    virtual void inputReportDefinitionAddCollection(input_report_definition_t* report,
+            input_collection_id_t id, int32_t arity) = 0;
+    virtual void inputReportDefinitionDeclareUsageInt(input_report_definition_t* report,
+            input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max,
+            float resolution) = 0;
+    virtual void inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report,
+            input_collection_id_t id, input_usage_t* usage, size_t usageCount) = 0;
+
+    virtual input_device_handle_t* registerDevice(input_device_identifier_t* id,
+            input_device_definition_t* d) = 0;
+    virtual void unregisterDevice(input_device_handle_t* handle) = 0;
+
+    virtual input_report_t* inputAllocateReport(input_report_definition_t* r) = 0;
+    virtual void inputReportSetUsageInt(input_report_t* r, input_collection_id_t id,
+            input_usage_t usage, int32_t value, int32_t arity_index) = 0;
+    virtual void inputReportSetUsageBool(input_report_t* r, input_collection_id_t id,
+            input_usage_t usage, bool value, int32_t arity_index) = 0;
+    virtual void reportEvent(input_device_handle_t* d, input_report_t* report) = 0;
+
+    virtual input_property_map_t* inputGetDevicePropertyMap(input_device_identifier_t* id) = 0;
+    virtual input_property_t* inputGetDeviceProperty(input_property_map_t* map,
+            const char* key) = 0;
+    virtual const char* inputGetPropertyKey(input_property_t* property) = 0;
+    virtual const char* inputGetPropertyValue(input_property_t* property) = 0;
+    virtual void inputFreeDeviceProperty(input_property_t* property) = 0;
+    virtual void inputFreeDevicePropertyMap(input_property_map_t* map) = 0;
 
     virtual void dump(String8& result) = 0;
 };
@@ -46,7 +85,44 @@
     InputDriver(const char* name);
     virtual ~InputDriver() = default;
 
-    virtual void init(InputHostInterface* host) override;
+    virtual void init() override;
+
+    virtual input_device_identifier_t* createDeviceIdentifier(
+            const char* name, int32_t productId, int32_t vendorId,
+            input_bus_t bus, const char* uniqueId) override;
+    virtual input_device_definition_t* createDeviceDefinition() override;
+    virtual input_report_definition_t* createInputReportDefinition() override;
+    virtual input_report_definition_t* createOutputReportDefinition() override;
+    virtual void freeReportDefinition(input_report_definition_t* reportDef) override;
+
+    virtual void inputDeviceDefinitionAddReport(input_device_definition_t* d,
+            input_report_definition_t* r) override;
+    virtual void inputReportDefinitionAddCollection(input_report_definition_t* report,
+            input_collection_id_t id, int32_t arity) override;
+    virtual void inputReportDefinitionDeclareUsageInt(input_report_definition_t* report,
+            input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max,
+            float resolution) override;
+    virtual void inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report,
+            input_collection_id_t id, input_usage_t* usage, size_t usageCount) override;
+
+    virtual input_device_handle_t* registerDevice(input_device_identifier_t* id,
+            input_device_definition_t* d) override;
+    virtual void unregisterDevice(input_device_handle_t* handle) override;
+
+    virtual input_report_t* inputAllocateReport(input_report_definition_t* r) override;
+    virtual void inputReportSetUsageInt(input_report_t* r, input_collection_id_t id,
+            input_usage_t usage, int32_t value, int32_t arity_index) override;
+    virtual void inputReportSetUsageBool(input_report_t* r, input_collection_id_t id,
+            input_usage_t usage, bool value, int32_t arity_index) override;
+    virtual void reportEvent(input_device_handle_t* d, input_report_t* report) override;
+
+    virtual input_property_map_t* inputGetDevicePropertyMap(input_device_identifier_t* id) override;
+    virtual input_property_t* inputGetDeviceProperty(input_property_map_t* map,
+            const char* key) override;
+    virtual const char* inputGetPropertyKey(input_property_t* property) override;
+    virtual const char* inputGetPropertyValue(input_property_t* property) override;
+    virtual void inputFreeDeviceProperty(input_property_t* property) override;
+    virtual void inputFreeDevicePropertyMap(input_property_map_t* map) override;
 
     virtual void dump(String8& result) override;
 
@@ -68,6 +144,8 @@
 
 input_report_definition_t* create_output_report_definition(input_host_t* host);
 
+void free_report_definition(input_host_t* host, input_report_definition_t* report_def);
+
 void input_device_definition_add_report(input_host_t* host,
         input_device_definition_t* d, input_report_definition_t* r);
 
diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp
index 51d3e6b..094200a 100644
--- a/services/inputflinger/host/InputHost.cpp
+++ b/services/inputflinger/host/InputHost.cpp
@@ -28,7 +28,7 @@
 
 void InputHost::registerInputDriver(InputDriverInterface* driver) {
     LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!");
-    driver->init(this);
+    driver->init();
     mDrivers.push_back(driver);
 }
 
diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h
index 42a66e0..eda4a89 100644
--- a/services/inputflinger/host/InputHost.h
+++ b/services/inputflinger/host/InputHost.h
@@ -26,15 +26,11 @@
 
 #include "InputDriver.h"
 
-// Declare a concrete type for the HAL
-struct input_host {
-};
-
 namespace android {
 
 class InputDriverInterface;
 
-class InputHostInterface : public input_host_t, public virtual RefBase {
+class InputHostInterface : public virtual RefBase {
 protected:
     InputHostInterface() = default;
     virtual ~InputHostInterface() = default;
diff --git a/services/inputflinger/host/inputflinger.rc b/services/inputflinger/host/inputflinger.rc
new file mode 100644
index 0000000..ae71ee5
--- /dev/null
+++ b/services/inputflinger/host/inputflinger.rc
@@ -0,0 +1,5 @@
+service inputflinger /system/bin/inputflinger
+    class main
+    user system
+    group input
+#    onrestart restart zygote
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
index b07d544..7b1f346 100644
--- a/services/sensorservice/CorrectedGyroSensor.cpp
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -58,12 +58,12 @@
 
 status_t CorrectedGyroSensor::activate(void* ident, bool enabled) {
     mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_9AXIS, ident, enabled);
 }
 
 status_t CorrectedGyroSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     mSensorDevice.setDelay(ident, mGyro.getHandle(), ns);
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
 Sensor CorrectedGyroSensor::getSensor() const {
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
index 4f63c31..359d289 100644
--- a/services/sensorservice/Fusion.cpp
+++ b/services/sensorservice/Fusion.cpp
@@ -24,28 +24,44 @@
 
 // -----------------------------------------------------------------------
 
+/*==================== BEGIN FUSION SENSOR PARAMETER =========================*/
+
+/* Note:
+ *   If a platform uses software fusion, it is necessary to tune the following
+ *   parameters to fit the hardware sensors prior to release.
+ *
+ *   The DEFAULT_ parameters will be used in FUSION_9AXIS and FUSION_NOMAG mode.
+ *   The GEOMAG_ parameters will be used in FUSION_NOGYRO mode.
+ */
+
 /*
- * gyroVAR gives the measured variance of the gyro's output per
+ * GYRO_VAR gives the measured variance of the gyro's output per
  * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro,
  * which is independent of the sampling frequency.
  *
  * The variance of gyro's output at a given sampling period can be
  * calculated as:
- *      variance(T) = gyroVAR / T
+ *      variance(T) = GYRO_VAR / T
  *
  * The variance of the INTEGRATED OUTPUT at a given sampling period can be
  * calculated as:
- *       variance_integrate_output(T) = gyroVAR * T
- *
+ *       variance_integrate_output(T) = GYRO_VAR * T
  */
-static const float gyroVAR = 1e-7;      // (rad/s)^2 / Hz
-static const float biasVAR = 1e-8;      // (rad/s)^2 / s (guessed)
+static const float DEFAULT_GYRO_VAR = 1e-7;      // (rad/s)^2 / Hz
+static const float DEFAULT_GYRO_BIAS_VAR = 1e-12;  // (rad/s)^2 / s (guessed)
+static const float GEOMAG_GYRO_VAR = 1e-4;      // (rad/s)^2 / Hz
+static const float GEOMAG_GYRO_BIAS_VAR = 1e-8;  // (rad/s)^2 / s (guessed)
 
 /*
  * Standard deviations of accelerometer and magnetometer
  */
-static const float accSTDEV  = 0.05f;   // m/s^2 (measured 0.08 / CDD 0.05)
-static const float magSTDEV  = 0.5f;    // uT    (measured 0.7  / CDD 0.5)
+static const float DEFAULT_ACC_STDEV  = 0.015f; // m/s^2 (measured 0.08 / CDD 0.05)
+static const float DEFAULT_MAG_STDEV  = 0.1f;   // uT    (measured 0.7  / CDD 0.5)
+static const float GEOMAG_ACC_STDEV  = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05)
+static const float GEOMAG_MAG_STDEV  = 0.1f;   // uT    (measured 0.7  / CDD 0.5)
+
+
+/* ====================== END FUSION SENSOR PARAMETER ========================*/
 
 static const float SYMMETRY_TOLERANCE = 1e-10f;
 
@@ -54,7 +70,8 @@
  * ill-conditioning and div by zeros.
  * Threshhold: 10% of g, in m/s^2
  */
-static const float FREE_FALL_THRESHOLD = 0.981f;
+static const float NOMINAL_GRAVITY = 9.81f;
+static const float FREE_FALL_THRESHOLD = 0.1f * (NOMINAL_GRAVITY);
 static const float FREE_FALL_THRESHOLD_SQ =
         FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD;
 
@@ -87,6 +104,9 @@
 static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ =
     MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG;
 
+static const float W_EPS = 1e-4f;
+static const float SQRT_3 = 1.732f;
+static const float WVEC_EPS = 1e-4f/SQRT_3;
 // -----------------------------------------------------------------------
 
 template <typename TYPE, size_t C, size_t R>
@@ -173,7 +193,7 @@
     init();
 }
 
-void Fusion::init() {
+void Fusion::init(int mode) {
     mInitState = 0;
 
     mGyroRate = 0;
@@ -183,6 +203,19 @@
     mCount[2] = 0;
 
     mData = 0;
+    mMode = mode;
+
+    if (mMode != FUSION_NOGYRO) { //normal or game rotation
+        mParam.gyroVar = DEFAULT_GYRO_VAR;
+        mParam.gyroBiasVar = DEFAULT_GYRO_BIAS_VAR;
+        mParam.accStdev = DEFAULT_ACC_STDEV;
+        mParam.magStdev = DEFAULT_MAG_STDEV;
+    } else {
+        mParam.gyroVar = GEOMAG_GYRO_VAR;
+        mParam.gyroBiasVar = GEOMAG_GYRO_BIAS_VAR;
+        mParam.accStdev = GEOMAG_ACC_STDEV;
+        mParam.magStdev = GEOMAG_MAG_STDEV;
+    }
 }
 
 void Fusion::initFusion(const vec4_t& q, float dT)
@@ -205,11 +238,11 @@
     const float dT3 = dT2*dT;
 
     // variance of integrated output at 1/dT Hz (random drift)
-    const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3;
+    const float q00 = mParam.gyroVar * dT + 0.33333f * mParam.gyroBiasVar * dT3;
 
     // variance of drift rate ramp
-    const float q11 = biasVAR * dT;
-    const float q10 = 0.5f * biasVAR * dT2;
+    const float q11 = mParam.gyroBiasVar * dT;
+    const float q10 = 0.5f * mParam.gyroBiasVar * dT2;
     const float q01 = q10;
 
     GQGt[0][0] =  q00;      // rad^2
@@ -223,7 +256,9 @@
 }
 
 bool Fusion::hasEstimate() const {
-    return (mInitState == (MAG|ACC|GYRO));
+    return ((mInitState & MAG) || (mMode == FUSION_NOMAG)) &&
+           ((mInitState & GYRO) || (mMode == FUSION_NOGYRO)) &&
+           (mInitState & ACC);
 }
 
 bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) {
@@ -234,6 +269,9 @@
         mData[0] += d * (1/length(d));
         mCount[0]++;
         mInitState |= ACC;
+        if (mMode == FUSION_NOGYRO ) {
+            mGyroRate = dT;
+        }
     } else if (what == MAG) {
         mData[1] += d * (1/length(d));
         mCount[1]++;
@@ -242,25 +280,29 @@
         mGyroRate = dT;
         mData[2] += d*dT;
         mCount[2]++;
-        if (mCount[2] == 64) {
-            // 64 samples is good enough to estimate the gyro drift and
-            // doesn't take too much time.
-            mInitState |= GYRO;
-        }
+        mInitState |= GYRO;
     }
 
-    if (mInitState == (MAG|ACC|GYRO)) {
+    if (hasEstimate()) {
         // Average all the values we collected so far
         mData[0] *= 1.0f/mCount[0];
-        mData[1] *= 1.0f/mCount[1];
+        if (mMode != FUSION_NOMAG) {
+            mData[1] *= 1.0f/mCount[1];
+        }
         mData[2] *= 1.0f/mCount[2];
 
         // calculate the MRPs from the data collection, this gives us
         // a rough estimate of our initial state
         mat33_t R;
-        vec3_t up(mData[0]);
-        vec3_t east(cross_product(mData[1], up));
-        east *= 1/length(east);
+        vec3_t  up(mData[0]);
+        vec3_t  east;
+
+        if (mMode != FUSION_NOMAG) {
+            east = normalize(cross_product(mData[1], up));
+        } else {
+            east = getOrthogonal(up);
+        }
+
         vec3_t north(cross_product(up, east));
         R << east << north << up;
         const vec4_t q = matrixToQuat(R);
@@ -278,21 +320,43 @@
     predict(w, dT);
 }
 
-status_t Fusion::handleAcc(const vec3_t& a) {
+status_t Fusion::handleAcc(const vec3_t& a, float dT) {
+    if (!checkInitComplete(ACC, a, dT))
+        return BAD_VALUE;
+
     // ignore acceleration data if we're close to free-fall
-    if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) {
+    const float l = length(a);
+    if (l < FREE_FALL_THRESHOLD) {
         return BAD_VALUE;
     }
 
-    if (!checkInitComplete(ACC, a))
-        return BAD_VALUE;
+    const float l_inv = 1.0f/l;
 
-    const float l = 1/length(a);
-    update(a*l, Ba, accSTDEV*l);
+    if ( mMode == FUSION_NOGYRO ) {
+        //geo mag
+        vec3_t w_dummy;
+        w_dummy = x1; //bias
+        predict(w_dummy, dT);
+    }
+
+    if ( mMode == FUSION_NOMAG) {
+        vec3_t m;
+        m = getRotationMatrix()*Bm;
+        update(m, Bm, mParam.magStdev);
+    }
+
+    vec3_t unityA = a * l_inv;
+    const float d = sqrtf(fabsf(l- NOMINAL_GRAVITY));
+    const float p = l_inv * mParam.accStdev*expf(d);
+
+    update(unityA, Ba, p);
     return NO_ERROR;
 }
 
 status_t Fusion::handleMag(const vec3_t& m) {
+    if (!checkInitComplete(MAG, m))
+        return BAD_VALUE;
+
     // the geomagnetic-field should be between 30uT and 60uT
     // reject if too large to avoid spurious magnetic sources
     const float magFieldSq = length_squared(m);
@@ -304,9 +368,6 @@
         return BAD_VALUE;
     }
 
-    if (!checkInitComplete(MAG, m))
-        return BAD_VALUE;
-
     // Orthogonalize the magnetic field to the gravity field, mapping it into
     // tangent to Earth.
     const vec3_t up( getRotationMatrix() * Ba );
@@ -324,10 +385,10 @@
     // then pass it in as the update.
     vec3_t north( cross_product(up, east) );
 
-    const float l = 1 / length(north);
-    north *= l;
+    const float l_inv = 1 / length(north);
+    north *= l_inv;
 
-    update(north, Bm, magSTDEV*l);
+    update(north, Bm,  mParam.magStdev*l_inv);
     return NO_ERROR;
 }
 
@@ -372,8 +433,11 @@
 void Fusion::predict(const vec3_t& w, float dT) {
     const vec4_t q  = x0;
     const vec3_t b  = x1;
-    const vec3_t we = w - b;
+    vec3_t we = w - b;
 
+    if (length(we) < WVEC_EPS) {
+        we = (we[0]>0.f)?WVEC_EPS:-WVEC_EPS;
+    }
     // q(k+1) = O(we)*q(k)
     // --------------------
     //
@@ -406,7 +470,7 @@
     const mat33_t wx2(wx*wx);
     const float lwedT = length(we)*dT;
     const float hlwedT = 0.5f*lwedT;
-    const float ilwe = 1/length(we);
+    const float ilwe = 1.f/length(we);
     const float k0 = (1-cosf(lwedT))*(ilwe*ilwe);
     const float k1 = sinf(lwedT);
     const float k2 = cosf(hlwedT);
@@ -422,6 +486,7 @@
     Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
 
     x0 = O*q;
+
     if (x0.w < 0)
         x0 = -x0;
 
@@ -466,15 +531,37 @@
 
     const vec3_t e(z - Bb);
     const vec3_t dq(K[0]*e);
-    const vec3_t db(K[1]*e);
 
     q += getF(q)*(0.5f*dq);
     x0 = normalize_quat(q);
-    x1 += db;
+
+    if (mMode != FUSION_NOMAG) {
+        const vec3_t db(K[1]*e);
+        x1 += db;
+    }
 
     checkState();
 }
 
+vec3_t Fusion::getOrthogonal(const vec3_t &v) {
+    vec3_t w;
+    if (fabsf(v[0])<= fabsf(v[1]) && fabsf(v[0]) <= fabsf(v[2]))  {
+        w[0]=0.f;
+        w[1] = v[2];
+        w[2] = -v[1];
+    } else if (fabsf(v[1]) <= fabsf(v[2])) {
+        w[0] = v[2];
+        w[1] = 0.f;
+        w[2] = -v[0];
+    }else {
+        w[0] = v[1];
+        w[1] = -v[0];
+        w[2] = 0.f;
+    }
+    return normalize(w);
+}
+
+
 // -----------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
index 7062999..602779f 100644
--- a/services/sensorservice/Fusion.h
+++ b/services/sensorservice/Fusion.h
@@ -27,6 +27,13 @@
 
 typedef mat<float, 3, 4> mat34_t;
 
+enum FUSION_MODE{
+    FUSION_9AXIS, // use accel gyro mag
+    FUSION_NOMAG, // use accel gyro (game rotation, gravity)
+    FUSION_NOGYRO, // use accel mag (geomag rotation)
+    NUM_FUSION_MODE
+};
+
 class Fusion {
     /*
      * the state vector is made of two sub-vector containing respectively:
@@ -55,9 +62,9 @@
 
 public:
     Fusion();
-    void init();
+    void init(int mode = FUSION_9AXIS);
     void handleGyro(const vec3_t& w, float dT);
-    status_t handleAcc(const vec3_t& a);
+    status_t handleAcc(const vec3_t& a, float dT);
     status_t handleMag(const vec3_t& m);
     vec4_t getAttitude() const;
     vec3_t getBias() const;
@@ -65,12 +72,21 @@
     bool hasEstimate() const;
 
 private:
+    struct Parameter {
+        float gyroVar;
+        float gyroBiasVar;
+        float accStdev;
+        float magStdev;
+    } mParam;
+
     mat<mat33_t, 2, 2> Phi;
     vec3_t Ba, Bm;
     uint32_t mInitState;
     float mGyroRate;
     vec<vec3_t, 3> mData;
     size_t mCount[3];
+    int mMode;
+
     enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
     bool checkInitComplete(int, const vec3_t& w, float d = 0);
     void initFusion(const vec4_t& q0, float dT);
@@ -78,6 +94,7 @@
     void predict(const vec3_t& w, float dT);
     void update(const vec3_t& z, const vec3_t& Bi, float sigma);
     static mat34_t getF(const vec4_t& p);
+    static vec3_t getOrthogonal(const vec3_t &v);
 };
 
 }; // namespace android
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 61118bc..a165a5b 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -46,9 +46,9 @@
 {
     if (event.type == SENSOR_TYPE_ACCELEROMETER) {
         vec3_t g;
-        if (!mSensorFusion.hasEstimate())
+        if (!mSensorFusion.hasEstimate(FUSION_NOMAG))
             return false;
-        const mat33_t R(mSensorFusion.getRotationMatrix());
+        const mat33_t R(mSensorFusion.getRotationMatrix(FUSION_NOMAG));
         // FIXME: we need to estimate the length of gravity because
         // the accelerometer may have a small scaling error. This
         // translates to an offset in the linear-acceleration sensor.
@@ -66,11 +66,11 @@
 }
 
 status_t GravitySensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_NOMAG, ident, enabled);
 }
 
 status_t GravitySensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_NOMAG, ident, ns);
 }
 
 Sensor GravitySensor::getSensor() const {
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
index 6d85cca..d55f336 100644
--- a/services/sensorservice/OrientationSensor.cpp
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -66,11 +66,11 @@
 }
 
 status_t OrientationSensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_9AXIS, ident, enabled);
 }
 
 status_t OrientationSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
 Sensor OrientationSensor::getSensor() const {
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index cb305eb..238845b 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -27,9 +27,10 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-RotationVectorSensor::RotationVectorSensor()
+RotationVectorSensor::RotationVectorSensor(int mode)
     : mSensorDevice(SensorDevice::getInstance()),
-      mSensorFusion(SensorFusion::getInstance())
+      mSensorFusion(SensorFusion::getInstance()),
+      mMode(mode)
 {
 }
 
@@ -37,15 +38,15 @@
         const sensors_event_t& event)
 {
     if (event.type == SENSOR_TYPE_ACCELEROMETER) {
-        if (mSensorFusion.hasEstimate()) {
-            const vec4_t q(mSensorFusion.getAttitude());
+        if (mSensorFusion.hasEstimate(mMode)) {
+            const vec4_t q(mSensorFusion.getAttitude(mMode));
             *outEvent = event;
             outEvent->data[0] = q.x;
             outEvent->data[1] = q.y;
             outEvent->data[2] = q.z;
             outEvent->data[3] = q.w;
-            outEvent->sensor = '_rov';
-            outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
+            outEvent->sensor = getSensorToken();
+            outEvent->type = getSensorType();
             return true;
         }
     }
@@ -53,20 +54,20 @@
 }
 
 status_t RotationVectorSensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(mMode, ident, enabled);
 }
 
 status_t RotationVectorSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(mMode, ident, ns);
 }
 
 Sensor RotationVectorSensor::getSensor() const {
     sensor_t hwSensor;
-    hwSensor.name       = "Rotation Vector Sensor";
+    hwSensor.name       = getSensorName();
     hwSensor.vendor     = "AOSP";
     hwSensor.version    = 3;
-    hwSensor.handle     = '_rov';
-    hwSensor.type       = SENSOR_TYPE_ROTATION_VECTOR;
+    hwSensor.handle     = getSensorToken();
+    hwSensor.type       = getSensorType();
     hwSensor.maxRange   = 1;
     hwSensor.resolution = 1.0f / (1<<24);
     hwSensor.power      = mSensorFusion.getPowerUsage();
@@ -75,6 +76,48 @@
     return sensor;
 }
 
+int RotationVectorSensor::getSensorType() const {
+    switch(mMode) {
+        case FUSION_9AXIS:
+            return SENSOR_TYPE_ROTATION_VECTOR;
+        case FUSION_NOMAG:
+            return SENSOR_TYPE_GAME_ROTATION_VECTOR;
+        case FUSION_NOGYRO:
+            return SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+        default:
+            assert(0);
+            return 0;
+    }
+}
+
+const char* RotationVectorSensor::getSensorName() const {
+    switch(mMode) {
+        case FUSION_9AXIS:
+            return "Rotation Vector Sensor";
+        case FUSION_NOMAG:
+            return "Game Rotation Vector Sensor";
+        case FUSION_NOGYRO:
+            return "GeoMag Rotation Vector Sensor";
+        default:
+            assert(0);
+            return NULL;
+    }
+}
+
+int RotationVectorSensor::getSensorToken() const {
+    switch(mMode) {
+        case FUSION_9AXIS:
+            return '_rov';
+        case FUSION_NOMAG:
+            return '_gar';
+        case FUSION_NOGYRO:
+            return '_geo';
+        default:
+            assert(0);
+            return 0;
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 GyroDriftSensor::GyroDriftSensor()
@@ -102,11 +145,11 @@
 }
 
 status_t GyroDriftSensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_9AXIS, ident, enabled);
 }
 
 status_t GyroDriftSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
 Sensor GyroDriftSensor::getSensor() const {
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index bb97fe1..1fc316b 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -35,9 +35,14 @@
 class RotationVectorSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
+    int mMode;
+
+    int getSensorType() const;
+    const char* getSensorName() const ;
+    int getSensorToken() const ;
 
 public:
-    RotationVectorSensor();
+    RotationVectorSensor(int mode = FUSION_9AXIS);
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
     virtual status_t activate(void* ident, bool enabled);
@@ -46,6 +51,16 @@
     virtual bool isVirtual() const { return true; }
 };
 
+class GameRotationVectorSensor : public RotationVectorSensor {
+public:
+    GameRotationVectorSensor() : RotationVectorSensor(FUSION_NOMAG) {}
+};
+
+class GeoMagRotationVectorSensor : public RotationVectorSensor {
+public:
+    GeoMagRotationVectorSensor() : RotationVectorSensor(FUSION_NOGYRO) {}
+};
+
 class GyroDriftSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 6d93009..9863f62 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -25,11 +25,17 @@
 
 SensorFusion::SensorFusion()
     : mSensorDevice(SensorDevice::getInstance()),
-      mEnabled(false), mGyroTime(0)
+      mAttitude(mAttitudes[FUSION_9AXIS]),
+      mGyroTime(0), mAccTime(0)
 {
     sensor_t const* list;
     Sensor uncalibratedGyro;
     ssize_t count = mSensorDevice.getSensorList(&list);
+
+    mEnabled[FUSION_9AXIS] = false;
+    mEnabled[FUSION_NOMAG] = false;
+    mEnabled[FUSION_NOGYRO] = false;
+
     if (count > 0) {
         for (size_t i=0 ; i<size_t(count) ; i++) {
             if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
@@ -55,81 +61,121 @@
         // and power/cpu usage.
         mEstimatedGyroRate = 200;
         mTargetDelayNs = 1000000000LL/mEstimatedGyroRate;
-        mFusion.init();
+
+        for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+            mFusions[i].init(i);
+        }
     }
 }
 
 void SensorFusion::process(const sensors_event_t& event) {
+
     if (event.type == mGyro.getType()) {
-        if (mGyroTime != 0) {
-            const float dT = (event.timestamp - mGyroTime) / 1000000000.0f;
-            mFusion.handleGyro(vec3_t(event.data), dT);
+        float dT;
+        if ( event.timestamp - mGyroTime> 0 &&
+             event.timestamp - mGyroTime< (int64_t)(5e7) ) { //0.05sec
+
+            dT = (event.timestamp - mGyroTime) / 1000000000.0f;
             // here we estimate the gyro rate (useful for debugging)
             const float freq = 1 / dT;
             if (freq >= 100 && freq<1000) { // filter values obviously wrong
                 const float alpha = 1 / (1 + dT); // 1s time-constant
                 mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha;
             }
+
+            const vec3_t gyro(event.data);
+            for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+                if (mEnabled[i]) {
+                    // fusion in no gyro mode will ignore
+                    mFusions[i].handleGyro(gyro, dT);
+                }
+            }
         }
         mGyroTime = event.timestamp;
     } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
         const vec3_t mag(event.data);
-        mFusion.handleMag(mag);
+        for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+            if (mEnabled[i]) {
+                mFusions[i].handleMag(mag);// fusion in no mag mode will ignore
+            }
+        }
     } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
-        const vec3_t acc(event.data);
-        mFusion.handleAcc(acc);
-        mAttitude = mFusion.getAttitude();
+        float dT;
+        if ( event.timestamp - mAccTime> 0 &&
+             event.timestamp - mAccTime< (int64_t)(1e8) ) { //0.1sec
+            dT = (event.timestamp - mAccTime) / 1000000000.0f;
+
+            const vec3_t acc(event.data);
+            for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+                if (mEnabled[i]) {
+                    mFusions[i].handleAcc(acc, dT);
+                    mAttitudes[i] = mFusions[i].getAttitude();
+                }
+            }
+        }
+        mAccTime = event.timestamp;
     }
 }
 
 template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
 template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
 
-status_t SensorFusion::activate(void* ident, bool enabled) {
+status_t SensorFusion::activate(int mode, void* ident, bool enabled) {
 
     ALOGD_IF(DEBUG_CONNECTIONS,
-            "SensorFusion::activate(ident=%p, enabled=%d)",
-            ident, enabled);
+            "SensorFusion::activate(mode=%d, ident=%p, enabled=%d)",
+            mode, ident, enabled);
 
-    const ssize_t idx = mClients.indexOf(ident);
+    const ssize_t idx = mClients[mode].indexOf(ident);
     if (enabled) {
         if (idx < 0) {
-            mClients.add(ident);
+            mClients[mode].add(ident);
         }
     } else {
         if (idx >= 0) {
-            mClients.removeItemsAt(idx);
+            mClients[mode].removeItemsAt(idx);
+        }
+    }
+
+    const bool newState = mClients[mode].size() != 0;
+    if (newState != mEnabled[mode]) {
+        mEnabled[mode] = newState;
+        if (newState) {
+            mFusions[mode].init(mode);
         }
     }
 
     mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
-    mSensorDevice.activate(ident, mMag.getHandle(), enabled);
-    mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
+    if (mode != FUSION_NOMAG) {
+        mSensorDevice.activate(ident, mMag.getHandle(), enabled);
+    }
+    if (mode != FUSION_NOGYRO) {
+        mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
+    }
 
-    const bool newState = mClients.size() != 0;
-    if (newState != mEnabled) {
-        mEnabled = newState;
-        if (newState) {
-            mFusion.init();
-            mGyroTime = 0;
-        }
+    return NO_ERROR;
+}
+
+status_t SensorFusion::setDelay(int mode, void* ident, int64_t ns) {
+    // Call batch with timeout zero instead of setDelay().
+    if (ns > (int64_t)5e7) {
+        ns = (int64_t)(5e7);
+    }
+    mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0);
+    if (mode != FUSION_NOMAG) {
+        mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0);
+    }
+    if (mode != FUSION_NOGYRO) {
+        mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0);
     }
     return NO_ERROR;
 }
 
-status_t SensorFusion::setDelay(void* ident, int64_t ns) {
-    // Call batch with timeout zero instead of setDelay().
-    mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0);
-    mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0);
-    mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0);
-    return NO_ERROR;
-}
 
-
-float SensorFusion::getPowerUsage() const {
+float SensorFusion::getPowerUsage(int mode) const {
     float power =   mAcc.getPowerUsage() +
-                    mMag.getPowerUsage() +
-                    mGyro.getPowerUsage();
+                    ((mode != FUSION_NOMAG) ? mMag.getPowerUsage() : 0) +
+                    ((mode != FUSION_NOGYRO) ? mGyro.getPowerUsage() : 0);
     return power;
 }
 
@@ -138,21 +184,55 @@
 }
 
 void SensorFusion::dump(String8& result) {
-    const Fusion& fusion(mFusion);
+    const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]);
     result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
             "q=< %g, %g, %g, %g > (%g), "
             "b=< %g, %g, %g >\n",
-            mEnabled ? "enabled" : "disabled",
-            mClients.size(),
+            mEnabled[FUSION_9AXIS] ? "enabled" : "disabled",
+            mClients[FUSION_9AXIS].size(),
             mEstimatedGyroRate,
-            fusion.getAttitude().x,
-            fusion.getAttitude().y,
-            fusion.getAttitude().z,
-            fusion.getAttitude().w,
-            length(fusion.getAttitude()),
-            fusion.getBias().x,
-            fusion.getBias().y,
-            fusion.getBias().z);
+            fusion_9axis.getAttitude().x,
+            fusion_9axis.getAttitude().y,
+            fusion_9axis.getAttitude().z,
+            fusion_9axis.getAttitude().w,
+            length(fusion_9axis.getAttitude()),
+            fusion_9axis.getBias().x,
+            fusion_9axis.getBias().y,
+            fusion_9axis.getBias().z);
+
+    const Fusion& fusion_nomag(mFusions[FUSION_NOMAG]);
+    result.appendFormat("game fusion(no mag) %s (%zd clients), "
+            "gyro-rate=%7.2fHz, "
+            "q=< %g, %g, %g, %g > (%g), "
+            "b=< %g, %g, %g >\n",
+            mEnabled[FUSION_NOMAG] ? "enabled" : "disabled",
+            mClients[FUSION_NOMAG].size(),
+            mEstimatedGyroRate,
+            fusion_nomag.getAttitude().x,
+            fusion_nomag.getAttitude().y,
+            fusion_nomag.getAttitude().z,
+            fusion_nomag.getAttitude().w,
+            length(fusion_nomag.getAttitude()),
+            fusion_nomag.getBias().x,
+            fusion_nomag.getBias().y,
+            fusion_nomag.getBias().z);
+
+    const Fusion& fusion_nogyro(mFusions[FUSION_NOGYRO]);
+    result.appendFormat("geomag fusion (no gyro) %s (%zd clients), "
+            "gyro-rate=%7.2fHz, "
+            "q=< %g, %g, %g, %g > (%g), "
+            "b=< %g, %g, %g >\n",
+            mEnabled[FUSION_NOGYRO] ? "enabled" : "disabled",
+            mClients[FUSION_NOGYRO].size(),
+            mEstimatedGyroRate,
+            fusion_nogyro.getAttitude().x,
+            fusion_nogyro.getAttitude().y,
+            fusion_nogyro.getAttitude().z,
+            fusion_nogyro.getAttitude().w,
+            length(fusion_nogyro.getAttitude()),
+            fusion_nogyro.getBias().x,
+            fusion_nogyro.getBias().y,
+            fusion_nogyro.getBias().z);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
index 432adbc..ad636d5 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -42,30 +42,52 @@
     Sensor mAcc;
     Sensor mMag;
     Sensor mGyro;
-    Fusion mFusion;
-    bool mEnabled;
+
+    Fusion mFusions[NUM_FUSION_MODE]; // normal, no_mag, no_gyro
+
+    bool mEnabled[NUM_FUSION_MODE];
+
+    vec4_t &mAttitude;
+    vec4_t mAttitudes[NUM_FUSION_MODE];
+
+    SortedVector<void*> mClients[3];
+
     float mEstimatedGyroRate;
     nsecs_t mTargetDelayNs;
+
     nsecs_t mGyroTime;
-    vec4_t mAttitude;
-    SortedVector<void*> mClients;
+    nsecs_t mAccTime;
 
     SensorFusion();
 
 public:
     void process(const sensors_event_t& event);
 
-    bool isEnabled() const { return mEnabled; }
-    bool hasEstimate() const { return mFusion.hasEstimate(); }
-    mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); }
-    vec4_t getAttitude() const { return mAttitude; }
-    vec3_t getGyroBias() const { return mFusion.getBias(); }
+    bool isEnabled() const {
+        return mEnabled[FUSION_9AXIS] ||
+                mEnabled[FUSION_NOMAG] ||
+                mEnabled[FUSION_NOGYRO];
+    }
+
+    bool hasEstimate(int mode = FUSION_9AXIS) const {
+        return mFusions[mode].hasEstimate();
+    }
+
+    mat33_t getRotationMatrix(int mode = FUSION_9AXIS) const {
+        return mFusions[mode].getRotationMatrix();
+    }
+
+    vec4_t getAttitude(int mode = FUSION_9AXIS) const {
+        return mAttitudes[mode];
+    }
+
+    vec3_t getGyroBias() const { return mFusions[FUSION_9AXIS].getBias(); }
     float getEstimatedRate() const { return mEstimatedGyroRate; }
 
-    status_t activate(void* ident, bool enabled);
-    status_t setDelay(void* ident, int64_t ns);
+    status_t activate(int mode, void* ident, bool enabled);
+    status_t setDelay(int mode, void* ident, int64_t ns);
 
-    float getPowerUsage() const;
+    float getPowerUsage(int mode=FUSION_9AXIS) const;
     int32_t getMinDelay() const;
 
     void dump(String8& result);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 1a486a3..8e2109b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -88,11 +88,14 @@
             uint32_t virtualSensorsNeeds =
                     (1<<SENSOR_TYPE_GRAVITY) |
                     (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
-                    (1<<SENSOR_TYPE_ROTATION_VECTOR);
+                    (1<<SENSOR_TYPE_ROTATION_VECTOR) |
+                    (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) |
+                    (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR);
 
             mLastEventSeen.setCapacity(count);
             for (ssize_t i=0 ; i<count ; i++) {
-                registerSensor( new HardwareSensor(list[i]) );
+                bool useThisSensor=true;
+
                 switch (list[i].type) {
                     case SENSOR_TYPE_ACCELEROMETER:
                         hasAccel = true;
@@ -110,9 +113,18 @@
                     case SENSOR_TYPE_GRAVITY:
                     case SENSOR_TYPE_LINEAR_ACCELERATION:
                     case SENSOR_TYPE_ROTATION_VECTOR:
-                        virtualSensorsNeeds &= ~(1<<list[i].type);
+                    case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                    case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+                        if (IGNORE_HARDWARE_FUSION) {
+                            useThisSensor = false;
+                        } else {
+                            virtualSensorsNeeds &= ~(1<<list[i].type);
+                        }
                         break;
                 }
+                if (useThisSensor) {
+                    registerSensor( new HardwareSensor(list[i]) );
+                }
             }
 
             // it's safe to instantiate the SensorFusion object here
@@ -124,26 +136,15 @@
             mUserSensorList = mSensorList;
 
             if (hasGyro && hasAccel && hasMag) {
-                Sensor aSensor;
-
                 // Add Android virtual sensors if they're not already
                 // available in the HAL
+                Sensor aSensor;
 
                 aSensor = registerVirtualSensor( new RotationVectorSensor() );
                 if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) {
                     mUserSensorList.add(aSensor);
                 }
 
-                aSensor = registerVirtualSensor( new GravitySensor(list, count) );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) {
-                    mUserSensorList.add(aSensor);
-                }
-
-                aSensor = registerVirtualSensor( new LinearAccelerationSensor(list, count) );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) {
-                    mUserSensorList.add(aSensor);
-                }
-
                 aSensor = registerVirtualSensor( new OrientationSensor() );
                 if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) {
                     // if we are doing our own rotation-vector, also add
@@ -151,11 +152,46 @@
                     mUserSensorList.replaceAt(aSensor, orientationIndex);
                 }
 
+                aSensor = registerVirtualSensor(
+                                new LinearAccelerationSensor(list, count) );
+                if (virtualSensorsNeeds &
+                            (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) {
+                    mUserSensorList.add(aSensor);
+                }
+
                 // virtual debugging sensors are not added to mUserSensorList
                 registerVirtualSensor( new CorrectedGyroSensor(list, count) );
                 registerVirtualSensor( new GyroDriftSensor() );
             }
 
+            if (hasAccel && hasGyro) {
+                Sensor aSensor;
+
+                aSensor = registerVirtualSensor(
+                                new GravitySensor(list, count) );
+                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) {
+                    mUserSensorList.add(aSensor);
+                }
+
+                aSensor = registerVirtualSensor(
+                                new GameRotationVectorSensor() );
+                if (virtualSensorsNeeds &
+                            (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) {
+                    mUserSensorList.add(aSensor);
+                }
+            }
+
+            if (hasAccel && hasMag) {
+                Sensor aSensor;
+
+                aSensor = registerVirtualSensor(
+                                new GeoMagRotationVectorSensor() );
+                if (virtualSensorsNeeds &
+                        (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)) {
+                    mUserSensorList.add(aSensor);
+                }
+            }
+
             // debugging sensor list
             mUserSensorListDebug = mSensorList;
 
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 9a573ae..7d81d6e 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -46,7 +46,7 @@
 #endif
 
 // ---------------------------------------------------------------------------
-
+#define IGNORE_HARDWARE_FUSION  false
 #define DEBUG_CONNECTIONS   false
 // Max size is 100 KB which is enough to accept a batch of about 1000 events.
 #define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 49389e0..2a025b8 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -134,7 +134,7 @@
                 sp<IBinder>* handle,
                 sp<IGraphicBufferProducer>* gbp)
             : flinger(flinger), client(client),
-              handle(handle), gbp(gbp),
+              handle(handle), gbp(gbp), result(NO_ERROR),
               name(name), w(w), h(h), format(format), flags(flags) {
         }
         status_t getResult() const { return result; }
diff --git a/services/surfaceflinger/DisplayHardware/FloatRect.h b/services/surfaceflinger/DisplayHardware/FloatRect.h
index b08a951..3b75cc0 100644
--- a/services/surfaceflinger/DisplayHardware/FloatRect.h
+++ b/services/surfaceflinger/DisplayHardware/FloatRect.h
@@ -29,7 +29,8 @@
     float right;
     float bottom;
 
-    inline FloatRect() { }
+    inline FloatRect()
+        : left(0), top(0), right(0), bottom(0) { }
     inline FloatRect(const Rect& other)
         : left(other.left), top(other.top), right(other.right), bottom(other.bottom) { }
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 6ef3295..a6bc158 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -66,7 +66,7 @@
                                        GRALLOC_USAGE_HW_COMPOSER);
     mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
     mConsumer->setDefaultBufferSize(mHwc.getWidth(disp),  mHwc.getHeight(disp));
-    mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
+    mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
 }
 
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
@@ -106,7 +106,7 @@
     // releaseBuffer call and we should be in the same state we'd be in if we
     // had released the old buffer first.
     if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
-        item.mBuf != mCurrentBufferSlot) {
+        item.mSlot != mCurrentBufferSlot) {
         // Release the previous buffer.
         err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer,
                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
@@ -115,7 +115,7 @@
             return err;
         }
     }
-    mCurrentBufferSlot = item.mBuf;
+    mCurrentBufferSlot = item.mSlot;
     mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
     outFence = item.mFence;
     outBuffer = mCurrentBuffer;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index ba4c198..48971bc 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -92,7 +92,7 @@
     mConsumer->setConsumerName(ConsumerBase::mName);
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
-    mConsumer->setDefaultMaxBufferCount(2);
+    sink->setAsyncMode(true);
 }
 
 VirtualDisplaySurface::~VirtualDisplaySurface() {
@@ -239,7 +239,6 @@
                         HAL_DATASPACE_UNKNOWN,
                         Rect(mSinkBufferWidth, mSinkBufferHeight),
                         NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
-                        true /* async*/,
                         outFence),
                     &qbo);
             if (result == NO_ERROR) {
@@ -282,17 +281,20 @@
     return NO_ERROR;
 }
 
-status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
-    return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
+status_t VirtualDisplaySurface::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
+    return mSource[SOURCE_SINK]->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+status_t VirtualDisplaySurface::setAsyncMode(bool async) {
+    return mSource[SOURCE_SINK]->setAsyncMode(async);
 }
 
 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
         PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) {
     LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
-    // Don't let a slow consumer block us
-    bool async = (source == SOURCE_SINK);
 
-    status_t result = mSource[source]->dequeueBuffer(sslot, fence, async,
+    status_t result = mSource[source]->dequeueBuffer(sslot, fence,
             mSinkBufferWidth, mSinkBufferHeight, format, usage);
     if (result < 0)
         return result;
@@ -331,16 +333,15 @@
     return result;
 }
 
-status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
+status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) {
     if (mDisplayId < 0)
-        return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage);
+        return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage);
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
             "Unexpected dequeueBuffer() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_GLES;
 
-    VDS_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)");
     VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
 
     status_t result = NO_ERROR;
@@ -442,11 +443,11 @@
         result = acquireBufferLocked(&item, 0);
         if (result != NO_ERROR)
             return result;
-        VDS_LOGW_IF(item.mBuf != sslot,
+        VDS_LOGW_IF(item.mSlot != sslot,
                 "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d",
-                item.mBuf, sslot);
-        mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf);
-        mFbFence = mSlots[item.mBuf].mFence;
+                item.mSlot, sslot);
+        mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mSlot);
+        mFbFence = mSlots[item.mSlot].mFence;
 
     } else {
         LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES,
@@ -460,9 +461,8 @@
         Rect crop;
         int scalingMode;
         uint32_t transform;
-        bool async;
         input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop,
-                &scalingMode, &transform, &async, &mFbFence);
+                &scalingMode, &transform, &mFbFence);
 
         mFbProducerSlot = pslot;
         mOutputFence = mFbFence;
@@ -472,7 +472,8 @@
     return NO_ERROR;
 }
 
-void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
+status_t VirtualDisplaySurface::cancelBuffer(int pslot,
+        const sp<Fence>& fence) {
     if (mDisplayId < 0)
         return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
 
@@ -520,9 +521,8 @@
     return INVALID_OPERATION;
 }
 
-void VirtualDisplaySurface::allocateBuffers(bool /* async */,
-        uint32_t /* width */, uint32_t /* height */, PixelFormat /* format */,
-        uint32_t /* usage */) {
+void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */,
+        uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) {
     // TODO: Should we actually allocate buffers for a virtual display?
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 6298751..d53d43c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -98,22 +98,23 @@
     // IGraphicBufferProducer interface, used by the GLES driver.
     //
     virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
-    virtual status_t setBufferCount(int bufferCount);
-    virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
-            uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual status_t setAsyncMode(bool async);
+    virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w,
+            uint32_t h, PixelFormat format, uint32_t usage);
     virtual status_t detachBuffer(int slot);
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
     virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
     virtual status_t queueBuffer(int pslot,
             const QueueBufferInput& input, QueueBufferOutput* output);
-    virtual void cancelBuffer(int pslot, const sp<Fence>& fence);
+    virtual status_t cancelBuffer(int pslot, const sp<Fence>& fence);
     virtual int query(int what, int* value);
     virtual status_t connect(const sp<IProducerListener>& listener,
             int api, bool producerControlledByApp, QueueBufferOutput* output);
     virtual status_t disconnect(int api);
     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
-    virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
+    virtual void allocateBuffers(uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage);
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags
index 791e0e4..6c851dd 100644
--- a/services/surfaceflinger/EventLog/EventLogTags.logtags
+++ b/services/surfaceflinger/EventLog/EventLogTags.logtags
@@ -36,6 +36,7 @@
 # 60100 - 60199 reserved for surfaceflinger
 
 60100 sf_frame_dur (window|3),(dur0|1),(dur1|1),(dur2|1),(dur3|1),(dur4|1),(dur5|1),(dur6|1)
+60110 sf_stop_bootanim (time|2|3)
 
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5ff79a9..33af4a5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -135,9 +135,8 @@
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
-    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
 #else
-    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
+    mProducer->setMaxDequeuedBufferCount(2);
 #endif
 
     const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 1ad86a6..99efd39 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -119,6 +119,7 @@
                 continue;
             case Looper::POLL_ERROR:
                 ALOGE("Looper::POLL_ERROR");
+                continue;
             case Looper::POLL_TIMEOUT:
                 // timeout (should not happen)
                 continue;
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index fb7af97..79ef92f 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -56,13 +56,18 @@
     return mProducer->requestBuffer(slot, buf);
 }
 
-status_t MonitoredProducer::setBufferCount(int bufferCount) {
-    return mProducer->setBufferCount(bufferCount);
+status_t MonitoredProducer::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
+    return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+status_t MonitoredProducer::setAsyncMode(bool async) {
+    return mProducer->setAsyncMode(async);
 }
 
 status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
-        bool async, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) {
-    return mProducer->dequeueBuffer(slot, fence, async, w, h, format, usage);
+        uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) {
+    return mProducer->dequeueBuffer(slot, fence, w, h, format, usage);
 }
 
 status_t MonitoredProducer::detachBuffer(int slot) {
@@ -84,8 +89,8 @@
     return mProducer->queueBuffer(slot, input, output);
 }
 
-void MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
-    mProducer->cancelBuffer(slot, fence);
+status_t MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+    return mProducer->cancelBuffer(slot, fence);
 }
 
 int MonitoredProducer::query(int what, int* value) {
@@ -105,9 +110,9 @@
     return mProducer->setSidebandStream(stream);
 }
 
-void MonitoredProducer::allocateBuffers(bool async, uint32_t width,
-        uint32_t height, PixelFormat format, uint32_t usage) {
-    mProducer->allocateBuffers(async, width, height, format, usage);
+void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height,
+        PixelFormat format, uint32_t usage) {
+    mProducer->allocateBuffers(width, height, format, usage);
 }
 
 status_t MonitoredProducer::allowAllocation(bool allow) {
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index da95766..3df6f0f 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -35,9 +35,10 @@
 
     // From IGraphicBufferProducer
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-    virtual status_t setBufferCount(int bufferCount);
-    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
-            uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual status_t setAsyncMode(bool async);
+    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+            uint32_t h, PixelFormat format, uint32_t usage);
     virtual status_t detachBuffer(int slot);
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
@@ -45,13 +46,13 @@
             const sp<GraphicBuffer>& buffer);
     virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
             QueueBufferOutput* output);
-    virtual void cancelBuffer(int slot, const sp<Fence>& fence);
+    virtual status_t cancelBuffer(int slot, const sp<Fence>& fence);
     virtual int query(int what, int* value);
     virtual status_t connect(const sp<IProducerListener>& token, int api,
             bool producerControlledByApp, QueueBufferOutput* output);
     virtual status_t disconnect(int api);
     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
-    virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
+    virtual void allocateBuffers(uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage);
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 7cd42e4..27357b9 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -148,7 +148,7 @@
     return engine;
 }
 
-RenderEngine::RenderEngine() : mEGLContext(EGL_NO_CONTEXT) {
+RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {
 }
 
 RenderEngine::~RenderEngine() {
@@ -316,7 +316,7 @@
     friend class Adder;
     KeyedVector<Attribute, EGLint> mList;
     struct Attribute {
-        Attribute() {};
+        Attribute() : v(0) {};
         Attribute(EGLint v) : v(v) { }
         EGLint v;
         bool operator < (const Attribute& other) const {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fdc3650..285b829 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -52,6 +52,7 @@
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include <utils/StopWatch.h>
+#include <utils/Timers.h>
 #include <utils/Trace.h>
 
 #include <private/android_filesystem_config.h>
@@ -235,9 +236,8 @@
     sp<BBinder> token = new DisplayToken(this);
 
     Mutex::Autolock _l(mStateLock);
-    DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL);
+    DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
     info.displayName = displayName;
-    info.isSecure = secure;
     mCurrentState.displays.add(token, info);
 
     return token;
@@ -266,9 +266,8 @@
     ALOGW_IF(mBuiltinDisplays[type],
             "Overwriting display token for display type %d", type);
     mBuiltinDisplays[type] = new BBinder();
-    DisplayDeviceState info(type);
     // All non-virtual displays are currently considered secure.
-    info.isSecure = true;
+    DisplayDeviceState info(type, true);
     mCurrentState.displays.add(mBuiltinDisplays[type], info);
 }
 
@@ -304,6 +303,10 @@
     // formerly we would just kill the process, but we now ask it to exit so it
     // can choose where to stop the animation.
     property_set("service.bootanim.exit", "1");
+
+    const int LOGTAG_SF_STOP_BOOTANIM = 60110;
+    LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
+                   ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 }
 
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -3127,8 +3130,12 @@
     GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
     :   impl(impl),
         looper(new Looper(true)),
+        result(NO_ERROR),
         exitPending(false),
-        exitRequested(false)
+        exitRequested(false),
+        code(0),
+        data(NULL),
+        reply(NULL)
     {}
 
     // Binder thread
@@ -3524,11 +3531,22 @@
 // ---------------------------------------------------------------------------
 
 SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
-    : type(DisplayDevice::DISPLAY_ID_INVALID), width(0), height(0) {
+    : type(DisplayDevice::DISPLAY_ID_INVALID),
+      layerStack(DisplayDevice::NO_LAYER_STACK),
+      orientation(0),
+      width(0),
+      height(0),
+      isSecure(false) {
 }
 
-SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
-    : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0) {
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(
+    DisplayDevice::DisplayType type, bool isSecure)
+    : type(type),
+      layerStack(DisplayDevice::NO_LAYER_STACK),
+      orientation(0),
+      width(0),
+      height(0),
+      isSecure(isSecure) {
     viewport.makeInvalid();
     frame.makeInvalid();
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b3baadd..4e0160a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -162,7 +162,7 @@
 
     struct DisplayDeviceState {
         DisplayDeviceState();
-        DisplayDeviceState(DisplayDevice::DisplayType type);
+        DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure);
         bool isValid() const { return type >= 0; }
         bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
         bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index ed1f31b..930e7c7 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -72,9 +72,9 @@
     // We call the rejecter here, in case the caller has a reason to
     // not accept this buffer.  This is used by SurfaceFlinger to
     // reject buffers which have the wrong size
-    int buf = item.mBuf;
-    if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
-        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
+    int slot = item.mSlot;
+    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
         return BUFFER_REJECTED;
     }
 
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index dcde512..ee4ad4e 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -24,10 +24,13 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/LayerState.h>
 
 #include <utils/String8.h>
 #include <ui/DisplayInfo.h>
 
+#include <math.h>
+
 namespace android {
 
 // Fill an RGBA_8888 formatted surface with a single color.
@@ -38,8 +41,8 @@
     ASSERT_TRUE(s != NULL);
     ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, NULL));
     uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
-    for (uint32_t y = 0; y < outBuffer.height; y++) {
-        for (uint32_t x = 0; x < outBuffer.width; x++) {
+    for (int y = 0; y < outBuffer.height; y++) {
+        for (int x = 0; x < outBuffer.width; x++) {
             uint8_t* pixel = img + (4 * (y*outBuffer.stride + x));
             pixel[0] = r;
             pixel[1] = g;
@@ -76,7 +79,7 @@
             String8 err(String8::format("pixel @ (%3d, %3d): "
                     "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
                     x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
-            EXPECT_EQ(String8(), err);
+            EXPECT_EQ(String8(), err) << err.string();
         }
     }
 
@@ -134,6 +137,8 @@
 
         SurfaceComposerClient::openGlobalTransaction();
 
+        mComposerClient->setDisplayLayerStack(display, 0);
+
         ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2));
         ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
 
@@ -249,4 +254,184 @@
     }
 }
 
+TEST_F(LayerUpdateTest, LayerCropWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before crop");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    Rect cropRect(16, 16, 32, 32);
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should crop the foreground surface.
+        SCOPED_TRACE("after crop");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel( 95,  80, 195,  63,  63);
+        sc->checkPixel( 80,  95, 195,  63,  63);
+        sc->checkPixel( 96,  96,  63,  63, 195);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerSetLayerWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setLayer");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should hide the foreground surface beneath the background.
+        SCOPED_TRACE("after setLayer");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerShowHideWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before hide");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should hide the foreground surface.
+        SCOPED_TRACE("after hide, before show");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should show the foreground surface.
+        SCOPED_TRACE("after show");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerSetAlphaWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setAlpha");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should set foreground to be 75% opaque.
+        SCOPED_TRACE("after setAlpha");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 162,  63,  96);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerSetLayerStackWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setLayerStack");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should hide the foreground surface since it goes to a different
+        // layer stack.
+        SCOPED_TRACE("after setLayerStack");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerSetFlagsWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setFlags");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags(
+            layer_state_t::eLayerHidden, layer_state_t::eLayerHidden));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should hide the foreground surface
+        SCOPED_TRACE("after setFlags");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerSetMatrixWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setMatrix");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 91,  96, 195,  63,  63);
+        sc->checkPixel( 96, 101, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2,
+            -M_SQRT1_2, M_SQRT1_2));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        SCOPED_TRACE("after setMatrix");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 91,  96, 195,  63,  63);
+        sc->checkPixel( 96,  91,  63,  63, 195);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+}
+
 }
diff --git a/services/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk
deleted file mode 100644
index d81679e..0000000
--- a/services/surfaceflinger/tests/resize/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	resize.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-    libui \
-    libgui
-
-LOCAL_MODULE:= test-resize
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
deleted file mode 100644
index 8b051e8..0000000
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2010 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 <cutils/memory.h>
-
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-using namespace android;
-
-namespace android {
-
-int main(int argc, char** argv)
-{
-    // set up the thread-pool
-    sp<ProcessState> proc(ProcessState::self());
-    ProcessState::self()->startThreadPool();
-
-    // create a client to surfaceflinger
-    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
-    
-    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
-            160, 240, PIXEL_FORMAT_RGB_565, 0);
-
-    sp<Surface> surface = surfaceControl->getSurface();
-
-    SurfaceComposerClient::openGlobalTransaction();
-    surfaceControl->setLayer(100000);
-    SurfaceComposerClient::closeGlobalTransaction();
-
-    ANativeWindow_Buffer outBuffer;
-    surface->lock(&outBuffer, NULL);
-    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
-    android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
-    surface->unlockAndPost();
-
-    surface->lock(&outBuffer);
-    android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
-    surface->unlockAndPost();
-
-    SurfaceComposerClient::openGlobalTransaction();
-    surfaceControl->setSize(320, 240);
-    SurfaceComposerClient::closeGlobalTransaction();
-
-    
-    IPCThreadState::self()->joinThreadPool();
-    
-    return 0;
-}
diff --git a/services/surfaceflinger/tests/screencap/Android.mk b/services/surfaceflinger/tests/screencap/Android.mk
deleted file mode 100644
index 5cdd1a8..0000000
--- a/services/surfaceflinger/tests/screencap/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	screencap.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	libbinder \
-	libskia \
-    libui \
-    libgui
-
-LOCAL_MODULE:= test-screencap
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_C_INCLUDES += \
-	external/skia/include/core \
-	external/skia/include/effects \
-	external/skia/include/images \
-	external/skia/src/ports \
-	external/skia/include/utils
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp
deleted file mode 100644
index f842fc3..0000000
--- a/services/surfaceflinger/tests/screencap/screencap.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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 <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-
-#include <binder/IMemory.h>
-#include <gui/ISurfaceComposer.h>
-
-#include <SkImageEncoder.h>
-#include <SkBitmap.h>
-
-using namespace android;
-
-int main(int argc, char** argv)
-{
-    if (argc != 2) {
-        printf("usage: %s path\n", argv[0]);
-        exit(0);
-    }
-
-    const String16 name("SurfaceFlinger");
-    sp<ISurfaceComposer> composer;
-    getService(name, &composer);
-
-    sp<IMemoryHeap> heap;
-    uint32_t w, h;
-    PixelFormat f;
-    sp<IBinder> display(composer->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    status_t err = composer->captureScreen(display, &heap, &w, &h, &f, 0, 0);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
-        exit(0);
-    }
-
-    printf("screen capture success: w=%u, h=%u, pixels=%p\n",
-            w, h, heap->getBase());
-
-    printf("saving file as PNG in %s ...\n", argv[1]);
-
-    SkBitmap b;
-    b.setConfig(SkBitmap::kARGB_8888_Config, w, h);
-    b.setPixels(heap->getBase());
-    SkImageEncoder::EncodeFile(argv[1], b,
-            SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
-
-    return 0;
-}
diff --git a/services/surfaceflinger/tests/transform/Android.mk b/services/surfaceflinger/tests/transform/Android.mk
deleted file mode 100644
index 6219dae..0000000
--- a/services/surfaceflinger/tests/transform/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	TransformTest.cpp \
-	../../Transform.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	libui \
-
-LOCAL_MODULE:= test-transform
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_C_INCLUDES += ../..
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/transform/TransformTest.cpp b/services/surfaceflinger/tests/transform/TransformTest.cpp
deleted file mode 100644
index e112c4e..0000000
--- a/services/surfaceflinger/tests/transform/TransformTest.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2007 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 <utils/Errors.h>
-#include "../../Transform.h"
-
-using namespace android;
-
-int main(int argc, char **argv)
-{
-    Transform tr90(Transform::ROT_90);
-    Transform trFH(Transform::FLIP_H);
-    Transform trFV(Transform::FLIP_V);
-
-    Transform tr90FH(Transform::ROT_90 | Transform::FLIP_H);
-    Transform tr90FV(Transform::ROT_90 | Transform::FLIP_V);
-
-    tr90.dump("tr90");
-    trFH.dump("trFH");
-    trFV.dump("trFV");
-
-    tr90FH.dump("tr90FH");
-    tr90FV.dump("tr90FV");
-
-    (trFH*tr90).dump("trFH*tr90");
-    (trFV*tr90).dump("trFV*tr90");
-
-    (tr90*trFH).dump("tr90*trFH");
-    (tr90*trFV).dump("tr90*trFV");
-
-    return 0;
-}