Merge "Modify EGL to disconnect the window when the surface gets destroyed." into lmp-dev
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 36d11fb..d2f99df 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -20,13 +20,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <sys/capability.h>
-#include <linux/prctl.h>
 
 #include <cutils/properties.h>
 
@@ -45,6 +45,36 @@
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 
+#define TOMBSTONE_DIR "/data/tombstones"
+#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
+/* Can accomodate a tombstone number up to 9999. */
+#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
+#define NUM_TOMBSTONES  10
+
+typedef struct {
+  char name[TOMBSTONE_MAX_LEN];
+  int fd;
+} tombstone_data_t;
+
+static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+
+/* Get the fds of any tombstone that was modified in the last half an hour. */
+static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
+    time_t thirty_minutes_ago = time(NULL) - 60*30;
+    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+        snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
+        int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+        struct stat st;
+        if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
+                (time_t) st.st_mtime >= thirty_minutes_ago) {
+            data[i].fd = fd;
+        } else {
+            close(fd);
+            data[i].fd = -1;
+        }
+    }
+}
+
 /* dumps the current system state to stdout */
 static void dumpstate() {
     time_t now = time(NULL);
@@ -119,7 +149,6 @@
     run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
     run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
 
-
     /* show the traces we collected in main(), if that was done */
     if (dump_traces_path != NULL) {
         dump_file("VM TRACES JUST NOW", dump_traces_path);
@@ -131,10 +160,13 @@
     property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
     if (!anr_traces_path[0]) {
         printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
-    } else if (stat(anr_traces_path, &st)) {
-        printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
     } else {
-        dump_file("VM TRACES AT LAST ANR", anr_traces_path);
+      int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+      if (fd < 0) {
+          printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
+      } else {
+          dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
+      }
     }
 
     /* slow traces for slow operations */
@@ -155,6 +187,18 @@
         }
     }
 
+    int dumped = 0;
+    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+        if (tombstone_data[i].fd != -1) {
+            dumped = 1;
+            dump_file_from_fd("TOMBSTONE", tombstone_data[i].name, tombstone_data[i].fd);
+            tombstone_data[i].fd = -1;
+        }
+    }
+    if (!dumped) {
+        printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+    }
+
     dump_file("NETWORK DEV INFO", "/proc/net/dev");
     dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
     dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
@@ -411,6 +455,9 @@
         return -1;
     }
 
+    /* Get the tombstone fds here while we are running as root. */
+    get_tombstone_fds(tombstone_data);
+
     /* switch to non-root user and group */
     gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
             AID_MOUNT, AID_INET, AID_NET_BW_STATS };
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 111bda6..53bfff6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -29,7 +29,10 @@
 typedef void (for_each_userid_func)(int);
 
 /* prints the contents of a file */
-int dump_file(const char *title, const char* path);
+int dump_file(const char *title, const char *path);
+
+/* prints the contents of the fd */
+int dump_file_from_fd(const char *title, const char *path, int fd);
 
 /* forks a command and waits for it to finish -- terminate args with NULL */
 int run_command(const char *title, int timeout_seconds, const char *command, ...);
@@ -71,7 +74,7 @@
 void dump_route_tables();
 
 /* Play a sound via Stagefright */
-void play_sound(const char* path);
+void play_sound(const char *path);
 
 /* Implemented by libdumpstate_board to dump board-specific info */
 void dumpstate_board();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 7694adb..a6d9ef6 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -249,8 +249,7 @@
 }
 
 /* prints the contents of a file */
-int dump_file(const char *title, const char* path) {
-    char buffer[32768];
+int dump_file(const char *title, const char *path) {
     int fd = open(path, O_RDONLY);
     if (fd < 0) {
         int err = errno;
@@ -259,6 +258,11 @@
         if (title) printf("\n");
         return -1;
     }
+    return dump_file_from_fd(title, path, fd);
+}
+
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+    char buffer[32768];
 
     if (title) printf("------ %s (%s", title, path);
 
@@ -282,8 +286,8 @@
         }
         if (ret <= 0) break;
     }
-
     close(fd);
+
     if (!newline) printf("\n");
     if (title) printf("\n");
     return 0;
diff --git a/data/etc/android.hardware.opengles.aep.xml b/data/etc/android.hardware.opengles.aep.xml
new file mode 100644
index 0000000..055fa7a
--- /dev/null
+++ b/data/etc/android.hardware.opengles.aep.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports the
+     Android Extension Pack features. -->
+<permissions>
+    <feature name="android.hardware.opengles.aep" />
+</permissions>
+
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
index f4a8aa3..7ddac57 100644
--- a/include/binder/IBatteryStats.h
+++ b/include/binder/IBatteryStats.h
@@ -30,10 +30,22 @@
 
     virtual void noteStartSensor(int uid, int sensor) = 0;
     virtual void noteStopSensor(int uid, int sensor) = 0;
+    virtual void noteStartVideo(int uid) = 0;
+    virtual void noteStopVideo(int uid) = 0;
+    virtual void noteStartAudio(int uid) = 0;
+    virtual void noteStopAudio(int uid) = 0;
+    virtual void noteResetVideo() = 0;
+    virtual void noteResetAudio() = 0;
 
     enum {
         NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         NOTE_STOP_SENSOR_TRANSACTION,
+        NOTE_START_VIDEO_TRANSACTION,
+        NOTE_STOP_VIDEO_TRANSACTION,
+        NOTE_START_AUDIO_TRANSACTION,
+        NOTE_STOP_AUDIO_TRANSACTION,
+        NOTE_RESET_VIDEO_TRANSACTION,
+        NOTE_RESET_AUDIO_TRANSACTION,
     };
 };
 
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
index d32df84..3ecac52 100644
--- a/include/gui/BitTube.h
+++ b/include/gui/BitTube.h
@@ -48,6 +48,9 @@
     // get receive file-descriptor
     int getFd() const;
 
+    // get the send file-descriptor.
+    int getSendFd() const;
+
     // send objects (sized blobs). All objects are guaranteed to be written or the call fails.
     template <typename T>
     static ssize_t sendObjects(const sp<BitTube>& tube,
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index cfcb7a5..1050e3b 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -120,6 +120,9 @@
     // in one of the slots.
     bool stillTracking(const BufferItem* item) const;
 
+    // waitWhileAllocatingLocked blocks until mIsAllocating is false.
+    void waitWhileAllocatingLocked() const;
+
     // mAllocator is the connection to SurfaceFlinger that is used to allocate
     // new GraphicBuffer objects.
     sp<IGraphicBufferAlloc> mAllocator;
@@ -234,6 +237,15 @@
     // mSidebandStream is a handle to the sideband buffer stream, if any
     sp<NativeHandle> mSidebandStream;
 
+    // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which
+    // releases mMutex while doing the allocation proper). Producers should not modify any of the
+    // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to
+    // false.
+    bool mIsAllocating;
+
+    // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
+    // becomes false.
+    mutable Condition mIsAllocatingCondition;
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 1aacee9..37530db 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -231,7 +231,7 @@
 protected:
 
     // abandonLocked overrides the ConsumerBase method to clear
-    // mCurrentTextureBuf in addition to the ConsumerBase behavior.
+    // mCurrentTextureImage in addition to the ConsumerBase behavior.
     virtual void abandonLocked();
 
     // dumpLocked overrides the ConsumerBase method to dump GLConsumer-
@@ -262,7 +262,7 @@
     status_t updateAndReleaseLocked(const BufferQueue::BufferItem& item);
 
     // Binds mTexName and the current buffer to mTexTarget.  Uses
-    // mCurrentTexture if it's set, mCurrentTextureBuf if not.  If the
+    // mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
     // bind succeeds, this calls doGLFenceWait.
     status_t bindTextureImageLocked();
 
@@ -275,11 +275,57 @@
     status_t checkAndUpdateEglStateLocked(bool contextCheck = false);
 
 private:
-    // createImage creates a new EGLImage from a GraphicBuffer.
-    EGLImageKHR createImage(EGLDisplay dpy,
-            const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+    // EglImage is a utility class for tracking and creating EGLImageKHRs. There
+    // is primarily just one image per slot, but there is also special cases:
+    //  - For releaseTexImage, we use a debug image (mReleasedTexImage)
+    //  - After freeBuffer, we must still keep the current image/buffer
+    // Reference counting EGLImages lets us handle all these cases easily while
+    // also only creating new EGLImages from buffers when required.
+    class EglImage : public LightRefBase<EglImage>  {
+    public:
+        EglImage(sp<GraphicBuffer> graphicBuffer);
 
-    // freeBufferLocked frees up the given buffer slot.  If the slot has been
+        // createIfNeeded creates an EGLImage if required (we haven't created
+        // one yet, or the EGLDisplay or crop-rect has changed).
+        status_t createIfNeeded(EGLDisplay display, const Rect& cropRect);
+
+        // This calls glEGLImageTargetTexture2DOES to bind the image to the
+        // texture in the specified texture target.
+        void bindToTextureTarget(uint32_t texTarget);
+
+        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+        const native_handle* graphicBufferHandle() {
+            return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+        }
+
+    private:
+        // Only allow instantiation using ref counting.
+        friend class LightRefBase<EglImage>;
+        virtual ~EglImage();
+
+        // createImage creates a new EGLImage from a GraphicBuffer.
+        EGLImageKHR createImage(EGLDisplay dpy,
+                const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+
+        // Disallow copying
+        EglImage(const EglImage& rhs);
+        void operator = (const EglImage& rhs);
+
+        // mGraphicBuffer is the buffer that was used to create this image.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mEglImage is the EGLImage created from mGraphicBuffer.
+        EGLImageKHR mEglImage;
+
+        // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
+        EGLDisplay mEglDisplay;
+
+        // mCropRect is the crop rectangle passed to EGL when mEglImage
+        // was created.
+        Rect mCropRect;
+    };
+
+    // freeBufferLocked frees up the given buffer slot. If the slot has been
     // initialized this will release the reference to the GraphicBuffer in that
     // slot and destroy the EGLImage in that slot.  Otherwise it has no effect.
     //
@@ -289,7 +335,7 @@
     // computeCurrentTransformMatrixLocked computes the transform matrix for the
     // current texture.  It uses mCurrentTransform and the current GraphicBuffer
     // to compute this matrix and stores it in mCurrentTransformMatrix.
-    // mCurrentTextureBuf must not be NULL.
+    // mCurrentTextureImage must not be NULL.
     void computeCurrentTransformMatrixLocked();
 
     // doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
@@ -303,13 +349,6 @@
     // before the outstanding accesses have completed.
     status_t syncForReleaseLocked(EGLDisplay dpy);
 
-    // Normally, when we bind a buffer to a texture target, we bind a buffer
-    // that is referenced by an entry in mEglSlots.  In some situations we
-    // have a buffer in mCurrentTextureBuf, but no corresponding entry for
-    // it in our slot array.  bindUnslottedBuffer handles that situation by
-    // binding the buffer without touching the EglSlots.
-    status_t bindUnslottedBufferLocked(EGLDisplay dpy);
-
     // returns a graphic buffer used when the texture image has been released
     static sp<GraphicBuffer> getDebugTexImageBuffer();
 
@@ -319,10 +358,10 @@
     // consume buffers as hardware textures.
     static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
 
-    // mCurrentTextureBuf is the graphic buffer of the current texture. It's
+    // mCurrentTextureImage is the EglImage/buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
     // must track it separately in order to support the getCurrentBuffer method.
-    sp<GraphicBuffer> mCurrentTextureBuf;
+    sp<EglImage> mCurrentTextureImage;
 
     // mCurrentCrop is the crop rectangle that applies to the current texture.
     // It gets set each time updateTexImage is called.
@@ -382,17 +421,10 @@
     // EGLSlot contains the information and object references that
     // GLConsumer maintains about a BufferQueue buffer slot.
     struct EglSlot {
-        EglSlot()
-        : mEglImage(EGL_NO_IMAGE_KHR),
-          mEglFence(EGL_NO_SYNC_KHR) {
-        }
+        EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
 
         // mEglImage is the EGLImage created from mGraphicBuffer.
-        EGLImageKHR mEglImage;
-
-        // mCropRect is the crop rectangle passed to EGL when mEglImage was
-        // created.
-        Rect mCropRect;
+        sp<EglImage> mEglImage;
 
         // mFence is the EGL sync object that must signal before the buffer
         // associated with this buffer slot may be dequeued. It is initialized
@@ -444,6 +476,7 @@
     // mReleasedTexImageBuffer is a dummy buffer used when in single buffer
     // mode and releaseTexImage() has been called
     static sp<GraphicBuffer> sReleasedTexImageBuffer;
+    sp<EglImage> mReleasedTexImage;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
index b296797..f64c6b8 100644
--- a/include/gui/ISensorEventConnection.h
+++ b/include/gui/ISensorEventConnection.h
@@ -40,7 +40,6 @@
                                    nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0;
     virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
     virtual status_t flush() = 0;
-    virtual void decreaseWakeLockRefCount() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index 58c1f6a..bb79bd0 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -47,6 +47,7 @@
         eOpaque             = 0x00000400,
         eProtectedByApp     = 0x00000800,
         eProtectedByDRM     = 0x00001000,
+        eCursorWindow       = 0x00002000,
 
         eFXSurfaceNormal    = 0x00000000,
         eFXSurfaceDim       = 0x00020000,
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index de3aeb1..88e7ad3 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -157,6 +157,63 @@
     OMX_BOOL bEnable;
 };
 
+// Structure describing a media image (frame)
+// Currently only supporting YUV
+struct MediaImage {
+    enum Type {
+        MEDIA_IMAGE_TYPE_UNKNOWN = 0,
+        MEDIA_IMAGE_TYPE_YUV,
+    };
+
+    enum PlaneIndex {
+        Y = 0,
+        U,
+        V,
+        MAX_NUM_PLANES
+    };
+
+    Type mType;
+    size_t mNumPlanes;              // number of planes
+    size_t mWidth;                  // width of largest plane
+    size_t mHeight;                 // height of largest plane
+    size_t mBitDepth;               // useable bit depth
+    struct PlaneInfo {
+        size_t mOffset;             // offset of first pixel of the plane in bytes
+                                    // from buffer offset
+        size_t mColInc;             // column increment in bytes
+        size_t mRowInc;             // row increment in bytes
+        size_t mHorizSubsampling;   // subsampling compared to the largest plane
+        size_t mVertSubsampling;    // subsampling compared to the largest plane
+    };
+    PlaneInfo mPlane[MAX_NUM_PLANES];
+};
+
+// A pointer to this struct is passed to OMX_GetParameter when the extension
+// index for the 'OMX.google.android.index.describeColorFormat'
+// extension is given.  This method can be called from any component state
+// other than invalid.  The color-format, frame width/height, and stride/
+// slice-height parameters are ones that are associated with a raw video
+// port (input or output), but the stride/slice height parameters may be
+// incorrect.  The component shall fill out the MediaImage structure that
+// corresponds to the described raw video format, and the potentially corrected
+// stride and slice-height info.
+//
+// For non-YUV packed planar/semiplanar image formats, the component shall set
+// mNumPlanes to 0, and mType to MEDIA_IMAGE_TYPE_UNKNOWN.
+struct DescribeColorFormatParams {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    // input: parameters from OMX_VIDEO_PORTDEFINITIONTYPE
+    OMX_COLOR_FORMATTYPE eColorFormat;
+    OMX_U32 nFrameWidth;
+    OMX_U32 nFrameHeight;
+    OMX_U32 nStride;
+    OMX_U32 nSliceHeight;
+
+    // output: fill out the MediaImage fields
+    MediaImage sMediaImage;
+};
+
 }  // namespace android
 
 extern android::OMXPluginBase *createOMXPlugin();
diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h
index 96a4396..5f9e9b6 100644
--- a/include/media/openmax/OMX_IVCommon.h
+++ b/include/media/openmax/OMX_IVCommon.h
@@ -157,6 +157,13 @@
      * an acceptable range once that is done.
      * */
     OMX_COLOR_FormatAndroidOpaque = 0x7F000789,
+    /** Flexible 8-bit YUV format.  Codec should report this format
+     *  as being supported if it supports any YUV420 packed planar
+     *  or semiplanar formats.  When port is set to use this format,
+     *  codec can substitute any YUV420 packed planar or semiplanar
+     *  format for it. */
+    OMX_COLOR_FormatYUV420Flexible = 0x7F420888,
+
     OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100,
     OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00,
     OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03,
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index ddc4635..7630faa 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -64,7 +64,9 @@
         USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
         USAGE_HW_COMPOSER       = GRALLOC_USAGE_HW_COMPOSER,
         USAGE_HW_VIDEO_ENCODER  = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        USAGE_HW_MASK           = GRALLOC_USAGE_HW_MASK
+        USAGE_HW_MASK           = GRALLOC_USAGE_HW_MASK,
+
+        USAGE_CURSOR            = GRALLOC_USAGE_CURSOR,
     };
 
     GraphicBuffer();
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index 5702151..8f3b7b4 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -49,6 +49,46 @@
         data.writeInt32(sensor);
         remote()->transact(NOTE_STOP_SENSOR_TRANSACTION, data, &reply);
     }
+
+    virtual void noteStartVideo(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_START_VIDEO_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteStopVideo(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_STOP_VIDEO_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteStartAudio(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_START_AUDIO_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteStopAudio(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_STOP_AUDIO_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteResetVideo() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        remote()->transact(NOTE_RESET_VIDEO_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteResetAudio() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats");
@@ -75,6 +115,46 @@
             reply->writeNoException();
             return NO_ERROR;
         } break;
+        case NOTE_START_VIDEO_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteStartVideo(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_STOP_VIDEO_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteStopVideo(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_START_AUDIO_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteStartAudio(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_STOP_AUDIO_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteStopAudio(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_RESET_VIDEO_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            noteResetVideo();
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_RESET_AUDIO_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            noteResetAudio();
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 0282834..3ed1f37 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -99,6 +99,11 @@
     return mReceiveFd;
 }
 
+int BitTube::getSendFd() const
+{
+    return mSendFd;
+}
+
 ssize_t BitTube::write(void const* vaddr, size_t size)
 {
     ssize_t err, len;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 40e6884..ec1e631 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -64,7 +64,9 @@
     mMaxAcquiredBufferCount(1),
     mBufferHasBeenQueued(false),
     mFrameCounter(0),
-    mTransformHint(0)
+    mTransformHint(0),
+    mIsAllocating(false),
+    mIsAllocatingCondition()
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -226,4 +228,11 @@
            (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
 }
 
+void BufferQueueCore::waitWhileAllocatingLocked() const {
+    ATRACE_CALL();
+    while (mIsAllocating) {
+        mIsAllocatingCondition.wait(mMutex);
+    }
+}
+
 } // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 849a12b..cbca3ac 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -74,6 +74,7 @@
     sp<IConsumerListener> listener;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("setBufferCount: BufferQueue has been abandoned");
@@ -266,6 +267,7 @@
 
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
 
         if (format == 0) {
             format = mCore->mDefaultBufferFormat;
@@ -424,6 +426,7 @@
     }
 
     Mutex::Autolock lock(mCore->mMutex);
+    mCore->waitWhileAllocatingLocked();
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
@@ -468,6 +471,7 @@
     }
 
     Mutex::Autolock lock(mCore->mMutex);
+    mCore->waitWhileAllocatingLocked();
 
     status_t returnFlags = NO_ERROR;
     int found;
@@ -796,6 +800,7 @@
     sp<IConsumerListener> listener;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
 
         if (mCore->mIsAbandoned) {
             // It's not really an error to disconnect after the surface has
@@ -862,55 +867,101 @@
 
 void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
         uint32_t height, uint32_t format, uint32_t usage) {
-    Vector<int> freeSlots;
+    ATRACE_CALL();
+    while (true) {
+        Vector<int> freeSlots;
+        size_t newBufferCount = 0;
+        uint32_t allocWidth = 0;
+        uint32_t allocHeight = 0;
+        uint32_t allocFormat = 0;
+        uint32_t allocUsage = 0;
+        { // Autolock scope
+            Mutex::Autolock lock(mCore->mMutex);
+            mCore->waitWhileAllocatingLocked();
 
-    Mutex::Autolock lock(mCore->mMutex);
+            int currentBufferCount = 0;
+            for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
+                if (mSlots[slot].mGraphicBuffer != NULL) {
+                    ++currentBufferCount;
+                } else {
+                    if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+                        BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
+                                slot);
+                        continue;
+                    }
 
-    int currentBufferCount = 0;
-    for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
-        if (mSlots[slot].mGraphicBuffer != NULL) {
-            ++currentBufferCount;
-        } else {
-            if (mSlots[slot].mBufferState != BufferSlot::FREE) {
-                BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
-                        slot);
+                    freeSlots.push_back(slot);
+                }
+            }
+
+            int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+            BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
+                    currentBufferCount, maxBufferCount);
+            if (maxBufferCount <= currentBufferCount)
+                return;
+            newBufferCount = maxBufferCount - currentBufferCount;
+            if (freeSlots.size() < newBufferCount) {
+                BQ_LOGE("allocateBuffers: ran out of free slots");
+                return;
+            }
+            allocWidth = width > 0 ? width : mCore->mDefaultWidth;
+            allocHeight = height > 0 ? height : mCore->mDefaultHeight;
+            allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+            allocUsage = usage | mCore->mConsumerUsageBits;
+
+            mCore->mIsAllocating = true;
+        } // Autolock scope
+
+        Vector<sp<GraphicBuffer> > buffers;
+        for (size_t i = 0; i <  newBufferCount; ++i) {
+            status_t result = NO_ERROR;
+            sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+                    allocWidth, allocHeight, allocFormat, allocUsage, &result));
+            if (result != NO_ERROR) {
+                BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
+                        " %u, usage %u)", width, height, format, usage);
+                Mutex::Autolock lock(mCore->mMutex);
+                mCore->mIsAllocating = false;
+                mCore->mIsAllocatingCondition.broadcast();
+                return;
+            }
+            buffers.push_back(graphicBuffer);
+        }
+
+        { // Autolock scope
+            Mutex::Autolock lock(mCore->mMutex);
+            uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
+            uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
+            uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+            uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+            if (checkWidth != allocWidth || checkHeight != allocHeight ||
+                checkFormat != allocFormat || checkUsage != allocUsage) {
+                // Something changed while we released the lock. Retry.
+                BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
+                mCore->mIsAllocating = false;
+                mCore->mIsAllocatingCondition.broadcast();
                 continue;
             }
 
-            freeSlots.push_front(slot);
-        }
-    }
+            for (size_t i = 0; i < newBufferCount; ++i) {
+                int slot = freeSlots[i];
+                if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+                    // A consumer allocated the FREE slot with attachBuffer. Discard the buffer we
+                    // allocated.
+                    BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. "
+                            "Dropping allocated buffer.", slot);
+                    continue;
+                }
+                mCore->freeBufferLocked(slot); // Clean up the slot first
+                mSlots[slot].mGraphicBuffer = buffers[i];
+                mSlots[slot].mFrameNumber = 0;
+                mSlots[slot].mFence = Fence::NO_FENCE;
+                BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
+            }
 
-    int maxBufferCount = mCore->getMaxBufferCountLocked(async);
-    BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
-            currentBufferCount, maxBufferCount);
-    for (; currentBufferCount < maxBufferCount; ++currentBufferCount) {
-        if (freeSlots.empty()) {
-            BQ_LOGE("allocateBuffers: ran out of free slots");
-            return;
-        }
-
-        width = width > 0 ? width : mCore->mDefaultWidth;
-        height = height > 0 ? height : mCore->mDefaultHeight;
-        format = format != 0 ? format : mCore->mDefaultBufferFormat;
-        usage |= mCore->mConsumerUsageBits;
-
-        status_t result = NO_ERROR;
-        sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
-                width, height, format, usage, &result));
-        if (result != NO_ERROR) {
-            BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
-                    " %u, usage %u)", width, height, format, usage);
-            return;
-        }
-
-        int slot = freeSlots[freeSlots.size() - 1];
-        mCore->freeBufferLocked(slot); // Clean up the slot first
-        mSlots[slot].mGraphicBuffer = graphicBuffer;
-        mSlots[slot].mFrameNumber = 0;
-        mSlots[slot].mFence = Fence::NO_FENCE;
-        BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
-        freeSlots.pop();
+            mCore->mIsAllocating = false;
+            mCore->mIsAllocatingCondition.broadcast();
+        } // Autolock scope
     }
 }
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 924fc0d..939c4a9 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -279,8 +279,12 @@
             return err;
         }
 
+        if (mReleasedTexImage == NULL) {
+            mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
+        }
+
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
-        mCurrentTextureBuf = getDebugTexImageBuffer();
+        mCurrentTextureImage = mReleasedTexImage;
         mCurrentCrop.makeInvalid();
         mCurrentTransform = 0;
         mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
@@ -288,9 +292,11 @@
         mCurrentFence = Fence::NO_FENCE;
 
         if (mAttached) {
-            // bind a dummy texture
-            glBindTexture(mTexTarget, mTexName);
-            bindUnslottedBufferLocked(mEglDisplay);
+            // This binds a dummy buffer (mReleasedTexImage).
+            status_t err =  bindTextureImageLocked();
+            if (err != NO_ERROR) {
+                return err;
+            }
         } else {
             // detached, don't touch the texture (and we may not even have an
             // EGLDisplay here.
@@ -332,29 +338,12 @@
         return err;
     }
 
-    int slot = item->mBuf;
-    bool destroyEglImage = false;
-
-    if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
-        if (item->mGraphicBuffer != NULL) {
-            // This buffer has not been acquired before, so we must assume
-            // that any EGLImage in mEglSlots is stale.
-            destroyEglImage = true;
-        } else if (mEglSlots[slot].mCropRect != item->mCrop) {
-            // We've already seen this buffer before, but it now has a
-            // different crop rect, so we'll need to recreate the EGLImage if
-            // we're using the EGL_ANDROID_image_crop extension.
-            destroyEglImage = hasEglAndroidImageCrop();
-        }
-    }
-
-    if (destroyEglImage) {
-        if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
-            ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
-                  slot);
-            // keep going
-        }
-        mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+    // If item->mGraphicBuffer is not null, this buffer has not been acquired
+    // 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;
+        mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
     }
 
     return NO_ERROR;
@@ -395,29 +384,18 @@
         return err;
     }
 
-    // If the mEglSlot entry is empty, create an EGLImage for the gralloc
-    // buffer currently in the slot in ConsumerBase.
-    //
+    // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
+    // if nessessary, for the gralloc buffer currently in the slot in
+    // ConsumerBase.
     // We may have to do this even when item.mGraphicBuffer == NULL (which
-    // means the buffer was previously acquired), if we destroyed the
-    // EGLImage when detaching from a context but the buffer has not been
-    // re-allocated.
-    if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
-        EGLImageKHR image = createImage(mEglDisplay,
-                mSlots[buf].mGraphicBuffer, item.mCrop);
-        if (image == EGL_NO_IMAGE_KHR) {
-            ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
-                  mEglDisplay, buf);
-            const sp<GraphicBuffer>& gb = mSlots[buf].mGraphicBuffer;
-            ST_LOGW("buffer size=%ux%u st=%u usage=0x%x fmt=%d",
-                gb->getWidth(), gb->getHeight(), gb->getStride(),
-                gb->getUsage(), gb->getPixelFormat());
-            releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
-                    mEglDisplay, EGL_NO_SYNC_KHR);
-            return UNKNOWN_ERROR;
-        }
-        mEglSlots[buf].mEglImage = image;
-        mEglSlots[buf].mCropRect = item.mCrop;
+    // means the buffer was previously acquired).
+    err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+    if (err != NO_ERROR) {
+        ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
+                mEglDisplay, buf);
+        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+                mEglDisplay, EGL_NO_SYNC_KHR);
+        return UNKNOWN_ERROR;
     }
 
     // Do whatever sync ops we need to do before releasing the old slot.
@@ -433,15 +411,15 @@
     }
 
     ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
-            mCurrentTexture,
-            mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+            mCurrentTexture, mCurrentTextureImage != NULL ?
+                    mCurrentTextureImage->graphicBufferHandle() : 0,
             buf, mSlots[buf].mGraphicBuffer->handle);
 
     // release old buffer
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
         status_t status = releaseBufferLocked(
-                mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
-                mEglSlots[mCurrentTexture].mEglFence);
+                mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
+                mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
         if (status < NO_ERROR) {
             ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
                    strerror(-status), status);
@@ -452,7 +430,7 @@
 
     // Update the GLConsumer state.
     mCurrentTexture = buf;
-    mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
+    mCurrentTextureImage = mEglSlots[buf].mEglImage;
     mCurrentCrop = item.mCrop;
     mCurrentTransform = item.mTransform;
     mCurrentScalingMode = item.mScalingMode;
@@ -477,25 +455,26 @@
     }
 
     glBindTexture(mTexTarget, mTexName);
-    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
-        if (mCurrentTextureBuf == NULL) {
-            ST_LOGE("bindTextureImage: no currently-bound texture");
-            return NO_INIT;
-        }
-        status_t err = bindUnslottedBufferLocked(mEglDisplay);
-        if (err != NO_ERROR) {
-            return err;
-        }
-    } else {
-        EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
+    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
+            mCurrentTextureImage == NULL) {
+        ST_LOGE("bindTextureImage: no currently-bound texture");
+        return NO_INIT;
+    }
 
-        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
+                                                      mCurrentCrop);
 
-        while ((error = glGetError()) != GL_NO_ERROR) {
-            ST_LOGE("bindTextureImage: error binding external texture image %p"
-                    ": %#04x", image, error);
-            return UNKNOWN_ERROR;
-        }
+    if (err != NO_ERROR) {
+        ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
+                mEglDisplay, mCurrentTexture);
+        return UNKNOWN_ERROR;
+    }
+
+    mCurrentTextureImage->bindToTextureTarget(mTexTarget);
+
+    while ((error = glGetError()) != GL_NO_ERROR) {
+        ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
+        return UNKNOWN_ERROR;
     }
 
     // Wait for the new buffer to be ready.
@@ -537,7 +516,7 @@
     if (fence->isValid() &&
             mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
         status_t err = addReleaseFence(mCurrentTexture,
-                mCurrentTextureBuf, fence);
+                mCurrentTextureImage->graphicBuffer(), fence);
         if (err != OK) {
             ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
                     strerror(-err), err);
@@ -583,18 +562,6 @@
         glDeleteTextures(1, &mTexName);
     }
 
-    // Because we're giving up the EGLDisplay we need to free all the EGLImages
-    // that are associated with it.  They'll be recreated when the
-    // GLConsumer gets attached to a new OpenGL ES context (and thus gets a
-    // new EGLDisplay).
-    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-        EGLImageKHR img = mEglSlots[i].mEglImage;
-        if (img != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mEglDisplay, img);
-            mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
-        }
-    }
-
     mEglDisplay = EGL_NO_DISPLAY;
     mEglContext = EGL_NO_CONTEXT;
     mAttached = false;
@@ -635,56 +602,25 @@
     // buffer.
     glBindTexture(mTexTarget, GLuint(tex));
 
-    if (mCurrentTextureBuf != NULL) {
-        // The EGLImageKHR that was associated with the slot was destroyed when
-        // the GLConsumer was detached from the old context, so we need to
-        // recreate it here.
-        status_t err = bindUnslottedBufferLocked(dpy);
-        if (err != NO_ERROR) {
-            return err;
-        }
-    }
-
     mEglDisplay = dpy;
     mEglContext = ctx;
     mTexName = tex;
     mAttached = true;
 
+    if (mCurrentTextureImage != NULL) {
+        // This may wait for a buffer a second time. This is likely required if
+        // this is a different context, since otherwise the wait could be skipped
+        // by bouncing through another context. For the same context the extra
+        // wait is redundant.
+        status_t err =  bindTextureImageLocked();
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
     return OK;
 }
 
-status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
-    ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
-            mCurrentTexture, mCurrentTextureBuf.get());
-
-    // Create a temporary EGLImageKHR.
-    Rect crop;
-    EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
-    if (image == EGL_NO_IMAGE_KHR) {
-        return UNKNOWN_ERROR;
-    }
-
-    // Attach the current buffer to the GL texture.
-    glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
-    GLint error;
-    status_t err = OK;
-    while ((error = glGetError()) != GL_NO_ERROR) {
-        ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
-                "(slot %d): %#04x", image, mCurrentTexture, error);
-        err = UNKNOWN_ERROR;
-    }
-
-    // We destroy the EGLImageKHR here because the current buffer may no
-    // longer be associated with one of the buffer slots, so we have
-    // nowhere to to store it.  If the buffer is still associated with a
-    // slot then another EGLImageKHR will be created next time that buffer
-    // gets acquired in updateTexImage.
-    eglDestroyImageKHR(dpy, image);
-
-    return err;
-}
-
 
 status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
     ST_LOGV("syncForReleaseLocked");
@@ -708,7 +644,7 @@
             }
             sp<Fence> fence(new Fence(fenceFd));
             status_t err = addReleaseFenceLocked(mCurrentTexture,
-                    mCurrentTextureBuf, fence);
+                    mCurrentTextureImage->graphicBuffer(), fence);
             if (err != OK) {
                 ST_LOGE("syncForReleaseLocked: error adding release fence: "
                         "%s (%d)", strerror(-err), err);
@@ -787,11 +723,11 @@
     bool needsRecompute = mFilteringEnabled != enabled;
     mFilteringEnabled = enabled;
 
-    if (needsRecompute && mCurrentTextureBuf==NULL) {
-        ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
+    if (needsRecompute && mCurrentTextureImage==NULL) {
+        ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
     }
 
-    if (needsRecompute && mCurrentTextureBuf != NULL) {
+    if (needsRecompute && mCurrentTextureImage != NULL) {
         computeCurrentTransformMatrixLocked();
     }
 }
@@ -825,10 +761,11 @@
         }
     }
 
-    sp<GraphicBuffer>& buf(mCurrentTextureBuf);
+    sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ?
+            NULL : mCurrentTextureImage->graphicBuffer();
 
     if (buf == NULL) {
-        ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
+        ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL");
     }
 
     float mtxBeforeFlipV[16];
@@ -911,39 +848,10 @@
     return mCurrentFrameNumber;
 }
 
-EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
-        const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
-    EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
-    EGLint attrs[] = {
-        EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
-        EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
-        EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
-        EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
-        EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
-        EGL_NONE,
-    };
-    if (!crop.isValid()) {
-        // No crop rect to set, so terminate the attrib array before the crop.
-        attrs[2] = EGL_NONE;
-    } else if (!isEglImageCroppable(crop)) {
-        // The crop rect is not at the origin, so we can't set the crop on the
-        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-        // extension.  In the future we can add a layered extension that
-        // removes this restriction if there is hardware that can support it.
-        attrs[2] = EGL_NONE;
-    }
-    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
-            EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
-    if (image == EGL_NO_IMAGE_KHR) {
-        EGLint error = eglGetError();
-        ST_LOGE("error creating EGLImage: %#x", error);
-    }
-    return image;
-}
-
 sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
     Mutex::Autolock lock(mMutex);
-    return mCurrentTextureBuf;
+    return (mCurrentTextureImage == NULL) ?
+            NULL : mCurrentTextureImage->graphicBuffer();
 }
 
 Rect GLConsumer::getCurrentCrop() const {
@@ -1067,18 +975,13 @@
     if (slotIndex == mCurrentTexture) {
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
     }
-    EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
-    if (img != EGL_NO_IMAGE_KHR) {
-        ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
-        eglDestroyImageKHR(mEglDisplay, img);
-    }
-    mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+    mEglSlots[slotIndex].mEglImage.clear();
     ConsumerBase::freeBufferLocked(slotIndex);
 }
 
 void GLConsumer::abandonLocked() {
     ST_LOGV("abandonLocked");
-    mCurrentTextureBuf.clear();
+    mCurrentTextureImage.clear();
     ConsumerBase::abandonLocked();
 }
 
@@ -1138,4 +1041,87 @@
     out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
 }
 
+GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
+    mGraphicBuffer(graphicBuffer),
+    mEglImage(EGL_NO_IMAGE_KHR),
+    mEglDisplay(EGL_NO_DISPLAY) {
+}
+
+GLConsumer::EglImage::~EglImage() {
+    if (mEglImage != EGL_NO_IMAGE_KHR) {
+        if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+           ALOGE("~EglImage: eglDestroyImageKHR failed");
+        }
+    }
+}
+
+status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
+                                              const Rect& cropRect) {
+    // If there's an image and it's no longer valid, destroy it.
+    bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
+    bool displayInvalid = mEglDisplay != eglDisplay;
+    bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
+    if (haveImage && (displayInvalid || cropInvalid)) {
+        if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+           ALOGE("createIfNeeded: eglDestroyImageKHR failed");
+        }
+        mEglImage = EGL_NO_IMAGE_KHR;
+        mEglDisplay = EGL_NO_DISPLAY;
+    }
+
+    // If there's no image, create one.
+    if (mEglImage == EGL_NO_IMAGE_KHR) {
+        mEglDisplay = eglDisplay;
+        mCropRect = cropRect;
+        mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+    }
+
+    // Fail if we can't create a valid image.
+    if (mEglImage == EGL_NO_IMAGE_KHR) {
+        mEglDisplay = EGL_NO_DISPLAY;
+        mCropRect.makeInvalid();
+        const sp<GraphicBuffer>& buffer = mGraphicBuffer;
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
+            buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
+            buffer->getUsage(), buffer->getPixelFormat());
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
+    glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage);
+}
+
+EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
+        const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+    EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+    EGLint attrs[] = {
+        EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
+        EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
+        EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
+        EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
+        EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
+        EGL_NONE,
+    };
+    if (!crop.isValid()) {
+        // No crop rect to set, so terminate the attrib array before the crop.
+        attrs[2] = EGL_NONE;
+    } else if (!isEglImageCroppable(crop)) {
+        // The crop rect is not at the origin, so we can't set the crop on the
+        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+        // extension.  In the future we can add a layered extension that
+        // removes this restriction if there is hardware that can support it.
+        attrs[2] = EGL_NONE;
+    }
+    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+            EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
+    if (image == EGL_NO_IMAGE_KHR) {
+        EGLint error = eglGetError();
+        ALOGE("error creating EGLImage: %#x", error);
+    }
+    return image;
+}
+
 }; // namespace android
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index 8f88141..28fcb53 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -34,8 +34,7 @@
     GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     ENABLE_DISABLE,
     SET_EVENT_RATE,
-    FLUSH_SENSOR,
-    DECREASE_WAKE_LOCK_REFCOUNT
+    FLUSH_SENSOR
 };
 
 class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -84,13 +83,6 @@
         remote()->transact(FLUSH_SENSOR, data, &reply);
         return reply.readInt32();
     }
-
-    virtual void decreaseWakeLockRefCount() {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
-        remote()->transact(DECREASE_WAKE_LOCK_REFCOUNT, data, &reply, IBinder::FLAG_ONEWAY);
-        return;
-    }
 };
 
 IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
@@ -133,11 +125,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
-        case DECREASE_WAKE_LOCK_REFCOUNT: {
-            CHECK_INTERFACE(ISensorEventConnection, data, reply);
-            decreaseWakeLockRefCount();
-            return NO_ERROR;
-        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 2103a95..613b8e2 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -166,83 +166,6 @@
         mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
         break;
-    case SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR:
-        mStringType = SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_WAKE_UP_ACCELEROMETER:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_ACCELEROMETER;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_MAGNETIC_FIELD;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_ORIENTATION:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_ORIENTATION;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_GYROSCOPE:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_GYROSCOPE;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_LIGHT:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_LIGHT;
-        mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_PRESSURE:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_PRESSURE;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_GRAVITY:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_GRAVITY;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_LINEAR_ACCELERATION;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_ROTATION_VECTOR;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_RELATIVE_HUMIDITY;
-        mFlags |= (SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_AMBIENT_TEMPERATURE;
-        mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_GAME_ROTATION_VECTOR;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_STEP_DETECTOR:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_STEP_DETECTOR;
-        mFlags |= (SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_STEP_COUNTER:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_STEP_COUNTER;
-        mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR;
-        mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
-    case SENSOR_TYPE_WAKE_UP_HEART_RATE:
-        mStringType = SENSOR_STRING_TYPE_WAKE_UP_HEART_RATE;
-        mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
-        mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
-        break;
     case SENSOR_TYPE_WAKE_UP_TILT_DETECTOR:
         mStringType = SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR;
         mFlags |= (SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP);
@@ -255,6 +178,10 @@
         mStringType = SENSOR_STRING_TYPE_GLANCE_GESTURE;
         mFlags |= (SENSOR_FLAG_ONE_SHOT_MODE | SENSOR_FLAG_WAKE_UP);
         break;
+    case SENSOR_TYPE_PICK_UP_GESTURE:
+        mStringType = SENSOR_STRING_TYPE_PICK_UP_GESTURE;
+        mFlags |= (SENSOR_FLAG_ONE_SHOT_MODE | SENSOR_FLAG_WAKE_UP);
+        break;
     default:
         // Only pipe the stringType, requiredPermission and flags for custom sensors.
         if (halVersion >= SENSORS_DEVICE_API_VERSION_1_2 && hwSensor->stringType) {
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index c2eaf4e..842502d 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -18,6 +18,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -147,7 +148,14 @@
 void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
     for (int i = 0; i < count; ++i) {
         if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
-            mSensorEventConnection->decreaseWakeLockRefCount();
+            // Send just a byte of data to acknowledge for the wake up sensor events
+            // received
+            char buf = '1';
+            ssize_t size = ::send(mSensorChannel->getFd(), &buf, sizeof(buf),
+                                             MSG_DONTWAIT | MSG_NOSIGNAL);
+            if (size < 0) {
+                ALOGE("sendAck failure %d", size);
+            }
         }
     }
     return;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index e21dc53..9b0bd60 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -126,6 +126,7 @@
 
 ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
 {
+    LOG_ALWAYS_FATAL_IF(this == NULL, "getNativeBuffer() called on NULL GraphicBuffer");
     return static_cast<ANativeWindowBuffer*>(
             const_cast<GraphicBuffer*>(this));
 }
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 6b90243..cc5d544 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -112,21 +112,16 @@
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -fvisibility=hidden
 
-include $(BUILD_SHARED_LIBRARY)
-
 # Symlink libGLESv3.so -> libGLESv2.so
 # Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
 # will be linked against libGLESv3.so.
-LIBGLESV2 := $(LOCAL_INSTALLED_MODULE)
-LIBGLESV3 := $(subst libGLESv2,libGLESv3,$(LIBGLESV2))
-$(LIBGLESV3): $(LIBGLESV2)
-	@echo "Symlink: $@ -> $(notdir $<)"
-	@mkdir -p $(dir $@)
-	$(hide) ln -sf $(notdir $<) $@
-ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
-	$(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(LIBGLESV3)
-LIBGLESV2 :=
-LIBGLESV3 :=
+# Note we defer the evaluation of the LOCAL_POST_INSTALL_CMD,
+# so $(LOCAL_INSTALLED_MODULE) will be expanded to correct value,
+# even for both 32-bit and 64-bit installed files in multilib build.
+LOCAL_POST_INSTALL_CMD = \
+    $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))libGLESv3.so
+
+include $(BUILD_SHARED_LIBRARY)
 
 ###############################################################################
 # Build the ETC1 host static library
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 2e7aa20..e6d0062 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -297,14 +297,18 @@
     arg_strpp->add_charvalue(src);
 }
 
-void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg,
+void fixup_glUniformGenericInteger(int argIndex, int nElemsPerVector, GLMessage *glmsg,
                                                                     void *pointersToFixup[]) {
     /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
-    fixup_GenericIntArray(argIndex, nIntegers, glmsg, pointersToFixup[0]);
+    GLMessage_DataType arg_count  = glmsg->args(1);
+    int n_vectors = arg_count.intvalue(0);
+    fixup_GenericIntArray(argIndex, nElemsPerVector * n_vectors, glmsg, pointersToFixup[0]);
 }
 
-void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
-    fixup_GenericFloatArray(argIndex, nFloats, glmsg, src);
+void fixup_glUniformGeneric(int argIndex, int nElemsPerVector, GLMessage *glmsg, void *src) {
+    GLMessage_DataType arg_count  = glmsg->args(1);
+    int n_vectors = arg_count.intvalue(0);
+    fixup_GenericFloatArray(argIndex, nElemsPerVector * n_vectors, glmsg, src);
 }
 
 void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg, void *pointersToFixup[]) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 6468017..8fe79d0 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -18,6 +18,7 @@
 #include <math.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <cutils/properties.h>
 
@@ -165,6 +166,7 @@
 
             mWakeLockAcquired = false;
             run("SensorService", PRIORITY_URGENT_DISPLAY);
+            mLooper = new Looper(false);
             mInitCheck = NO_ERROR;
         }
     }
@@ -340,6 +342,8 @@
     SensorDevice& device(SensorDevice::getInstance());
     const size_t vcount = mVirtualSensorList.size();
 
+    SensorEventAckReceiver sender(this);
+    sender.run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
     ssize_t count;
     const int halVersion = device.getHalDeviceVersion();
     do {
@@ -348,6 +352,11 @@
             ALOGE("sensor poll failed (%s)", strerror(-count));
             break;
         }
+
+        // Reset sensors_event_t.flags to zero for all events in the buffer.
+        for (int i = 0; i < count; i++) {
+             buffer[i].flags = 0;
+        }
         Mutex::Autolock _l(mLock);
         // Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The
         // rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock,
@@ -443,6 +452,19 @@
     return false;
 }
 
+sp<Looper> SensorService::getLooper() const {
+    return mLooper;
+}
+
+bool SensorService::SensorEventAckReceiver::threadLoop() {
+    ALOGD("new thread SensorEventAckReceiver");
+    do {
+        sp<Looper> looper = mService->getLooper();
+        looper->pollOnce(-1);
+    } while(!Thread::exitPending());
+    return false;
+}
+
 void SensorService::recordLastValueLocked(
         const sensors_event_t* buffer, size_t count) {
     const sensors_event_t* last = NULL;
@@ -656,6 +678,12 @@
         err = sensor->activate(connection.get(), true);
     }
 
+    if (err == NO_ERROR && sensor->getSensor().isWakeUpSensor()) {
+        // Add the file descriptor to the Looper for receiving acknowledgments;
+        int ret = mLooper->addFd(connection->getSensorChannel()->getSendFd(), 0,
+                                        ALOOPER_EVENT_INPUT, connection.get(), NULL);
+    }
+
     if (err != NO_ERROR) {
         // batch/activate has failed, reset our state.
         cleanupWithoutDisableLocked(connection, handle);
@@ -752,9 +780,8 @@
 
 
 bool SensorService::canAccessSensor(const Sensor& sensor) {
-    String16 permissionString(sensor.getRequiredPermission());
-    return permissionString.size() == 0 ||
-            PermissionCache::checkCallingPermission(permissionString);
+    return (sensor.getRequiredPermission().isEmpty()) ||
+            PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission()));
 }
 
 bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
@@ -797,7 +824,6 @@
     }
 }
 // ---------------------------------------------------------------------------
-
 SensorService::SensorRecord::SensorRecord(
         const sp<SensorEventConnection>& connection)
 {
@@ -828,25 +854,30 @@
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid)
-    : mService(service), mUid(uid), mWakeLockRefCount(0)
-{
+    : mService(service), mUid(uid), mWakeLockRefCount(0), mEventCache(NULL), mCacheSize(0),
+      mMaxCacheSize(0) {
     const SensorDevice& device(SensorDevice::getInstance());
     if (device.getHalDeviceVersion() >= SENSORS_DEVICE_API_VERSION_1_1) {
-        // Increase socket buffer size to 1MB for batching capabilities.
-        mChannel = new BitTube(service->mSocketBufferSize);
+        // Increase socket buffer size to a max of 100 KB for batching capabilities.
+        mChannel = new BitTube(mService->mSocketBufferSize);
     } else {
         mChannel = new BitTube(SOCKET_BUFFER_SIZE_NON_BATCHED);
     }
+#if DEBUG_CONNECTIONS
+    mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
+#endif
 }
 
-SensorService::SensorEventConnection::~SensorEventConnection()
-{
+SensorService::SensorEventConnection::~SensorEventConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+    if (mEventCache != NULL) {
+        delete mEventCache;
+    }
     mService->cleanupConnection(this);
 }
 
-void SensorService::SensorEventConnection::onFirstRef()
-{
+void SensorService::SensorEventConnection::onFirstRef() {
+    LooperCallback::onFirstRef();
 }
 
 bool SensorService::SensorEventConnection::needsWakeLock() {
@@ -856,15 +887,28 @@
 
 void SensorService::SensorEventConnection::dump(String8& result) {
     Mutex::Autolock _l(mConnectionLock);
-    result.appendFormat("%d WakeLockRefCount\n", mWakeLockRefCount);
+    result.appendFormat("\t %d WakeLockRefCount \n", mWakeLockRefCount);
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
-        result.appendFormat("\t %s | status: %s | pending flush events %d | uid %d\n",
+        result.appendFormat("\t %s | status: %s | pending flush events %d | flush calls %d| uid %d|"
+                            "cache size: %d max cache size %d\n",
                             mService->getSensorName(mSensorInfo.keyAt(i)).string(),
                             flushInfo.mFirstFlushPending ? "First flush pending" :
                                                            "active",
                             flushInfo.mPendingFlushEventsToSend,
-                            mUid);
+                            flushInfo.mNumFlushCalls,
+                            mUid,
+                            mCacheSize,
+                            mMaxCacheSize);
+#if DEBUG_CONNECTIONS
+        result.appendFormat("\t events recvd: %d | sent %d | cache %d | dropped %d\n",
+                                        mEventsReceived,
+                                        mEventsSent,
+                                        mEventsSentFromCache,
+                                        mEventsReceived - (mEventsSentFromCache +
+                                                           mEventsSent + mCacheSize));
+#endif
+
     }
 }
 
@@ -910,8 +954,7 @@
 
 status_t SensorService::SensorEventConnection::sendEvents(
         sensors_event_t const* buffer, size_t numEvents,
-        sensors_event_t* scratch)
-{
+        sensors_event_t* scratch) {
     // filter out events not for this connection
     size_t count = 0;
     Mutex::Autolock _l(mConnectionLock);
@@ -927,30 +970,127 @@
                 curr = buffer[i].meta_data.sensor;
             }
             ssize_t index = mSensorInfo.indexOfKey(curr);
-            if (index >= 0 && mSensorInfo[index].mFirstFlushPending == true &&
-                buffer[i].type == SENSOR_TYPE_META_DATA) {
-                // This is the first flush before activate is called. Events can now be sent for
-                // this sensor on this connection.
-                ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
-                         buffer[i].meta_data.sensor);
-                mSensorInfo.editValueAt(index).mFirstFlushPending = false;
+            // Check if this connection has registered for this sensor. If not continue to the
+            // next sensor_event.
+            if (index < 0) {
+                ++i;
+                continue;
             }
-            if (index >= 0 && mSensorInfo[index].mFirstFlushPending == false)  {
-                do {
+
+            // Check if there is a pending flush_complete event for this sensor on this connection.
+            FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
+            if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+                if (flushInfo.mFirstFlushPending == true) {
+                    // This is the first flush before activate is called. Events can now be sent for
+                    // this sensor on this connection.
+                    ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
+                                                    buffer[i].meta_data.sensor);
+                    flushInfo.mFirstFlushPending = false;
+                    ++i;
+                    continue;
+                }
+            }
+
+            // If there is a pending flush complete event for this sensor on this connection,
+            // ignore the event and proceed to the next.
+            if (flushInfo.mFirstFlushPending) {
+                ++i;
+                continue;
+            }
+
+            do {
+                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+                    // Send flush complete event only if flush() has been explicitly called by
+                    // this app else ignore.
+                    if (flushInfo.mNumFlushCalls > 0) {
+                        scratch[count++] = buffer[i];
+                        flushInfo.mNumFlushCalls--;
+                    }
+                    ++i;
+                } else {
+                    // Regular sensor event, just copy it to the scratch buffer.
                     scratch[count++] = buffer[i++];
-                } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
-                         (buffer[i].type == SENSOR_TYPE_META_DATA  &&
-                          buffer[i].meta_data.sensor == curr)));
-            } else {
-                i++;
-            }
+                }
+            } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
+                                       (buffer[i].type == SENSOR_TYPE_META_DATA  &&
+                                        buffer[i].meta_data.sensor == curr)));
         }
     } else {
         scratch = const_cast<sensors_event_t *>(buffer);
         count = numEvents;
     }
 
-    // Send pending flush events (if any) before sending events from the cache.
+    // Early return if there are no events for this connection.
+    if (count == 0) {
+        return status_t(NO_ERROR);
+    }
+
+#if DEBUG_CONNECTIONS
+     mEventsReceived += count;
+#endif
+    if (mCacheSize != 0) {
+        // There are some events in the cache which need to be sent first. Copy this buffer to
+        // the end of cache.
+        if (mCacheSize + count <= mMaxCacheSize) {
+            memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
+            mCacheSize += count;
+        } else {
+            // Some events need to be dropped.
+            int remaningCacheSize = mMaxCacheSize - mCacheSize;
+            if (remaningCacheSize != 0) {
+                memcpy(&mEventCache[mCacheSize], scratch,
+                                                remaningCacheSize * sizeof(sensors_event_t));
+            }
+            int numEventsDropped = count - remaningCacheSize;
+            countFlushCompleteEventsLocked(mEventCache, numEventsDropped);
+            // Drop the first "numEventsDropped" in the cache.
+            memmove(mEventCache, &mEventCache[numEventsDropped],
+                    (mCacheSize - numEventsDropped) * sizeof(sensors_event_t));
+
+            // Copy the remainingEvents in scratch buffer to the end of cache.
+            memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
+                                            numEventsDropped * sizeof(sensors_event_t));
+        }
+        return status_t(NO_ERROR);
+    }
+
+    int numWakeUpSensorEvents = countWakeUpSensorEventsLocked(scratch, count);
+    mWakeLockRefCount += numWakeUpSensorEvents;
+
+    // NOTE: ASensorEvent and sensors_event_t are the same type.
+    ssize_t size = SensorEventQueue::write(mChannel,
+                                    reinterpret_cast<ASensorEvent const*>(scratch), count);
+    if (size < 0) {
+        // Write error, copy events to local cache.
+        mWakeLockRefCount -= numWakeUpSensorEvents;
+        if (mEventCache == NULL) {
+            mMaxCacheSize = computeMaxCacheSizeLocked();
+            mEventCache = new sensors_event_t[mMaxCacheSize];
+            mCacheSize = 0;
+        }
+        memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
+        mCacheSize += count;
+
+        // Add this file descriptor to the looper to get a callback when this fd is available for
+        // writing.
+        mService->getLooper()->addFd(mChannel->getSendFd(), 0,
+                ALOOPER_EVENT_OUTPUT | ALOOPER_EVENT_INPUT, this, NULL);
+        return size;
+    }
+
+#if DEBUG_CONNECTIONS
+    if (size > 0) {
+        mEventsSent += count;
+    }
+#endif
+
+    return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+void SensorService::SensorEventConnection::writeToSocketFromCacheLocked() {
+    // At a time write at most half the size of the receiver buffer in SensorEventQueue.
+    const int maxWriteSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2;
+    // Send pending flush events (if any) before sending events from the buffer.
     {
         ASensorEvent flushCompleteEvent;
         flushCompleteEvent.type = SENSOR_TYPE_META_DATA;
@@ -963,35 +1103,44 @@
                 flushCompleteEvent.meta_data.sensor = mSensorInfo.keyAt(i);
                 ssize_t size = SensorEventQueue::write(mChannel, &flushCompleteEvent, 1);
                 if (size < 0) {
-                    // ALOGW("dropping %d events on the floor", count);
-                    countFlushCompleteEventsLocked(scratch, count);
-                    return size;
+                    return;
                 }
                 ALOGD_IF(DEBUG_CONNECTIONS, "sent dropped flush complete event==%d ",
-                         flushCompleteEvent.meta_data.sensor);
+                                                flushCompleteEvent.meta_data.sensor);
                 flushInfo.mPendingFlushEventsToSend--;
             }
         }
     }
+    // Write "count" events at a time.
+    for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
+        const int count = (mCacheSize - numEventsSent) < maxWriteSize ?
+                                        mCacheSize - numEventsSent : maxWriteSize;
+        int numWakeUpSensorEvents =
+                  countWakeUpSensorEventsLocked(mEventCache + numEventsSent, count);
+        mWakeLockRefCount += numWakeUpSensorEvents;
 
-    // Early return if there are no events for this connection.
-    if (count == 0) {
-        return status_t(NO_ERROR);
+        ssize_t size = SensorEventQueue::write(mChannel,
+                          reinterpret_cast<ASensorEvent const*>(mEventCache + numEventsSent),
+                          count);
+        if (size < 0) {
+            memmove(mEventCache, &mEventCache[numEventsSent],
+                                 (mCacheSize - numEventsSent) * sizeof(sensors_event_t));
+            ALOGD_IF(DEBUG_CONNECTIONS, "wrote %d events from cache size==%d ",
+                                            numEventsSent, mCacheSize);
+            mCacheSize -= numEventsSent;
+            mWakeLockRefCount -= numWakeUpSensorEvents;
+            return;
+        }
+        numEventsSent += count;
+#if DEBUG_CONNECTIONS
+        mEventsSentFromCache += count;
+#endif
     }
-
-    int numWakeUpSensorEvents = countWakeUpSensorEventsLocked(scratch, count);
-    // NOTE: ASensorEvent and sensors_event_t are the same type
-    ssize_t size = SensorEventQueue::write(mChannel,
-            reinterpret_cast<ASensorEvent const*>(scratch), count);
-    if (size == -EAGAIN) {
-        // the destination doesn't accept events anymore, it's probably
-        // full. For now, we just drop the events on the floor.
-        // ALOGW("dropping %d events on the floor", count);
-        countFlushCompleteEventsLocked(scratch, count);
-        mWakeLockRefCount -= numWakeUpSensorEvents;
-        return size;
-    }
-    return size < 0 ? status_t(size) : status_t(NO_ERROR);
+    ALOGD_IF(DEBUG_CONNECTIONS, "wrote all events from cache size=%d ", mCacheSize);
+    // All events from the cache have been sent. Reset cache size to zero.
+    mCacheSize = 0;
+    // Poll only for ALOOPER_EVENT_INPUT(read) on the file descriptor.
+    mService->getLooper()->addFd(mChannel->getSendFd(), 0, ALOOPER_EVENT_INPUT, this, NULL);
 }
 
 void SensorService::SensorEventConnection::countFlushCompleteEventsLocked(
@@ -1015,7 +1164,6 @@
     for (int i = 0; i < count; ++i) {
         if (mService->isWakeUpSensorEvent(scratch[i])) {
             scratch[i].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
-            ++mWakeLockRefCount;
             return 1;
         }
     }
@@ -1035,6 +1183,7 @@
     if (enabled) {
         err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
                                reservedFlags);
+
     } else {
         err = mService->disable(this, handle);
     }
@@ -1055,14 +1204,16 @@
     // Loop through all sensors for this connection and call flush on each of them.
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const int handle = mSensorInfo.keyAt(i);
+        FlushInfo& flushInfo = mSensorInfo.editValueFor(handle);
         if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 || mService->isVirtualSensor(handle)) {
             // For older devices just increment pending flush count which will send a trivial
             // flush complete event.
-            FlushInfo& flushInfo = mSensorInfo.editValueFor(handle);
             flushInfo.mPendingFlushEventsToSend++;
         } else {
             status_t err_flush = mService->flushSensor(this, handle);
-            if (err_flush != NO_ERROR) {
+            if (err_flush == NO_ERROR) {
+                flushInfo.mNumFlushCalls++;
+            } else {
                 ALOGE("Flush error handle=%d %s", handle, strerror(-err_flush));
             }
             err = (err_flush != NO_ERROR) ? err_flush : err;
@@ -1071,15 +1222,69 @@
     return err;
 }
 
-void SensorService::SensorEventConnection::decreaseWakeLockRefCount() {
-    {
+int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* data) {
+    if (events & ALOOPER_EVENT_HANGUP || events & ALOOPER_EVENT_ERROR) {
+        return 0;
+    }
+
+    if (events & ALOOPER_EVENT_INPUT) {
+        char buf;
+        ssize_t ret = ::recv(fd, &buf, sizeof(buf), MSG_DONTWAIT);
+
+        {
+           Mutex::Autolock _l(mConnectionLock);
+           --mWakeLockRefCount;
+        }
+        // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released
+        // here as checkWakeLockState() will need it.
+        if (mWakeLockRefCount == 0) {
+            mService->checkWakeLockState();
+        }
+        // continue getting callbacks.
+        return 1;
+    }
+
+    if (events & ALOOPER_EVENT_OUTPUT) {
+        // send sensor data that is stored in mEventCache.
         Mutex::Autolock _l(mConnectionLock);
-        --mWakeLockRefCount;
+        writeToSocketFromCacheLocked();
     }
-    // Release the lock before calling checkWakeLockState which also needs the same connectionLock.
-    if (mWakeLockRefCount == 0) {
-        mService->checkWakeLockState();
-    }
+    return 1;
+}
+
+int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const {
+    int fifoWakeUpSensors = 0;
+    int fifoNonWakeUpSensors = 0;
+    for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+        const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i));
+        if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
+            // Each sensor has a reserved fifo. Sum up the fifo sizes for all wake up sensors and
+            // non wake_up sensors.
+            if (sensor.isWakeUpSensor()) {
+                fifoWakeUpSensors += sensor.getFifoReservedEventCount();
+            } else {
+                fifoNonWakeUpSensors += sensor.getFifoReservedEventCount();
+            }
+        } else {
+            // Shared fifo. Compute the max of the fifo sizes for wake_up and non_wake up sensors.
+            if (sensor.isWakeUpSensor()) {
+                fifoWakeUpSensors = fifoWakeUpSensors > sensor.getFifoMaxEventCount() ?
+                                          fifoWakeUpSensors : sensor.getFifoMaxEventCount();
+
+            } else {
+                fifoNonWakeUpSensors = fifoNonWakeUpSensors > sensor.getFifoMaxEventCount() ?
+                                          fifoNonWakeUpSensors : sensor.getFifoMaxEventCount();
+
+            }
+        }
+   }
+   if (fifoWakeUpSensors + fifoNonWakeUpSensors == 0) {
+       // It is extremely unlikely that there is a write failure in non batch mode. Return a cache
+       // size of 100.
+       ALOGI("Write failure in non-batch mode");
+       return 100;
+   }
+   return fifoWakeUpSensors + fifoNonWakeUpSensors;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5fd56b8..3cdc825 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -24,7 +24,9 @@
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
+#include <utils/AndroidThreads.h>
 #include <utils/RefBase.h>
+#include <utils/Looper.h>
 
 #include <binder/BinderService.h>
 
@@ -38,10 +40,11 @@
 // ---------------------------------------------------------------------------
 
 #define DEBUG_CONNECTIONS   false
-// Max size is 1 MB which is enough to accept a batch of about 10k events.
-#define MAX_SOCKET_BUFFER_SIZE_BATCHED 1024 * 1024
+// Max size is 100 KB which is enough to accept a batch of about 1000 events.
+#define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024
+// For older HALs which don't support batching, use a smaller socket buffer size.
 #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
-#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1 << 31)
+#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1U << 31)
 
 struct sensors_poll_device_t;
 struct sensors_module_t;
@@ -72,7 +75,8 @@
     virtual sp<ISensorEventConnection> createSensorEventConnection();
     virtual status_t dump(int fd, const Vector<String16>& args);
 
-    class SensorEventConnection : public BnSensorEventConnection {
+    class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
+        friend class SensorService;
         virtual ~SensorEventConnection();
         virtual void onFirstRef();
         virtual sp<BitTube> getSensorChannel() const;
@@ -80,7 +84,6 @@
                                        nsecs_t maxBatchReportLatencyNs, int reservedFlags);
         virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
         virtual status_t flush();
-        void decreaseWakeLockRefCount();
         // Count the number of flush complete events which are about to be dropped in the buffer.
         // Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be
         // sent separately before the next batch of events.
@@ -90,7 +93,20 @@
         // Increment it by exactly one unit for each packet sent on the socket. SOCK_SEQPACKET for
         // the socket ensures that either the entire packet is read or dropped.
         // Return 1 if mWakeLockRefCount has been incremented, zero if not.
-        int countWakeUpSensorEventsLocked(sensors_event_t* scratch, const int count);
+        int countWakeUpSensorEventsLocked(sensors_event_t* scratch, int count);
+
+        // Writes events from mEventCache to the socket.
+        void writeToSocketFromCacheLocked();
+
+        // Compute the approximate cache size from the FIFO sizes of various sensors registered for
+        // this connection. Wake up and non-wake up sensors have separate FIFOs but FIFO may be
+        // shared amongst wake-up sensors and non-wake up sensors.
+        int computeMaxCacheSizeLocked() const;
+
+        // LooperCallback method. If there is data to read on this fd, it is an ack from the
+        // app that it has read events from a wake up sensor, decrement mWakeLockRefCount.
+        // If this fd is available for writing send the data from the cache.
+        virtual int handleEvent(int fd, int events, void* data);
 
         sp<SensorService> const mService;
         sp<BitTube> mChannel;
@@ -108,10 +124,20 @@
             // Every activate is preceded by a flush. Only after the first flush complete is
             // received, the events for the sensor are sent on that *connection*.
             bool mFirstFlushPending;
-            FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false) {}
+            // Number of time flush() was called on this connection. This is incremented every time
+            // flush() is called and decremented when flush_complete_event is received.
+            int mNumFlushCalls;
+            FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false),
+                                            mNumFlushCalls(0) {}
         };
         // protected by SensorService::mLock. Key for this vector is the sensor handle.
         KeyedVector<int, FlushInfo> mSensorInfo;
+        sensors_event_t *mEventCache;
+        int mCacheSize, mMaxCacheSize;
+
+#if DEBUG_CONNECTIONS
+        int mEventsReceived, mEventsSent, mEventsSentFromCache;
+#endif
 
     public:
         SensorEventConnection(const sp<SensorService>& service, uid_t uid);
@@ -138,6 +164,13 @@
         size_t getNumConnections() const { return mConnections.size(); }
     };
 
+    class SensorEventAckReceiver : public Thread {
+        sp<SensorService> const mService;
+    public:
+        virtual bool threadLoop();
+        SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
+    };
+
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     Sensor getSensorFromHandle(int handle) const;
@@ -160,6 +193,9 @@
     void checkWakeLockState();
     void checkWakeLockStateLocked();
     bool isWakeUpSensorEvent(const sensors_event_t& event) const;
+
+    sp<Looper> getLooper() const;
+
     // constants
     Vector<Sensor> mSensorList;
     Vector<Sensor> mUserSensorListDebug;
@@ -168,6 +204,7 @@
     Vector<SensorInterface *> mVirtualSensorList;
     status_t mInitCheck;
     size_t mSocketBufferSize;
+    sp<Looper> mLooper;
 
     // protected by mLock
     mutable Mutex mLock;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 185dab2..a8fb5bd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -681,6 +681,9 @@
                     if (l.compositionType == HWC_OVERLAY) {
                         disp.hasOvComp = true;
                     }
+                    if (l.compositionType == HWC_CURSOR_OVERLAY) {
+                        disp.hasOvComp = true;
+                    }
                 }
                 if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
                     disp.hasFbComp = true;
@@ -853,6 +856,16 @@
     return mDisplayData[id].lastRetireFence;
 }
 
+status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos)
+{
+    if (mHwc->setCursorPositionAsync) {
+        return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top);
+    }
+    else {
+        return NO_ERROR;
+    }
+}
+
 /*
  * Helper template to implement a concrete HWCLayer
  * This holds the pointer to the concrete hwc layer type
@@ -935,6 +948,16 @@
             getLayer()->flags &= ~HWC_SKIP_LAYER;
         }
     }
+    virtual void setIsCursorLayerHint(bool isCursor) {
+        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+            if (isCursor) {
+                getLayer()->flags |= HWC_IS_CURSOR_LAYER;
+            }
+            else {
+                getLayer()->flags &= ~HWC_IS_CURSOR_LAYER;
+            }
+        }
+    }
     virtual void setBlending(uint32_t blending) {
         getLayer()->blending = blending;
     }
@@ -1122,6 +1145,8 @@
                             "HWC",
                             "BKGND",
                             "FB TARGET",
+                            "SIDEBAND",
+                            "HWC_CURSOR",
                             "UNKNOWN"};
                     if (type >= NELEM(compositionTypeName))
                         type = NELEM(compositionTypeName) - 1;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c62b924..9bd99eb 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -141,6 +141,8 @@
     // displays, writes to the output buffer are complete.
     sp<Fence> getLastRetireFence(int32_t id) const;
 
+    status_t setCursorPositionAsync(int32_t id, const Rect &pos);
+
     /*
      * Interface to hardware composer's layers functionality.
      * This abstracts the HAL interface to layers which can evolve in
@@ -157,6 +159,7 @@
         virtual sp<Fence> getAndResetReleaseFence() = 0;
         virtual void setDefaultState() = 0;
         virtual void setSkip(bool skip) = 0;
+        virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
         virtual void setBlending(uint32_t blending) = 0;
         virtual void setTransform(uint32_t transform) = 0;
         virtual void setFrame(const Rect& frame) = 0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4861e34..bbb5cfe 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -79,7 +79,8 @@
         mSecure(false),
         mProtectedByApp(false),
         mHasSurface(false),
-        mClientRef(client)
+        mClientRef(client),
+        mPotentialCursor(false)
 {
     mCurrentCrop.makeInvalid();
     mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -200,6 +201,7 @@
 
     mFormat = format;
 
+    mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
     mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
     mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
     mCurrentOpacity = getOpacityForFormat(format);
@@ -441,7 +443,7 @@
     // TODO: there is a possible optimization here: we only need to set the
     // acquire fence the first time a new buffer is acquired on EACH display.
 
-    if (layer.getCompositionType() == HWC_OVERLAY) {
+    if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) {
         sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
         if (fence->isValid()) {
             fenceFd = fence->dup();
@@ -453,6 +455,26 @@
     layer.setAcquireFenceFd(fenceFd);
 }
 
+Rect Layer::getPosition(
+    const sp<const DisplayDevice>& hw)
+{
+    // this gives us only the "orientation" component of the transform
+    const State& s(getCurrentState());
+
+    // apply the layer's transform, followed by the display's global transform
+    // here we're guaranteed that the layer's transform preserves rects
+    Rect win(s.active.w, s.active.h);
+    if (!s.active.crop.isEmpty()) {
+        win.intersect(s.active.crop, &win);
+    }
+    // subtract the transparent region and snap to the bounds
+    Rect bounds = reduce(win, s.activeTransparentRegion);
+    Rect frame(s.transform.transform(bounds));
+    frame.intersect(hw->getViewport(), &frame);
+    const Transform& tr(hw->getTransform());
+    return Rect(tr.transform(frame));
+}
+
 // ---------------------------------------------------------------------------
 // drawing...
 // ---------------------------------------------------------------------------
@@ -1187,6 +1209,9 @@
         // need a hardware-protected path to external video sink
         usage |= GraphicBuffer::USAGE_PROTECTED;
     }
+    if (mPotentialCursor) {
+        usage |= GraphicBuffer::USAGE_CURSOR;
+    }
     usage |= GraphicBuffer::USAGE_HW_COMPOSER;
     return usage;
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2d8084d..e21dd36 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -201,6 +201,8 @@
     void setAcquireFence(const sp<const DisplayDevice>& hw,
             HWComposer::HWCLayerInterface& layer);
 
+    Rect getPosition(const sp<const DisplayDevice>& hw);
+
     /*
      * called after page-flip
      */
@@ -260,6 +262,8 @@
      */
     Region latchBuffer(bool& recomputeVisibleRegions);
 
+    bool isPotentialCursor() const { return mPotentialCursor;}
+
     /*
      * called with the state lock when the surface is removed from the
      * current list
@@ -391,6 +395,9 @@
     // Set to true once we've returned this surface's handle
     mutable bool mHasSurface;
     const wp<Client> mClientRef;
+
+    // This layer can be a cursor on some displays.
+    bool mPotentialCursor;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index aeba720..53b0dc4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -990,6 +990,26 @@
             }
         }
 
+        // If possible, attempt to use the cursor overlay on each display.
+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+            sp<const DisplayDevice> hw(mDisplays[dpy]);
+            const int32_t id = hw->getHwcDisplayId();
+            if (id >= 0) {
+                const Vector< sp<Layer> >& currentLayers(
+                    hw->getVisibleLayersSortedByZ());
+                const size_t count = currentLayers.size();
+                HWComposer::LayerListIterator cur = hwc.begin(id);
+                const HWComposer::LayerListIterator end = hwc.end(id);
+                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+                    const sp<Layer>& layer(currentLayers[i]);
+                    if (layer->isPotentialCursor()) {
+                        cur->setIsCursorLayerHint();
+                        break;
+                    }
+                }
+            }
+        }
+
         status_t err = hwc.prepare();
         ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
 
@@ -1364,6 +1384,34 @@
     }
 
     commitTransaction();
+
+    updateCursorAsync();
+}
+
+void SurfaceFlinger::updateCursorAsync()
+{
+    HWComposer& hwc(getHwComposer());
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        sp<const DisplayDevice> hw(mDisplays[dpy]);
+        const int32_t id = hw->getHwcDisplayId();
+        if (id < 0) {
+            continue;
+        }
+        const Vector< sp<Layer> >& currentLayers(
+            hw->getVisibleLayersSortedByZ());
+        const size_t count = currentLayers.size();
+        HWComposer::LayerListIterator cur = hwc.begin(id);
+        const HWComposer::LayerListIterator end = hwc.end(id);
+        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+            if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
+                continue;
+            }
+            const sp<Layer>& layer(currentLayers[i]);
+            Rect cursorPos = layer->getPosition(hw);
+            hwc.setCursorPositionAsync(id, cursorPos);
+            break;
+        }
+    }
 }
 
 void SurfaceFlinger::commitTransaction()
@@ -1695,6 +1743,7 @@
             const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
             if (!clip.isEmpty()) {
                 switch (cur->getCompositionType()) {
+                    case HWC_CURSOR_OVERLAY:
                     case HWC_OVERLAY: {
                         const Layer::State& state(layer->getDrawingState());
                         if ((cur->getHints() & HWC_HINT_CLEAR_FB)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 996a795..476e549 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -249,6 +249,8 @@
     void handleTransaction(uint32_t transactionFlags);
     void handleTransactionLocked(uint32_t transactionFlags);
 
+    void updateCursorAsync();
+
     /* handlePageFilp: this is were we latch a new buffer
      * if available and compute the dirty region.
      */