Merge "BufferQueue: add a setMaxAcquiredBufferCount check" into jb-mr1-dev
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 06cd3da..0f5c14a 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -93,6 +93,10 @@
 
     ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY = 0x0000,
 
+    ACONFIGURATION_LAYOUTDIR_ANY  = 0x00,
+    ACONFIGURATION_LAYOUTDIR_LTR  = 0x01,
+    ACONFIGURATION_LAYOUTDIR_RTL  = 0x02,
+
     ACONFIGURATION_MCC = 0x0001,
     ACONFIGURATION_MNC = 0x0002,
     ACONFIGURATION_LOCALE = 0x0004,
@@ -107,6 +111,7 @@
     ACONFIGURATION_SCREEN_LAYOUT = 0x0800,
     ACONFIGURATION_UI_MODE = 0x1000,
     ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000,
+    ACONFIGURATION_LAYOUTDIR = 0x4000,
 };
 
 /**
@@ -331,6 +336,17 @@
 void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
 
 /**
+ * Return the configuration's layout direction, or
+ * ACONFIGURATION_LAYOUTDIR_ANY if not set.
+ */
+int32_t AConfiguration_getLayoutDirection(AConfiguration* config);
+
+/**
+ * Set the configuration's layout direction.
+ */
+void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value);
+
+/**
  * Perform a diff between two configurations.  Returns a bit mask of
  * ACONFIGURATION_* constants, each bit set meaning that configuration element
  * is different between them.
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 691ba2f..3378d97 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -41,7 +41,6 @@
 
             int                 getCallingPid();
             int                 getCallingUid();
-            int                 getOrigCallingUid();
 
             void                setStrictModePolicy(int32_t policy);
             int32_t             getStrictModePolicy() const;
@@ -117,7 +116,6 @@
             status_t            mLastError;
             pid_t               mCallingPid;
             uid_t               mCallingUid;
-            uid_t               mOrigCallingUid;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
 };
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 877b17c..3ff95d2 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -285,9 +285,12 @@
             return err;
         }
     }
-    void* buffer = writeInplace(size);
-    return buffer == NULL ? NO_MEMORY :
-        val.flatten(buffer);
+    if (size) {
+        void* buffer = writeInplace(size);
+        return buffer == NULL ? NO_MEMORY :
+                val.flatten(buffer);
+    }
+    return NO_ERROR;
 }
 
 template<typename T>
@@ -303,9 +306,12 @@
         }
         size = s;
     }
-    void const* buffer = readInplace(size);
-    return buffer == NULL ? NO_MEMORY :
-        val.unflatten(buffer, size);
+    if (size) {
+        void const* buffer = readInplace(size);
+        return buffer == NULL ? NO_MEMORY :
+                val.unflatten(buffer, size);
+    }
+    return NO_ERROR;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/Region.h b/include/ui/Region.h
index f0819af..0049fde 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -28,6 +28,7 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+class SharedBuffer;
 class String8;
 
 // ---------------------------------------------------------------------------
@@ -41,10 +42,10 @@
                         
         Region& operator = (const Region& rhs);
 
-    inline  bool        isEmpty() const     { return mBounds.isEmpty();  }
-    inline  bool        isRect() const      { return mStorage.isEmpty(); }
+    inline  bool        isEmpty() const     { return getBounds().isEmpty(); }
+    inline  bool        isRect() const      { return mStorage.size() == 1; }
 
-    inline  Rect        getBounds() const   { return mBounds; }
+    inline  Rect        getBounds() const   { return mStorage[mStorage.size() - 1]; }
     inline  Rect        bounds() const      { return getBounds(); }
 
             // the region becomes its bounds
@@ -106,18 +107,24 @@
 
     
     /* various ways to access the rectangle list */
+
     
+    // STL-like iterators
     typedef Rect const* const_iterator;
-    
-            const_iterator begin() const;
-            const_iterator end() const;
+    const_iterator begin() const;
+    const_iterator end() const;
+
+    // returns an array of rect which has the same life-time has this
+    // Region object.
+    Rect const* getArray(size_t* count) const;
+
+    // returns a SharedBuffer as well as the number of rects.
+    // ownership is transfered to the caller.
+    // the caller must call SharedBuffer::release() to free the memory.
+    SharedBuffer const* getSharedBuffer(size_t* count) const;
 
     /* no user serviceable parts here... */
             
-            size_t      getRects(Vector<Rect>& rectList) const;
-            Rect const* getArray(size_t* count) const;
-
-            
             // add a rectangle to the internal list. This rectangle must
             // be sorted in Y and X and must not make the region invalid.
             void        addRectUnchecked(int l, int t, int r, int b);
@@ -156,8 +163,11 @@
 
     static bool validate(const Region& reg, const char* name);
     
-    Rect            mBounds;
-    Vector<Rect>    mStorage;
+    // mStorage is a (manually) sorted array of Rects describing the region
+    // with an extra Rect as the last element which is set to the
+    // bounds of the region. However, if the region is
+    // a simple Rect then mStorage contains only that rect.
+    Vector<Rect> mStorage;
 };
 
 
diff --git a/include/utils/SharedBuffer.h b/include/utils/SharedBuffer.h
index 24508b0..b670953 100644
--- a/include/utils/SharedBuffer.h
+++ b/include/utils/SharedBuffer.h
@@ -44,9 +44,6 @@
      * users.
      */
     static          ssize_t                 dealloc(const SharedBuffer* released);
-    
-    //! get the SharedBuffer from the data pointer
-    static  inline  const SharedBuffer*     sharedBuffer(const void* data);
 
     //! access the data for read
     inline          const void*             data() const;
@@ -94,9 +91,10 @@
 private:
         inline SharedBuffer() { }
         inline ~SharedBuffer() { }
-        inline SharedBuffer(const SharedBuffer&);
+        SharedBuffer(const SharedBuffer&);
+        SharedBuffer& operator = (const SharedBuffer&);
  
-        // 16 bytes. must be sized to preserve correct alingment.
+        // 16 bytes. must be sized to preserve correct alignment.
         mutable int32_t        mRefs;
                 size_t         mSize;
                 uint32_t       mReserved[2];
@@ -104,10 +102,6 @@
 
 // ---------------------------------------------------------------------------
 
-const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
-    return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
-}
-
 const void* SharedBuffer::data() const {
     return this + 1;
 }
@@ -120,19 +114,16 @@
     return mSize;
 }
 
-SharedBuffer* SharedBuffer::bufferFromData(void* data)
-{
-    return ((SharedBuffer*)data)-1;
+SharedBuffer* SharedBuffer::bufferFromData(void* data) {
+    return data ? static_cast<SharedBuffer *>(data)-1 : 0;
 }
     
-const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
-{
-    return ((const SharedBuffer*)data)-1;
+const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
+    return data ? static_cast<const SharedBuffer *>(data)-1 : 0;
 }
 
-size_t SharedBuffer::sizeFromData(const void* data)
-{
-    return (((const SharedBuffer*)data)-1)->mSize;
+size_t SharedBuffer::sizeFromData(const void* data) {
+    return data ? bufferFromData(data)->mSize : 0;
 }
 
 bool SharedBuffer::onlyOwner() const {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 7e416b9..6e83faa 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -371,11 +371,6 @@
     return mCallingUid;
 }
 
-int IPCThreadState::getOrigCallingUid()
-{
-    return mOrigCallingUid;
-}
-
 int64_t IPCThreadState::clearCallingIdentity()
 {
     int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
@@ -646,7 +641,6 @@
 {
     pthread_setspecific(gTLS, this);
     clearCaller();
-    mOrigCallingUid = mCallingUid;
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
 }
@@ -998,7 +992,6 @@
             
             mCallingPid = tr.sender_pid;
             mCallingUid = tr.sender_euid;
-            mOrigCallingUid = tr.sender_euid;
             
             int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
             if (gDisableBackgroundScheduling) {
@@ -1056,7 +1049,6 @@
             
             mCallingPid = origPid;
             mCallingUid = origUid;
-            mOrigCallingUid = origUid;
 
             IF_LOG_TRANSACTIONS() {
                 TextOutput::Bundle _b(alog);
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index a3d8b01..94fb1d5 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -48,22 +48,20 @@
 
 // ----------------------------------------------------------------------------
 
-Region::Region()
-    : mBounds(0,0)
-{
+Region::Region() {
+    mStorage.add(Rect(0,0));
 }
 
 Region::Region(const Region& rhs)
-    : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
+    : mStorage(rhs.mStorage)
 {
 #if VALIDATE_REGIONS
     validate(rhs, "rhs copy-ctor");
 #endif
 }
 
-Region::Region(const Rect& rhs)
-    : mBounds(rhs)
-{
+Region::Region(const Rect& rhs) {
+    mStorage.add(rhs);
 }
 
 Region::~Region()
@@ -76,40 +74,46 @@
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
-    mBounds = rhs.mBounds;
     mStorage = rhs.mStorage;
     return *this;
 }
 
 Region& Region::makeBoundsSelf()
 {
-    mStorage.clear();
+    if (mStorage.size() >= 2) {
+        const Rect bounds(getBounds());
+        mStorage.clear();
+        mStorage.add(bounds);
+    }
     return *this;
 }
 
 void Region::clear()
 {
-    mBounds.clear();
     mStorage.clear();
+    mStorage.add(Rect(0,0));
 }
 
 void Region::set(const Rect& r)
 {
-    mBounds = r;
     mStorage.clear();
+    mStorage.add(r);
 }
 
 void Region::set(uint32_t w, uint32_t h)
 {
-    mBounds = Rect(int(w), int(h));
     mStorage.clear();
+    mStorage.add(Rect(w,h));
 }
 
 // ----------------------------------------------------------------------------
 
 void Region::addRectUnchecked(int l, int t, int r, int b)
 {
-    mStorage.add(Rect(l,t,r,b));
+    Rect rect(l,t,r,b);
+    size_t where = mStorage.size() - 1;
+    mStorage.insertAt(rect, where, 1);
+
 #if VALIDATE_REGIONS
     validate(*this, "addRectUnchecked");
 #endif
@@ -252,7 +256,7 @@
 // to obtain an optimal region.
 class Region::rasterizer : public region_operator<Rect>::region_rasterizer 
 {
-    Rect& bounds;
+    Rect bounds;
     Vector<Rect>& storage;
     Rect* head;
     Rect* tail;
@@ -260,10 +264,7 @@
     Rect* cur;
 public:
     rasterizer(Region& reg) 
-        : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
-        bounds.top = bounds.bottom = 0;
-        bounds.left   = INT_MAX;
-        bounds.right  = INT_MIN;
+        : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
         storage.clear();
     }
 
@@ -281,6 +282,7 @@
             bounds.left  = 0;
             bounds.right = 0;
         }
+        storage.add(bounds);
     }
     
     virtual void operator()(const Rect& rect) {
@@ -372,6 +374,9 @@
                 reg.getBounds().left, reg.getBounds().top, 
                 reg.getBounds().right, reg.getBounds().bottom);
     }
+    if (reg.mStorage.size() == 2) {
+        ALOGE("mStorage size is 2, which is never valid");
+    }
     if (result == false) {
         reg.dump(name);
     }
@@ -529,11 +534,10 @@
 
 void Region::translate(Region& reg, int dx, int dy)
 {
-    if (!reg.isEmpty()) {
+    if ((dx || dy) && !reg.isEmpty()) {
 #if VALIDATE_REGIONS
         validate(reg, "translate (before)");
 #endif
-        reg.mBounds.translate(dx, dy);
         size_t count = reg.mStorage.size();
         Rect* rects = reg.mStorage.editArray();
         while (count) {
@@ -556,12 +560,11 @@
 // ----------------------------------------------------------------------------
 
 size_t Region::getSize() const {
-    return (mStorage.size() + 1) * sizeof(Rect);
+    return mStorage.size() * sizeof(Rect);
 }
 
 status_t Region::flatten(void* buffer) const {
     Rect* rects = reinterpret_cast<Rect*>(buffer);
-    *rects++ = mBounds;
     memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
     return NO_ERROR;
 }
@@ -570,8 +573,6 @@
     mStorage.clear();
     if (size >= sizeof(Rect)) {
         Rect const* rects = reinterpret_cast<Rect const*>(buffer);
-        mBounds = *rects++;
-        size -= sizeof(Rect);
         size_t count = size / sizeof(Rect);
         if (count > 0) {
             ssize_t err = mStorage.insertAt(0, count);
@@ -581,25 +582,21 @@
             memcpy(mStorage.editArray(), rects, count*sizeof(Rect));
         }
     }
+#if VALIDATE_REGIONS
+    validate(*this, "Region::unflatten");
+#endif
     return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
 
 Region::const_iterator Region::begin() const {
-    return isRect() ? &mBounds : mStorage.array();
+    return mStorage.array();
 }
 
 Region::const_iterator Region::end() const {
-    if (isRect()) {
-        if (isEmpty()) {
-            return &mBounds;
-        } else {
-            return &mBounds + 1;
-        }
-    } else {
-        return mStorage.array() + mStorage.size();
-    }
+    size_t numRects = isRect() ? 1 : mStorage.size() - 1;
+    return mStorage.array() + numRects;
 }
 
 Rect const* Region::getArray(size_t* count) const {
@@ -609,14 +606,16 @@
     return b;
 }
 
-size_t Region::getRects(Vector<Rect>& rectList) const
-{
-    rectList = mStorage;
-    if (rectList.isEmpty()) {
-        rectList.clear();
-        rectList.add(mBounds);
+SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
+    // We can get to the SharedBuffer of a Vector<Rect> because Rect has
+    // a trivial destructor.
+    SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
+    if (count) {
+        size_t numRects = isRect() ? 1 : mStorage.size() - 1;
+        count[0] = numRects;
     }
-    return rectList.size();
+    sb->acquire();
+    return sb;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 020ec15..8083bba 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -51,7 +51,7 @@
         mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
 {
     if (mStorage) {
-        SharedBuffer::sharedBuffer(mStorage)->acquire();
+        SharedBuffer::bufferFromData(mStorage)->acquire();
     }
 }
 
@@ -73,7 +73,7 @@
         if (rhs.mCount) {
             mStorage = rhs.mStorage;
             mCount = rhs.mCount;
-            SharedBuffer::sharedBuffer(mStorage)->acquire();
+            SharedBuffer::bufferFromData(mStorage)->acquire();
         } else {
             mStorage = 0;
             mCount = 0;
@@ -85,7 +85,7 @@
 void* VectorImpl::editArrayImpl()
 {
     if (mStorage) {
-        SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
+        SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage)->attemptEdit();
         if (sb == 0) {
             sb = SharedBuffer::alloc(capacity() * mItemSize);
             if (sb) {
@@ -101,7 +101,7 @@
 size_t VectorImpl::capacity() const
 {
     if (mStorage) {
-        return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
+        return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize;
     }
     return 0;
 }
@@ -346,7 +346,7 @@
 void VectorImpl::release_storage()
 {
     if (mStorage) {
-        const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
+        const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
         if (sb->release(SharedBuffer::eKeepStorage) == 1) {
             _do_destroy(mStorage, mCount);
             SharedBuffer::dealloc(sb);
@@ -372,7 +372,7 @@
             (mFlags & HAS_TRIVIAL_COPY) &&
             (mFlags & HAS_TRIVIAL_DTOR))
         {
-            const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+            const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
             SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
             mStorage = sb->data();
         } else {
@@ -424,7 +424,7 @@
             (mFlags & HAS_TRIVIAL_COPY) &&
             (mFlags & HAS_TRIVIAL_DTOR))
         {
-            const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+            const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
             SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
             mStorage = sb->data();
         } else {
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index dd0dc16..07002cc 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -52,3 +52,19 @@
 LOCAL_MODULE:= libsurfaceflinger
 
 include $(BUILD_SHARED_LIBRARY)
+
+###############################################################
+# uses jni which may not be available in PDK
+ifneq ($(wildcard libnativehelper/include),)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= \
+    DdmConnection.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libdl
+
+LOCAL_MODULE:= libsurfaceflinger_ddmconnection
+
+include $(BUILD_SHARED_LIBRARY)
+endif # libnativehelper
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
index 433b38e..ece965c 100644
--- a/services/surfaceflinger/DdmConnection.cpp
+++ b/services/surfaceflinger/DdmConnection.cpp
@@ -23,6 +23,10 @@
 
 namespace android {
 
+void DdmConnection_start(const char* name) {
+    ALOGI("DdmConnection_start");
+    DdmConnection::start(name);
+}
 
 void DdmConnection::start(const char* name) {
     JavaVM* vm;
diff --git a/services/surfaceflinger/DdmConnection.h b/services/surfaceflinger/DdmConnection.h
index 91b737c..b6b088b 100644
--- a/services/surfaceflinger/DdmConnection.h
+++ b/services/surfaceflinger/DdmConnection.h
@@ -19,6 +19,9 @@
 
 namespace android {
 
+// wrapper for dlsym
+extern "C" void DdmConnection_start(const char* name);
+
 class DdmConnection {
 public:
     static void start(const char* name);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 283d149..23290e3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -573,9 +573,12 @@
         reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
     }
     virtual void setVisibleRegionScreen(const Region& reg) {
-        getLayer()->visibleRegionScreen.rects =
-                reinterpret_cast<hwc_rect_t const *>(
-                        reg.getArray(&getLayer()->visibleRegionScreen.numRects));
+        // Region::getSharedBuffer creates a reference to the underlying
+        // SharedBuffer of this Region, this reference is freed
+        // in onDisplayed()
+        hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
+        SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
+        visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
     }
     virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
         if (buffer == 0 || buffer->handle == 0) {
@@ -586,6 +589,16 @@
             getLayer()->handle = buffer->handle;
         }
     }
+    virtual void onDisplayed() {
+        hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
+        SharedBuffer const* sb = SharedBuffer::bufferFromData(visibleRegion.rects);
+        if (sb) {
+            sb->release();
+            // not technically needed but safer
+            visibleRegion.numRects = 0;
+            visibleRegion.rects = NULL;
+        }
+    }
 };
 
 /*
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 8852ab6..a49a023 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -130,6 +130,7 @@
         virtual void setVisibleRegionScreen(const Region& reg) = 0;
         virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
         virtual void setAcquireFenceFd(int fenceFd) = 0;
+        virtual void onDisplayed() = 0;
     };
 
     /*
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index dcda67e..ade9f75 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -140,6 +140,8 @@
     return true;
 }
 
+// This will return when (1) a vsync event has been received, and (2) there was
+// at least one connection interested in receiving it when we started waiting.
 Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
         DisplayEventReceiver::Event* event)
 {
@@ -193,31 +195,54 @@
             // don't report it, and disable VSYNC events
             disableVSyncLocked();
         } else if (!timestamp && waitForVSync) {
+            // we have at least one client, so we want vsync enabled
+            // (TODO: this function is called right after we finish
+            // notifying clients of a vsync, so this call will be made
+            // at the vsync rate, e.g. 60fps.  If we can accurately
+            // track the current state we could avoid making this call
+            // so often.)
             enableVSyncLocked();
         }
 
-        // note: !timestamp implies signalConnections.isEmpty()
+        // note: !timestamp implies signalConnections.isEmpty(), because we
+        // don't populate signalConnections if there's no vsync pending
         if (!timestamp) {
             // wait for something to happen
-            if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) {
-                // h/w vsync cannot be used (screen is off), so we use
-                // a  timeout instead. it doesn't matter how imprecise this
-                // is, we just need to make sure to serve the clients
-                if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
+            if (waitForVSync) {
+                // This is where we spend most of our time, waiting
+                // for vsync events and new client registrations.
+                //
+                // If the screen is off, we can't use h/w vsync, so we
+                // use a 16ms timeout instead.  It doesn't need to be
+                // precise, we just need to keep feeding our clients.
+                //
+                // We don't want to stall if there's a driver bug, so we
+                // use a (long) timeout when waiting for h/w vsync, and
+                // generate fake events when necessary.
+                bool softwareSync = mUseSoftwareVSync;
+                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
+                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
+                    if (!softwareSync) {
+                        ALOGW("Timed out waiting for hw vsync; faking it");
+                    }
                     mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                     mVSyncCount++;
                 }
             } else {
-                // This is where we spend most of our time, waiting
-                // for a vsync events and registered clients
+                // Nobody is interested in vsync, so we just want to sleep.
+                // h/w vsync should be disabled, so this will wait until we
+                // get a new connection, or an existing connection becomes
+                // interested in receiving vsync again.
                 mCondition.wait(mLock);
             }
         }
     } while (signalConnections.isEmpty());
 
     // here we're guaranteed to have a timestamp and some connections to signal
+    // (The connections might have dropped out of mDisplayEventConnections
+    // while we were asleep, but we'll still have strong references to them.)
 
-    // dispatch vsync events to listeners...
+    // fill in vsync event info
     event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
     event->header.timestamp = timestamp;
     event->vsync.count = vsyncCount;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ea1bc54..f928805 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -72,6 +72,7 @@
 
 void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface* layer) {
+    LayerBaseClient::onLayerDisplayed(hw, layer);
     if (layer) {
         mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
     }
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index a2513a2..87dc572 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -288,12 +288,16 @@
     // scaling is already applied in transformedBounds
     layer.setFrame(transformedBounds);
     layer.setCrop(transformedBounds.getBounds());
-    layer.setVisibleRegionScreen(tr.transform(visibleRegion));
 }
 
 void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer) {
     layer.setBuffer(0);
+    // we have to set the visible region on every frame because
+    // we currently free it during onLayerDisplayed(), which is called
+    // after HWComposer::commit() -- every frame.
+    const Transform& tr = hw->getTransform();
+    layer.setVisibleRegionScreen(tr.transform(visibleRegion));
 }
 
 void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw,
@@ -301,6 +305,13 @@
     layer.setAcquireFenceFd(-1);
 }
 
+void LayerBase::onLayerDisplayed(const sp<const DisplayDevice>& hw,
+        HWComposer::HWCLayerInterface* layer) {
+    if (layer) {
+        layer->onDisplayed();
+    }
+}
+
 void LayerBase::setFiltering(bool filtering)
 {
     mFiltering = filtering;
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c18f397..4651517 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -218,7 +218,7 @@
     /** called after page-flip
      */
     virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
-            HWComposer::HWCLayerInterface* layer) { }
+            HWComposer::HWCLayerInterface* layer);
 
     /** called before composition.
      * returns true if the layer has pending updates.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7124b0c..ee653f3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <errno.h>
 #include <math.h>
+#include <dlfcn.h>
 
 #include <EGL/egl.h>
 #include <GLES/gl.h>
@@ -108,9 +109,11 @@
     property_get("debug.sf.ddms", value, "0");
     mDebugDDMS = atoi(value);
     if (mDebugDDMS) {
-        DdmConnection::start(getServiceName());
+        if (!startDdmConnection()) {
+            // start failed, and DDMS debugging not enabled
+            mDebugDDMS = 0;
+        }
     }
-
     ALOGI_IF(mDebugRegion, "showupdates enabled");
     ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
 }
@@ -2061,6 +2064,24 @@
     hw->dump(result);
 }
 
+bool SurfaceFlinger::startDdmConnection()
+{
+    void* libddmconnection_dso =
+            dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
+    if (!libddmconnection_dso) {
+        return false;
+    }
+    void (*DdmConnection_start)(const char* name);
+    DdmConnection_start =
+            (typeof DdmConnection_start)dlsym(libddmconnection_dso, "DdmConnection_start");
+    if (!DdmConnection_start) {
+        dlclose(libddmconnection_dso);
+        return false;
+    }
+    (*DdmConnection_start)(getServiceName());
+    return true;
+}
+
 status_t SurfaceFlinger::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 50fef00..9db6b2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -388,6 +388,7 @@
     void clearStatsLocked(const Vector<String16>& args, size_t& index,
         String8& result, char* buffer, size_t SIZE) const;
     void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const;
+    bool startDdmConnection();
 
     /* ------------------------------------------------------------------------
      * Attributes