Merge "Fixed disconnect bug in SurfaceTexture"
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 8414ff6..65ccb8d 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -254,6 +254,14 @@
     AKEYCODE_CALENDAR        = 208,
     AKEYCODE_MUSIC           = 209,
     AKEYCODE_CALCULATOR      = 210,
+    AKEYCODE_ZENKAKU_HANKAKU = 211,
+    AKEYCODE_EISU            = 212,
+    AKEYCODE_MUHENKAN        = 213,
+    AKEYCODE_HENKAN          = 214,
+    AKEYCODE_KATAKANA_HIRAGANA = 215,
+    AKEYCODE_YEN             = 216,
+    AKEYCODE_RO              = 217,
+    AKEYCODE_KANA            = 218,
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
index 76389a0..3022d05 100644
--- a/include/gui/BitTube.h
+++ b/include/gui/BitTube.h
@@ -22,6 +22,7 @@
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <cutils/log.h>
 
 
 namespace android {
@@ -43,9 +44,27 @@
 
     status_t writeToParcel(Parcel* reply) const;
 
+    template <typename T>
+    static ssize_t sendObjects(const sp<BitTube>& tube,
+            T const* events, size_t count) {
+        return sendObjects(tube, events, count, sizeof(T));
+    }
+
+    template <typename T>
+    static ssize_t recvObjects(const sp<BitTube>& tube,
+            T* events, size_t count) {
+        return recvObjects(tube, events, count, sizeof(T));
+    }
+
 private:
     int mSendFd;
     mutable int mReceiveFd;
+
+    static ssize_t sendObjects(const sp<BitTube>& tube,
+            void const* events, size_t count, size_t objSize);
+
+    static ssize_t recvObjects(const sp<BitTube>& tube,
+            void* events, size_t count, size_t objSize);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index 7bca8d6..e631cca 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -89,7 +89,7 @@
     int getFd() const;
 
     /*
-     * getEvents reads event from the queue and returns how many events were
+     * getEvents reads events from the queue and returns how many events were
      * read. Returns 0 if there are no more events or a negative error code.
      * If NOT_ENOUGH_DATA is returned, the object has become invalid forever, it
      * should be destroyed and getEvents() shouldn't be called again.
@@ -99,6 +99,13 @@
             Event* events, size_t count);
 
     /*
+     * sendEvents write events to the queue and returns how many events were
+     * written.
+     */
+    static ssize_t sendEvents(const sp<BitTube>& dataChannel,
+            Event const* events, size_t count);
+
+    /*
      * setVsyncRate() sets the Event::VSync delivery rate. A value of
      * 1 returns every Event::VSync. A value of 2 returns every other event,
      * etc... a value of 0 returns no event unless  requestNextVsync() has
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index ef7c6e3..759b5cb 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -54,7 +54,10 @@
     virtual void onFirstRef();
 
     int getFd() const;
-    ssize_t write(ASensorEvent const* events, size_t numEvents);
+
+    static ssize_t write(const sp<BitTube>& tube,
+            ASensorEvent const* events, size_t numEvents);
+
     ssize_t read(ASensorEvent* events, size_t numEvents);
 
     status_t waitForEvent() const;
diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h
new file mode 100644
index 0000000..81d9601
--- /dev/null
+++ b/include/media/hardware/CryptoAPI.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Errors.h>
+
+#ifndef CRYPTO_API_H_
+
+#define CRYPTO_API_H_
+
+namespace android {
+
+struct CryptoPlugin;
+
+struct CryptoFactory {
+    CryptoFactory() {}
+    virtual ~CryptoFactory() {}
+
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
+
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *data, size_t size,
+            CryptoPlugin **plugin) = 0;
+
+private:
+    CryptoFactory(const CryptoFactory &);
+    CryptoFactory &operator=(const CryptoFactory &);
+};
+
+struct CryptoPlugin {
+    enum Mode {
+        kMode_Unencrypted = 0,
+        kMode_AES_CTR     = 1,
+
+        // Neither key nor iv are being used in this mode.
+        // Each subsample is encrypted w/ an iv of all zeroes.
+        kMode_AES_WV      = 2,  // FIX constant
+    };
+
+    struct SubSample {
+        size_t mNumBytesOfClearData;
+        size_t mNumBytesOfEncryptedData;
+    };
+
+    CryptoPlugin() {}
+    virtual ~CryptoPlugin() {}
+
+    // If this method returns false, a non-secure decoder will be used to
+    // decode the data after decryption. The decrypt API below will have
+    // to support insecure decryption of the data (secure = false) for
+    // media data of the given mime type.
+    virtual bool requiresSecureDecoderComponent(const char *mime) const = 0;
+
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            Mode mode,
+            const void *srcPtr,
+            const SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr) = 0;
+
+private:
+    CryptoPlugin(const CryptoPlugin &);
+    CryptoPlugin &operator=(const CryptoPlugin &);
+};
+
+}  // namespace android
+
+extern "C" {
+    extern android::CryptoFactory *createCryptoFactory();
+}
+
+#endif  // CRYPTO_API_H_
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 55f4178..355a319 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -16,9 +16,9 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <fcntl.h>
-#include <signal.h>
 #include <unistd.h>
 
 #include <utils/Errors.h>
@@ -30,17 +30,25 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+// Socket buffer size.  The default is typically about 128KB, which is much larger than
+// we really need.  So we make it smaller.
+static const size_t SOCKET_BUFFER_SIZE = 4 * 1024;
+
+
 BitTube::BitTube()
     : mSendFd(-1), mReceiveFd(-1)
 {
-    int fds[2];
-    if (pipe(fds) == 0) {
-        mReceiveFd = fds[0];
-        mSendFd = fds[1];
-        fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
-        fcntl(mSendFd, F_SETFL, O_NONBLOCK);
-        // ignore SIGPIPE, we handle write errors through EPIPE instead
-        signal(SIGPIPE, SIG_IGN);
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
+        int size = SOCKET_BUFFER_SIZE;
+        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
+        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
+        mReceiveFd = sockets[0];
+        mSendFd = sockets[1];
     } else {
         mReceiveFd = -errno;
         ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
@@ -52,6 +60,9 @@
 {
     mReceiveFd = dup(data.readFileDescriptor());
     if (mReceiveFd >= 0) {
+        int size = SOCKET_BUFFER_SIZE;
+        setsockopt(mReceiveFd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+        setsockopt(mReceiveFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
         fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
     } else {
         mReceiveFd = -errno;
@@ -86,7 +97,7 @@
 {
     ssize_t err, len;
     do {
-        len = ::write(mSendFd, vaddr, size);
+        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
         err = len < 0 ? errno : 0;
     } while (err == EINTR);
     return err == 0 ? len : -err;
@@ -97,7 +108,7 @@
 {
     ssize_t err, len;
     do {
-        len = ::read(mReceiveFd, vaddr, size);
+        len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
         err = len < 0 ? errno : 0;
     } while (err == EINTR);
     if (err == EAGAIN || err == EWOULDBLOCK) {
@@ -119,5 +130,46 @@
     return result;
 }
 
+
+ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
+        void const* events, size_t count, size_t objSize)
+{
+    ssize_t numObjects = 0;
+    for (size_t i=0 ; i<count ; i++) {
+        const char* vaddr = reinterpret_cast<const char*>(events) + objSize * i;
+        ssize_t size = tube->write(vaddr, objSize);
+        if (size < 0) {
+            // error occurred
+            numObjects = -size;
+            break;
+        } else if (size == 0) {
+            // no more space
+            break;
+        }
+        numObjects++;
+    }
+    return numObjects;
+}
+
+ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
+        void* events, size_t count, size_t objSize)
+{
+    ssize_t numObjects = 0;
+    for (size_t i=0 ; i<count ; i++) {
+        char* vaddr = reinterpret_cast<char*>(events) + objSize * i;
+        ssize_t size = tube->read(vaddr, objSize);
+        if (size < 0) {
+            // error occurred
+            numObjects = -size;
+            break;
+        } else if (size == 0) {
+            // no more messages
+            break;
+        }
+        numObjects++;
+    }
+    return numObjects;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index a6790ad..9973e8d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -85,22 +85,13 @@
 ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
         Event* events, size_t count)
 {
-    ssize_t size = dataChannel->read(events, sizeof(events[0])*count);
-    ALOGE_IF(size<0,
-            "DisplayEventReceiver::getEvents error (%s)",
-            strerror(-size));
-    if (size >= 0) {
-        // Note: if (size % sizeof(events[0])) != 0, we've got a
-        // partial read. This can happen if the queue filed up (ie: if we
-        // didn't pull from it fast enough).
-        // We discard the partial event and rely on the sender to
-        // re-send the event if appropriate (some events, like VSYNC
-        // can be lost forever).
+    return BitTube::recvObjects(dataChannel, events, count);
+}
 
-        // returns number of events read
-        size /= sizeof(events[0]);
-    }
-    return size;
+ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
+        Event const* events, size_t count)
+{
+    return BitTube::sendObjects(dataChannel, events, count);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index b95dd90..04ba640 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -53,36 +53,15 @@
     return mSensorChannel->getFd();
 }
 
-ssize_t SensorEventQueue::write(ASensorEvent const* events, size_t numEvents)
-{
-    ssize_t size = mSensorChannel->write(events, numEvents * sizeof(events[0]));
-    if (size >= 0) {
-        if (size % sizeof(events[0])) {
-            // partial write!!! should never happen.
-            return -EINVAL;
-        }
-        // returns number of events written
-        size /= sizeof(events[0]);
-    }
-    return size;
+
+ssize_t SensorEventQueue::write(const sp<BitTube>& tube,
+        ASensorEvent const* events, size_t numEvents) {
+    return BitTube::sendObjects(tube, events, numEvents);
 }
 
 ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
 {
-    ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0]));
-    ALOGE_IF(size<0 && size!=-EAGAIN,
-            "SensorChannel::read error (%s)", strerror(-size));
-    if (size >= 0) {
-        if (size % sizeof(events[0])) {
-            // partial read!!! should never happen.
-            ALOGE("SensorEventQueue partial read (event-size=%u, read=%d)",
-                    sizeof(events[0]), int(size));
-            return -EINVAL;
-        }
-        // returns number of events read
-        size /= sizeof(events[0]);
-    }
-    return size;
+    return BitTube::recvObjects(mSensorChannel, events, numEvents);
 }
 
 sp<Looper> SensorEventQueue::getLooper() const
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 702b52b..d2e0110 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,8 +10,6 @@
     DisplayHardware/DisplayHardware.cpp     \
     DisplayHardware/DisplayHardwareBase.cpp \
     DisplayHardware/HWComposer.cpp          \
-    DisplayHardware/VSyncBarrier.cpp        \
-    DisplayEventConnection.cpp              \
     GLExtensions.cpp                        \
     MessageQueue.cpp                        \
     SurfaceFlinger.cpp                      \
diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp
deleted file mode 100644
index 77ecbd2..0000000
--- a/services/surfaceflinger/DisplayEventConnection.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IDisplayEventConnection.h>
-#include <gui/BitTube.h>
-#include <gui/DisplayEventReceiver.h>
-
-#include <utils/Errors.h>
-
-#include "SurfaceFlinger.h"
-#include "DisplayEventConnection.h"
-#include "EventThread.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-DisplayEventConnection::DisplayEventConnection(
-        const sp<EventThread>& eventThread)
-    : mEventThread(eventThread), mChannel(new BitTube())
-{
-}
-
-DisplayEventConnection::~DisplayEventConnection() {
-    mEventThread->unregisterDisplayEventConnection(this);
-}
-
-void DisplayEventConnection::onFirstRef() {
-    // NOTE: mEventThread doesn't hold a strong reference on us
-    mEventThread->registerDisplayEventConnection(this);
-}
-
-sp<BitTube> DisplayEventConnection::getDataChannel() const {
-    return mChannel;
-}
-
-void DisplayEventConnection::setVsyncRate(uint32_t count) {
-    mEventThread->setVsyncRate(count, this);
-}
-
-void DisplayEventConnection::requestNextVsync() {
-    mEventThread->requestNextVsync(this);
-}
-
-status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event)
-{
-    ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event));
-    return size < 0 ? status_t(size) : status_t(NO_ERROR);
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/DisplayEventConnection.h b/services/surfaceflinger/DisplayEventConnection.h
deleted file mode 100644
index cc3ee36..0000000
--- a/services/surfaceflinger/DisplayEventConnection.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef ANDROID_SURFACE_FLINGER_DISPLAY_EVENT_CONNECTION_H
-#define ANDROID_SURFACE_FLINGER_DISPLAY_EVENT_CONNECTION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IDisplayEventConnection.h>
-
-#include <utils/Errors.h>
-#include <gui/DisplayEventReceiver.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class BitTube;
-class EventThread;
-
-// ---------------------------------------------------------------------------
-
-class DisplayEventConnection : public BnDisplayEventConnection {
-public:
-    DisplayEventConnection(const sp<EventThread>& flinger);
-
-    status_t postEvent(const DisplayEventReceiver::Event& event);
-
-private:
-    virtual ~DisplayEventConnection();
-    virtual void onFirstRef();
-    virtual sp<BitTube> getDataChannel() const;
-    virtual void setVsyncRate(uint32_t count);
-    virtual void requestNextVsync();    // asynchronous
-
-    sp<EventThread> const mEventThread;
-    sp<BitTube> const mChannel;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SURFACE_FLINGER_DISPLAY_EVENT_CONNECTION_H */
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index b7584b3..c46e630 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -35,6 +35,7 @@
 
 #include <hardware/gralloc.h>
 
+#include "DisplayHardwareBase.h"
 #include "GLExtensions.h"
 #include "HWComposer.h"
 #include "SurfaceFlinger.h"
@@ -160,7 +161,6 @@
     mDpiX = mNativeWindow->xdpi;
     mDpiY = mNativeWindow->ydpi;
     mRefreshRate = fbDev->fps;
-    mNextFakeVSync = 0;
 
     if (mDpiX == 0 || mDpiY == 0) {
         ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), "
@@ -353,12 +353,32 @@
 
 
     // initialize the H/W composer
-    mHwc = new HWComposer(mFlinger);
+    mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod);
     if (mHwc->initCheck() == NO_ERROR) {
         mHwc->setFrameBuffer(mDisplay, mSurface);
     }
 }
 
+void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {
+    Mutex::Autolock _l(mLock);
+    mVSyncHandler = handler;
+}
+
+void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) {
+    sp<VSyncHandler> handler;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        mLastHwVSync = timestamp;
+        if (mVSyncHandler != NULL) {
+            handler = mVSyncHandler.promote();
+        }
+    }
+
+    if (handler != NULL) {
+        handler->onVSyncReceived(dpy, timestamp);
+    }
+}
+
 HWComposer& DisplayHardware::getHwComposer() const {
     return *mHwc;
 }
@@ -393,22 +413,12 @@
     return mPageFlipCount;
 }
 
-// this needs to be thread safe
-nsecs_t DisplayHardware::waitForRefresh() const {
-    nsecs_t timestamp;
-    if (mVSync.wait(&timestamp) < 0) {
-        // vsync not supported!
-        usleep( getDelayToNextVSyncUs(&timestamp) );
-    }
-    mLastHwVSync = timestamp; // FIXME: Not thread safe
-    return timestamp;
-}
-
 nsecs_t DisplayHardware::getRefreshTimestamp() const {
     // this returns the last refresh timestamp.
     // if the last one is not available, we estimate it based on
     // the refresh period and whatever closest timestamp we have.
-    nsecs_t now = systemTime();
+    Mutex::Autolock _l(mLock);
+    nsecs_t now = systemTime(CLOCK_MONOTONIC);
     return now - ((now - mLastHwVSync) %  mRefreshPeriod);
 }
 
@@ -416,27 +426,6 @@
     return mRefreshPeriod;
 }
 
-int32_t DisplayHardware::getDelayToNextVSyncUs(nsecs_t* timestamp) const {
-    Mutex::Autolock _l(mFakeVSyncMutex);
-    const nsecs_t period = mRefreshPeriod;
-    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    nsecs_t next_vsync = mNextFakeVSync;
-    nsecs_t sleep = next_vsync - now;
-    if (sleep < 0) {
-        // we missed, find where the next vsync should be
-        sleep = (period - ((now - next_vsync) % period));
-        next_vsync = now + sleep;
-    }
-    mNextFakeVSync = next_vsync + period;
-    timestamp[0] = next_vsync;
-
-    // round to next microsecond
-    int32_t sleep_us = (sleep + 999LL) / 1000LL;
-
-    // guaranteed to be > 0
-    return sleep_us;
-}
-
 status_t DisplayHardware::compositionComplete() const {
     return mNativeWindow->compositionComplete();
 }
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 0a828b3..84a3eff 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -30,16 +30,25 @@
 #include "GLExtensions.h"
 
 #include "DisplayHardware/DisplayHardwareBase.h"
-#include "DisplayHardware/VSyncBarrier.h"
+#include "HWComposer.h"
 
 namespace android {
 
 class FramebufferNativeWindow;
-class HWComposer;
 
-class DisplayHardware : public DisplayHardwareBase
+class DisplayHardware :
+    public DisplayHardwareBase,
+    public HWComposer::EventHandler
 {
 public:
+
+    class VSyncHandler : virtual public RefBase {
+        friend class DisplayHardware;
+        virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0;
+    protected:
+        virtual ~VSyncHandler() {}
+    };
+
     enum {
         COPY_BITS_EXTENSION         = 0x00000008,
         BUFFER_PRESERVED            = 0x00010000,
@@ -52,7 +61,7 @@
             const sp<SurfaceFlinger>& flinger,
             uint32_t displayIndex);
 
-    ~DisplayHardware();
+    virtual ~DisplayHardware();
 
     void releaseScreen() const;
     void acquireScreen() const;
@@ -69,14 +78,15 @@
     int         getHeight() const;
     PixelFormat getFormat() const;
     uint32_t    getFlags() const;
-    void        makeCurrent() const;
     uint32_t    getMaxTextureSize() const;
     uint32_t    getMaxViewportDims() const;
-
-    // waits for the next vsync and returns the timestamp of when it happened
-    nsecs_t     waitForRefresh() const;
     nsecs_t     getRefreshPeriod() const;
     nsecs_t     getRefreshTimestamp() const;
+    void        makeCurrent() const;
+
+
+    void setVSyncHandler(const sp<VSyncHandler>& handler);
+
 
     uint32_t getPageFlipCount() const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
@@ -94,9 +104,9 @@
     inline Rect bounds() const { return getBounds(); }
 
 private:
+    virtual void onVSyncReceived(int dpy, nsecs_t timestamp);
     void init(uint32_t displayIndex) __attribute__((noinline));
     void fini() __attribute__((noinline));
-    int32_t getDelayToNextVSyncUs(nsecs_t* timestamp) const;
 
     sp<SurfaceFlinger> mFlinger;
     EGLDisplay      mDisplay;
@@ -114,15 +124,18 @@
     mutable uint32_t mPageFlipCount;
     GLint           mMaxViewportDims[2];
     GLint           mMaxTextureSize;
-    VSyncBarrier    mVSync;
 
-    mutable Mutex   mFakeVSyncMutex;
-    mutable nsecs_t mNextFakeVSync;
     nsecs_t         mRefreshPeriod;
     mutable nsecs_t mLastHwVSync;
 
+    // constant once set
     HWComposer*     mHwc;
 
+    mutable Mutex   mLock;
+
+    // protected by mLock
+    wp<VSyncHandler>    mVSyncHandler;
+
     sp<FramebufferNativeWindow> mNativeWindow;
 };
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f17bf43..e742d3e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -22,9 +22,11 @@
 
 #include <utils/Errors.h>
 #include <utils/String8.h>
+#include <utils/Thread.h>
 #include <utils/Vector.h>
 
 #include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
 
 #include <cutils/log.h>
 
@@ -37,11 +39,16 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+HWComposer::HWComposer(
+        const sp<SurfaceFlinger>& flinger,
+        EventHandler& handler,
+        nsecs_t refreshPeriod)
     : mFlinger(flinger),
       mModule(0), mHwc(0), mList(0), mCapacity(0),
       mNumOVLayers(0), mNumFBLayers(0),
-      mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
+      mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE),
+      mEventHandler(handler),
+      mRefreshPeriod(refreshPeriod)
 {
     int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
     ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
@@ -53,7 +60,14 @@
             if (mHwc->registerProcs) {
                 mCBContext.hwc = this;
                 mCBContext.procs.invalidate = &hook_invalidate;
+                mCBContext.procs.vsync = &hook_vsync;
                 mHwc->registerProcs(mHwc, &mCBContext.procs);
+                memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero));
+            }
+
+            if (mHwc->common.version < HWC_DEVICE_API_VERSION_0_3) {
+                // we don't have VSYNC support, we need to fake it
+                mVSyncThread = new VSyncThread(*this);
             }
         }
     }
@@ -61,6 +75,9 @@
 
 HWComposer::~HWComposer() {
     free(mList);
+    if (mVSyncThread != NULL) {
+        mVSyncThread->requestExitAndWait();
+    }
     if (mHwc) {
         hwc_close(mHwc);
     }
@@ -74,10 +91,32 @@
     reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
 }
 
+void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp) {
+    reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp);
+}
+
 void HWComposer::invalidate() {
     mFlinger->repaintEverything();
 }
 
+void HWComposer::vsync(int dpy, int64_t timestamp) {
+    mEventHandler.onVSyncReceived(dpy, timestamp);
+}
+
+status_t HWComposer::eventControl(int event, int enabled) {
+    status_t err = NO_ERROR;
+    if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+        err = mHwc->methods->eventControl(mHwc, event, enabled);
+    } else {
+        if (mVSyncThread != NULL) {
+            mVSyncThread->setEnabled(enabled);
+        } else {
+            err = BAD_VALUE;
+        }
+    }
+    return err;
+}
+
 void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
     mDpy = (hwc_display_t)dpy;
     mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index aa8ebe1..60a6367 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -27,6 +27,10 @@
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
+extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
+                           const struct timespec *request,
+                           struct timespec *remain);
+
 namespace android {
 // ---------------------------------------------------------------------------
 
@@ -37,8 +41,15 @@
 class HWComposer
 {
 public:
+    class EventHandler {
+        friend class HWComposer;
+        virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0;
+    protected:
+        virtual ~EventHandler() {}
+    };
 
-    HWComposer(const sp<SurfaceFlinger>& flinger);
+    HWComposer(const sp<SurfaceFlinger>& flinger,
+            EventHandler& handler, nsecs_t refreshPeriod);
     ~HWComposer();
 
     status_t initCheck() const;
@@ -46,7 +57,7 @@
     // tells the HAL what the framebuffer is
     void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
 
-    // create a work list for numLayers layer
+    // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
     status_t createWorkList(size_t numLayers);
 
     // Asks the HAL what it can do
@@ -61,23 +72,108 @@
     // release hardware resources
     status_t release() const;
 
+    // get the layer array created by createWorkList()
     size_t getNumLayers() const;
     hwc_layer_t* getLayers() const;
 
-    // updated in preapre()
+    // get number of layers of the given type as updated in prepare().
+    // type is HWC_OVERLAY or HWC_FRAMEBUFFER
     size_t getLayerCount(int type) const;
 
-    // for debugging
+    // Events handling ---------------------------------------------------------
+
+    enum {
+        EVENT_VSYNC = HWC_EVENT_VSYNC
+    };
+
+    status_t eventControl(int event, int enabled);
+
+    // this class is only used to fake the VSync event on systems that don't
+    // have it.
+    class VSyncThread : public Thread {
+        HWComposer& mHwc;
+        mutable Mutex mLock;
+        Condition mCondition;
+        bool mEnabled;
+        mutable nsecs_t mNextFakeVSync;
+        nsecs_t mRefreshPeriod;
+
+        virtual void onFirstRef() {
+            run("VSyncThread",
+                PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+        }
+
+        virtual bool threadLoop() {
+            { // scope for lock
+                Mutex::Autolock _l(mLock);
+                while (!mEnabled) {
+                    mCondition.wait(mLock);
+                }
+            }
+
+            const nsecs_t period = mRefreshPeriod;
+            const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+            nsecs_t next_vsync = mNextFakeVSync;
+            nsecs_t sleep = next_vsync - now;
+            if (sleep < 0) {
+                // we missed, find where the next vsync should be
+                sleep = (period - ((now - next_vsync) % period));
+                next_vsync = now + sleep;
+            }
+            mNextFakeVSync = next_vsync + period;
+
+            struct timespec spec;
+            spec.tv_sec  = next_vsync / 1000000000;
+            spec.tv_nsec = next_vsync % 1000000000;
+
+            // NOTE: EINTR can happen with clock_nanosleep(), in case of
+            // any error (including EINTR) we go through the condition's
+            // test -- this is always correct and easy.
+            if (::clock_nanosleep(CLOCK_MONOTONIC,
+                    TIMER_ABSTIME, &spec, NULL) == 0) {
+                mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
+            }
+            return true;
+        }
+
+    public:
+        VSyncThread(HWComposer& hwc) :
+            mHwc(hwc), mEnabled(false),
+            mNextFakeVSync(0),
+            mRefreshPeriod(hwc.mRefreshPeriod) {
+        }
+        void setEnabled(bool enabled) {
+            Mutex::Autolock _l(mLock);
+            mEnabled = enabled;
+            mCondition.signal();
+        }
+    };
+
+    friend class VSyncThread;
+
+    // for debugging ----------------------------------------------------------
     void dump(String8& out, char* scratch, size_t SIZE,
             const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
 
 private:
+
+    struct callbacks : public hwc_procs_t {
+        // these are here to facilitate the transition when adding
+        // new callbacks (an implementation can check for NULL before
+        // calling a new callback).
+        void (*zero[4])(void);
+    };
+
     struct cb_context {
-        hwc_procs_t procs;
+        callbacks procs;
         HWComposer* hwc;
     };
+
     static void hook_invalidate(struct hwc_procs* procs);
-    void invalidate();
+    static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
+
+    inline void invalidate();
+    inline void vsync(int dpy, int64_t timestamp);
 
     sp<SurfaceFlinger>      mFlinger;
     hw_module_t const*      mModule;
@@ -89,6 +185,9 @@
     hwc_display_t           mDpy;
     hwc_surface_t           mSur;
     cb_context              mCBContext;
+    EventHandler&           mEventHandler;
+    nsecs_t                 mRefreshPeriod;
+    sp<VSyncThread>         mVSyncThread;
 };
 
 
diff --git a/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp b/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp
deleted file mode 100644
index 187da20..0000000
--- a/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-
-#include "DisplayHardware/VSyncBarrier.h"
-
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC   _IOW('F', 0x20, __u32)
-#endif
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-VSyncBarrier::VSyncBarrier() : mFd(-EINVAL) {
-#if HAS_WAITFORVSYNC
-    mFd = open("/dev/graphics/fb0", O_RDWR);
-    if (mFd < 0) {
-        mFd = -errno;
-    }
-    // try to see if FBIO_WAITFORVSYNC is supported
-    uint32_t crt = 0;
-    int err = ioctl(mFd, FBIO_WAITFORVSYNC, &crt);
-    if (err < 0) {
-        close(mFd);
-        mFd = -EINVAL;
-    }
-#endif
-}
-
-VSyncBarrier::~VSyncBarrier() {
-    if (mFd >= 0) {
-        close(mFd);
-    }
-}
-
-status_t VSyncBarrier::initCheck() const {
-    return mFd < 0 ? mFd : status_t(NO_ERROR);
-}
-
-// this must be thread-safe
-status_t VSyncBarrier::wait(nsecs_t* timestamp) const {
-    if (mFd < 0) {
-        return mFd;
-    }
-
-    int err;
-    uint32_t crt = 0;
-    do {
-        err = ioctl(mFd, FBIO_WAITFORVSYNC, &crt);
-    } while (err<0 && errno==EINTR);
-    if (err < 0) {
-        return -errno;
-    }
-    // ideally this would come from the driver
-    timestamp[0] = systemTime();
-    return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VSyncBarrier.h b/services/surfaceflinger/DisplayHardware/VSyncBarrier.h
deleted file mode 100644
index 3c32950..0000000
--- a/services/surfaceflinger/DisplayHardware/VSyncBarrier.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef ANDROID_SURFACE_FLINGER_VSYNCBARRIER_H_
-#define ANDROID_SURFACE_FLINGER_VSYNCBARRIER_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class VSyncBarrier {
-    int mFd;
-public:
-    VSyncBarrier();
-    ~VSyncBarrier();
-    status_t initCheck() const;
-    status_t wait(nsecs_t* timestamp) const;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* ANDROID_SURFACE_FLINGER_VSYNCBARRIER_H_ */
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 3c045d7..b05b7c2 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -19,6 +19,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <gui/BitTube.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/DisplayEventReceiver.h>
 
@@ -26,7 +27,6 @@
 #include <utils/Trace.h>
 
 #include "DisplayHardware/DisplayHardware.h"
-#include "DisplayEventConnection.h"
 #include "EventThread.h"
 #include "SurfaceFlinger.h"
 
@@ -38,18 +38,20 @@
 
 EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
     : mFlinger(flinger),
-      mHw(flinger->graphicPlane(0).displayHardware()),
+      mHw(flinger->graphicPlane(0).editDisplayHardware()),
       mLastVSyncTimestamp(0),
+      mVSyncTimestamp(0),
       mDeliveredEvents(0)
 {
 }
 
 void EventThread::onFirstRef() {
+    mHw.setVSyncHandler(this);
     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 }
 
-sp<DisplayEventConnection> EventThread::createEventConnection() const {
-    return new DisplayEventConnection(const_cast<EventThread*>(this));
+sp<EventThread::Connection> EventThread::createEventConnection() const {
+    return new Connection(const_cast<EventThread*>(this));
 }
 
 nsecs_t EventThread::getLastVSyncTimestamp() const {
@@ -63,132 +65,135 @@
 }
 
 status_t EventThread::registerDisplayEventConnection(
-        const sp<DisplayEventConnection>& connection) {
+        const sp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
-    ConnectionInfo info;
-    mDisplayEventConnections.add(connection, info);
+    mDisplayEventConnections.add(connection);
     mCondition.signal();
     return NO_ERROR;
 }
 
 status_t EventThread::unregisterDisplayEventConnection(
-        const wp<DisplayEventConnection>& connection) {
+        const wp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
-    mDisplayEventConnections.removeItem(connection);
+    mDisplayEventConnections.remove(connection);
     mCondition.signal();
     return NO_ERROR;
 }
 
 void EventThread::removeDisplayEventConnection(
-        const wp<DisplayEventConnection>& connection) {
+        const wp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
-    mDisplayEventConnections.removeItem(connection);
-}
-
-EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked(
-        const wp<DisplayEventConnection>& connection) {
-    ssize_t index = mDisplayEventConnections.indexOfKey(connection);
-    if (index < 0) return NULL;
-    return &mDisplayEventConnections.editValueAt(index);
+    mDisplayEventConnections.remove(connection);
 }
 
 void EventThread::setVsyncRate(uint32_t count,
-        const wp<DisplayEventConnection>& connection) {
+        const sp<EventThread::Connection>& connection) {
     if (int32_t(count) >= 0) { // server must protect against bad params
         Mutex::Autolock _l(mLock);
-        ConnectionInfo* info = getConnectionInfoLocked(connection);
-        if (info) {
-            const int32_t new_count = (count == 0) ? -1 : count;
-            if (info->count != new_count) {
-                info->count = new_count;
-                mCondition.signal();
-            }
+        const int32_t new_count = (count == 0) ? -1 : count;
+        if (connection->count != new_count) {
+            connection->count = new_count;
+            mCondition.signal();
         }
     }
 }
 
 void EventThread::requestNextVsync(
-        const wp<DisplayEventConnection>& connection) {
+        const sp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
-    ConnectionInfo* info = getConnectionInfoLocked(connection);
-    if (info && info->count < 0) {
-        info->count = 0;
+    if (connection->count < 0) {
+        connection->count = 0;
         mCondition.signal();
     }
 }
 
+void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
+    Mutex::Autolock _l(mLock);
+    mVSyncTimestamp = timestamp;
+    mCondition.signal();
+}
+
 bool EventThread::threadLoop() {
 
     nsecs_t timestamp;
     DisplayEventReceiver::Event vsync;
-    Vector< wp<DisplayEventConnection> > displayEventConnections;
+    Vector< wp<EventThread::Connection> > displayEventConnections;
 
-    { // scope for the lock
+    do {
+
         Mutex::Autolock _l(mLock);
         do {
-            // see if we need to wait for the VSYNC at all
-            do {
-                bool waitForNextVsync = false;
-                size_t count = mDisplayEventConnections.size();
-                for (size_t i=0 ; i<count ; i++) {
-                    const ConnectionInfo& info(
-                            mDisplayEventConnections.valueAt(i));
-                    if (info.count >= 0) {
-                        // at least one continuous mode or active one-shot event
-                        waitForNextVsync = true;
-                        break;
-                    }
-                }
+            // check if we have received a VSYNC event
+            if (mVSyncTimestamp) {
+                // we have a VSYNC event pending
+                timestamp = mVSyncTimestamp;
+                mVSyncTimestamp = 0;
+                break;
+            }
 
-                if (waitForNextVsync)
-                    break;
-
-                mCondition.wait(mLock);
-            } while(true);
-
-            // at least one listener requested VSYNC
-            mLock.unlock();
-            timestamp = mHw.waitForRefresh();
-            ATRACE_INT("VSYNC", mDeliveredEvents&1);
-            mLock.lock();
-            mDeliveredEvents++;
-            mLastVSyncTimestamp = timestamp;
-
-            // now see if we still need to report this VSYNC event
-            const size_t count = mDisplayEventConnections.size();
+            // check if we should be waiting for VSYNC events
+            bool waitForNextVsync = false;
+            size_t count = mDisplayEventConnections.size();
             for (size_t i=0 ; i<count ; i++) {
-                bool reportVsync = false;
-                const ConnectionInfo& info(
-                        mDisplayEventConnections.valueAt(i));
-                if (info.count >= 1) {
-                    if (info.count==1 || (mDeliveredEvents % info.count) == 0) {
-                        // continuous event, and time to report it
-                        reportVsync = true;
-                    }
-                } else if (info.count >= -1) {
-                    ConnectionInfo& info(
-                            mDisplayEventConnections.editValueAt(i));
-                    if (info.count == 0) {
-                        // fired this time around
-                        reportVsync = true;
-                    }
-                    info.count--;
-                }
-                if (reportVsync) {
-                    displayEventConnections.add(mDisplayEventConnections.keyAt(i));
+                sp<Connection> connection =
+                        mDisplayEventConnections.itemAt(i).promote();
+                if (connection!=0 && connection->count >= 0) {
+                    // at least one continuous mode or active one-shot event
+                    waitForNextVsync = true;
+                    break;
                 }
             }
-        } while (!displayEventConnections.size());
 
-        // dispatch vsync events to listeners...
-        vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-        vsync.header.timestamp = timestamp;
-        vsync.vsync.count = mDeliveredEvents;
-    }
+            // enable or disable VSYNC events
+            mHw.getHwComposer().eventControl(
+                    HWComposer::EVENT_VSYNC, waitForNextVsync);
+
+            // wait for something to happen
+            mCondition.wait(mLock);
+        } while(true);
+
+        // process vsync event
+
+        ATRACE_INT("VSYNC", mDeliveredEvents&1);
+        mDeliveredEvents++;
+        mLastVSyncTimestamp = timestamp;
+
+        // now see if we still need to report this VSYNC event
+        const size_t count = mDisplayEventConnections.size();
+        for (size_t i=0 ; i<count ; i++) {
+            bool reportVsync = false;
+            sp<Connection> connection =
+                    mDisplayEventConnections.itemAt(i).promote();
+            if (connection == 0)
+                continue;
+
+            const int32_t count = connection->count;
+            if (count >= 1) {
+                if (count==1 || (mDeliveredEvents % count) == 0) {
+                    // continuous event, and time to report it
+                    reportVsync = true;
+                }
+            } else if (count >= -1) {
+                if (count == 0) {
+                    // fired this time around
+                    reportVsync = true;
+                }
+                connection->count--;
+            }
+            if (reportVsync) {
+                displayEventConnections.add(connection);
+            }
+        }
+    } while (!displayEventConnections.size());
+
+    // dispatch vsync events to listeners...
+    vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+    vsync.header.timestamp = timestamp;
+    vsync.vsync.count = mDeliveredEvents;
 
     const size_t count = displayEventConnections.size();
     for (size_t i=0 ; i<count ; i++) {
-        sp<DisplayEventConnection> conn(displayEventConnections[i].promote());
+        sp<Connection> conn(displayEventConnections[i].promote());
         // make sure the connection didn't die
         if (conn != NULL) {
             status_t err = conn->postEvent(vsync);
@@ -232,4 +237,39 @@
 
 // ---------------------------------------------------------------------------
 
+EventThread::Connection::Connection(
+        const sp<EventThread>& eventThread)
+    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
+{
+}
+
+EventThread::Connection::~Connection() {
+    mEventThread->unregisterDisplayEventConnection(this);
+}
+
+void EventThread::Connection::onFirstRef() {
+    // NOTE: mEventThread doesn't hold a strong reference on us
+    mEventThread->registerDisplayEventConnection(this);
+}
+
+sp<BitTube> EventThread::Connection::getDataChannel() const {
+    return mChannel;
+}
+
+void EventThread::Connection::setVsyncRate(uint32_t count) {
+    mEventThread->setVsyncRate(count, this);
+}
+
+void EventThread::Connection::requestNextVsync() {
+    mEventThread->requestNextVsync(this);
+}
+
+status_t EventThread::Connection::postEvent(
+        const DisplayEventReceiver::Event& event) {
+    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
+    return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+// ---------------------------------------------------------------------------
+
 }; // namespace android
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 3a3071e..3f9d452 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -20,13 +20,14 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
 
 #include <utils/Errors.h>
 #include <utils/threads.h>
-#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
 
-#include "DisplayEventConnection.h"
+#include "DisplayHardware/DisplayHardware.h"
 
 // ---------------------------------------------------------------------------
 
@@ -35,32 +36,43 @@
 // ---------------------------------------------------------------------------
 
 class SurfaceFlinger;
-class DisplayHardware;
-class DisplayEventConnection;
 
 // ---------------------------------------------------------------------------
 
-class EventThread : public Thread {
-    friend class DisplayEventConnection;
+class EventThread : public Thread, public DisplayHardware::VSyncHandler {
+    class Connection : public BnDisplayEventConnection {
+    public:
+        Connection(const sp<EventThread>& eventThread);
+        status_t postEvent(const DisplayEventReceiver::Event& event);
+
+        // count >= 1 : continuous event. count is the vsync rate
+        // count == 0 : one-shot event that has not fired
+        // count ==-1 : one-shot event that fired this round / disabled
+        // count ==-2 : one-shot event that fired the round before
+        int32_t count;
+
+    private:
+        virtual ~Connection();
+        virtual void onFirstRef();
+        virtual sp<BitTube> getDataChannel() const;
+        virtual void setVsyncRate(uint32_t count);
+        virtual void requestNextVsync();    // asynchronous
+        sp<EventThread> const mEventThread;
+        sp<BitTube> const mChannel;
+    };
 
 public:
+
     EventThread(const sp<SurfaceFlinger>& flinger);
 
-    sp<DisplayEventConnection> createEventConnection() const;
+    sp<Connection> createEventConnection() const;
+    status_t registerDisplayEventConnection(const sp<Connection>& connection);
+    status_t unregisterDisplayEventConnection(const wp<Connection>& connection);
 
-    status_t registerDisplayEventConnection(
-            const sp<DisplayEventConnection>& connection);
-
-    status_t unregisterDisplayEventConnection(
-            const wp<DisplayEventConnection>& connection);
-
-    void setVsyncRate(uint32_t count,
-            const wp<DisplayEventConnection>& connection);
-
-    void requestNextVsync(const wp<DisplayEventConnection>& connection);
+    void setVsyncRate(uint32_t count, const sp<Connection>& connection);
+    void requestNextVsync(const sp<Connection>& connection);
 
     nsecs_t getLastVSyncTimestamp() const;
-
     nsecs_t getVSyncPeriod() const;
 
     void dump(String8& result, char* buffer, size_t SIZE) const;
@@ -69,33 +81,21 @@
     virtual bool        threadLoop();
     virtual status_t    readyToRun();
     virtual void        onFirstRef();
+    virtual void onVSyncReceived(int, nsecs_t timestamp);
 
-    struct ConnectionInfo {
-        ConnectionInfo() : count(-1) { }
-
-        // count >= 1 : continuous event. count is the vsync rate
-        // count == 0 : one-shot event that has not fired
-        // count ==-1 : one-shot event that fired this round / disabled
-        // count ==-2 : one-shot event that fired the round before
-        int32_t count;
-    };
-
-    void removeDisplayEventConnection(
-            const wp<DisplayEventConnection>& connection);
-
-    ConnectionInfo* getConnectionInfoLocked(
-            const wp<DisplayEventConnection>& connection);
+    void removeDisplayEventConnection(const wp<Connection>& connection);
 
     // constants
     sp<SurfaceFlinger> mFlinger;
-    const DisplayHardware& mHw;
+    DisplayHardware& mHw;
 
     mutable Mutex mLock;
     mutable Condition mCondition;
 
     // protected by mLock
-    KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+    SortedVector< wp<Connection> > mDisplayEventConnections;
     nsecs_t mLastVSyncTimestamp;
+    nsecs_t mVSyncTimestamp;
 
     // main thread only
     size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0b68aa3..7023e0f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -50,7 +50,6 @@
 
 #include "clz.h"
 #include "DdmConnection.h"
-#include "DisplayEventConnection.h"
 #include "EventThread.h"
 #include "GLExtensions.h"
 #include "Layer.h"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b507877..6fa81db 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -270,8 +270,9 @@
     };
 
     struct State {
-        State() {
-            orientation = ISurfaceComposer::eOrientationDefault;
+        State()
+            : orientation(ISurfaceComposer::eOrientationDefault),
+              orientationFlags(0) {
         }
         LayerVector     layersSortedByZ;
         uint8_t         orientation;