Merge "Log when binder thread pool is starved" into nyc-dev
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 613b63b..df639cd 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -116,6 +116,7 @@
         "EGL_EXT_buffer_age "                   // strongly recommended with partial_update
         "EGL_KHR_create_context_no_error "
         "EGL_KHR_mutable_render_buffer "
+        "EGL_EXT_yuv_surface "
         ;
 
 // extensions not exposed to applications but used by the ANDROID system
diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
new file mode 100644
index 0000000..a6fae80
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
@@ -0,0 +1,197 @@
+Name
+
+    ANDROID_create_native_client_buffer
+
+Name Strings
+
+    EGL_ANDROID_create_native_client_buffer
+
+Contributors
+
+    Craig Donner
+
+Contact
+
+    Craig Donner, Google Inc. (cdonner 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, January 19, 2016
+
+Number
+
+    EGL Extension #XXX
+
+Dependencies
+
+    Requires EGL 1.2.
+
+    EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required.
+
+    This extension is written against the wording of the EGL 1.2
+    Specification as modified by EGL_KHR_image_base and
+    EGL_ANDROID_image_native_buffer.
+
+Overview
+
+    This extension allows creating an EGLClientBuffer backed by an Android
+    window buffer (struct ANativeWindowBuffer) which can be later used to
+    create an EGLImage.
+
+New Types
+
+    None.
+
+New Procedures and Functions
+
+EGLClientBuffer eglCreateNativeClientBufferANDROID(
+                        const EGLint *attrib_list)
+
+New Tokens
+
+    EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
+    EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
+    EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
+    EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
+
+Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
+
+    Add the following to section 2.5.1 "EGLImage Specification" (as modified by
+    the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications),
+    below the description of eglCreateImageKHR:
+
+   "The command
+
+        EGLClientBuffer eglCreateNativeClientBufferANDROID(
+                                const EGLint *attrib_list)
+
+    may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer
+    struct. EGL implementations must guarantee that the lifetime of the
+    returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound
+    to, following the lifetime semantics described below in section 2.5.2; the
+    EGLClientBuffer must be destroyed no earlier than when all of its associated
+    EGLImages are destroyed by eglDestroyImageKHR. <attrib_list> is a list of
+    attribute-value pairs which is used to specify the dimensions, format, and
+    usage of the underlying buffer structure. If <attrib_list> is non-NULL, the
+    last attribute specified in the list must be EGL_NONE.
+
+    Attribute names accepted in <attrib_list> are shown in Table aaa,
+    together with the <target> for which each attribute name is valid, and
+    the default value used for each attribute if it is not included in
+    <attrib_list>.
+
+      +---------------------------------+----------------------+---------------+
+      | Attribute                       | Description          | Default Value |
+      |                                 |                      |               |
+      +---------------------------------+----------------------+---------------+
+      | EGL_NONE                        | Marks the end of the | N/A           |
+      |                                 | attribute-value list |               |
+      | EGL_WIDTH                       | The width of the     | 0             |
+      |                                 | buffer data          |               |
+      | EGL_HEIGHT                      | The height of the    | 0             |
+      |                                 | buffer data          |               |
+      | EGL_RED_SIZE                    | The bits of Red in   | 0             |
+      |                                 | the color buffer     |               |
+      | EGL_GREEN_SIZE                  | The bits of Green in | 0             |
+      |                                 | the color buffer     |               |
+      | EGL_BLUE_SIZE                   | The bits of Blue in  | 0             |
+      |                                 | the color buffer     |               |
+      | EGL_ALPHA_SIZE                  | The bits of Alpha in | 0             |
+      |                                 | the color buffer     |               |
+      |                                 | buffer data          |               |
+      | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of    | 0             |
+      |                                 | the buffer data      |               |
+      +---------------------------------+----------------------+---------------+
+       Table aaa.  Legal attributes for eglCreateNativeClientBufferANDROID
+       <attrib_list> parameter.
+
+    The maximum width and height may depend on the amount of available memory,
+    which may also depend on the format and usage flags. The values of
+    EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and
+    correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE
+    is non-zero then the combination of all four sizes must correspond to a
+    valid pixel format for the implementation. The
+    EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of the following bits:
+
+        EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the
+        created buffer must have a hardware-protected path to external display
+        sink. If a hardware-protected path is not available, then either don't
+        composite only this buffer (preferred) to the external sink, or (less
+        desirable) do not route the entire composition to the external sink.
+
+        EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be
+        used to create a renderbuffer. This flag must not be set if
+        EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID is set.
+
+        EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to
+        create a texture. This flag must not be set if
+        EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID is set.
+
+    Errors
+
+        If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no
+        memory will be allocated, and one of the following errors will be
+        generated:
+
+       * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error
+         EGL_BAD_PARAMETER is generated.
+
+       * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE,
+         EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the
+         EGL implementation, the error EGL_BAD_PARAMETER is generated.
+
+       * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination
+         of gralloc usage flags for the EGL implementation, or is incompatible
+         with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is
+         Generated.
+
+       * If both the EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID and
+         EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID are set in the value of
+         EGL_NATIVE_BUFFER_USAGE_ANDROID, the error EGL_BAD_PARAMETER is
+         Generated."
+
+Issues
+
+    1. Should this extension define what combinations of formats and usage flags
+    EGL implementations are required to support?
+
+    RESOLVED: Partially.
+
+    The set of valid color combinations is implementation-specific and may
+    depend on additional EGL extensions, but generally RGB565 and RGBA888 should
+    be supported. The particular valid combinations for a given Android version
+    and implementation should be documented by that version.
+
+    2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the
+    client buffers created by this extension?
+
+    RESOLVED: No.
+
+    A destroy function would add several complications:
+
+        a) ANativeWindowBuffer is a reference counted object, may be used
+           outside of EGL.
+        b) The same buffer may back multiple EGLImages, though this usage may
+           result in undefined behavior.
+        c) The interactions between the lifetimes of EGLImages and their
+           EGLClientBuffers would become needlessly complex.
+
+    Because ANativeWindowBuffer is a reference counted object, implementations
+    of this extension should ensure the buffer has a lifetime at least as long
+    as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest
+    method is to increment the reference count of the buffer in
+    eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should
+    ensure proper lifetime semantics.
+
+Revision History
+
+#2 (Craig Donner, April 15, 2016)
+    - Set color formats and usage bits explicitly using additional attributes,
+    and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID.
+
+#1 (Craig Donner, January 19, 2016)
+    - Initial draft.
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 4cf9370..5ba387d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -15,7 +15,6 @@
  */
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
 
 // This is needed for stdint.h to define INT64_MAX in C++
 #define __STDC_LIMIT_MACROS
@@ -34,21 +33,12 @@
 #include "DispSync.h"
 #include "EventLog/EventLog.h"
 
-#include <algorithm>
-
-using std::max;
-using std::min;
-
 namespace android {
 
 // Setting this to true enables verbose tracing that can be used to debug
 // vsync event model or phase issues.
 static const bool kTraceDetailedInfo = false;
 
-// Setting this to true adds a zero-phase tracer for correlating with hardware
-// vsync events
-static const bool kEnableZeroPhaseTracer = false;
-
 // This is the threshold used to determine when hardware vsync events are
 // needed to re-synchronize the software vsync model with the hardware.  The
 // error metric used is the mean of the squared difference between each
@@ -59,36 +49,28 @@
 // vsync event.
 static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
 
-#undef LOG_TAG
-#define LOG_TAG "DispSyncThread"
 class DispSyncThread: public Thread {
 public:
 
-    DispSyncThread(const char* name):
-            mName(name),
+    DispSyncThread():
             mStop(false),
             mPeriod(0),
             mPhase(0),
             mReferenceTime(0),
-            mWakeupLatency(0),
-            mFrameNumber(0) {}
+            mWakeupLatency(0) {
+    }
 
     virtual ~DispSyncThread() {}
 
     void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         mPeriod = period;
         mPhase = phase;
         mReferenceTime = referenceTime;
-        ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
-                " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
-                ns2us(mPhase), ns2us(mReferenceTime));
         mCond.signal();
     }
 
     void stop() {
-        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         mStop = true;
         mCond.signal();
@@ -107,12 +89,6 @@
             { // Scope for lock
                 Mutex::Autolock lock(mMutex);
 
-                if (kTraceDetailedInfo) {
-                    ATRACE_INT64("DispSync:Frame", mFrameNumber);
-                }
-                ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber);
-                ++mFrameNumber;
-
                 if (mStop) {
                     return false;
                 }
@@ -133,9 +109,6 @@
                 bool isWakeup = false;
 
                 if (now < targetTime) {
-                    ALOGV("[%s] Waiting until %" PRId64, mName,
-                            ns2us(targetTime));
-                    if (kTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
                     err = mCond.waitRelative(mMutex, targetTime - now);
 
                     if (err == TIMED_OUT) {
@@ -149,15 +122,15 @@
 
                 now = systemTime(SYSTEM_TIME_MONOTONIC);
 
-                // Don't correct by more than 1.5 ms
-                static const nsecs_t kMaxWakeupLatency = us2ns(1500);
-
                 if (isWakeup) {
                     mWakeupLatency = ((mWakeupLatency * 63) +
                             (now - targetTime)) / 64;
-                    mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
+                    if (mWakeupLatency > 500000) {
+                        // Don't correct by more than 500 us
+                        mWakeupLatency = 500000;
+                    }
                     if (kTraceDetailedInfo) {
-                        ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
+                        ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);
                         ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
                     }
                 }
@@ -173,9 +146,7 @@
         return false;
     }
 
-    status_t addEventListener(const char* name, nsecs_t phase,
-            const sp<DispSync::Callback>& callback) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+    status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) {
         Mutex::Autolock lock(mMutex);
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -185,14 +156,15 @@
         }
 
         EventListener listener;
-        listener.mName = name;
         listener.mPhase = phase;
         listener.mCallback = callback;
 
         // We want to allow the firstmost future event to fire without
-        // allowing any past events to fire
-        listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
-                mWakeupLatency;
+        // allowing any past events to fire.  Because
+        // computeListenerNextEventTimeLocked filters out events within a half
+        // a period of the last event time, we need to initialize the last
+        // event time to a half a period in the past.
+        listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2;
 
         mEventListeners.push(listener);
 
@@ -202,7 +174,6 @@
     }
 
     status_t removeEventListener(const sp<DispSync::Callback>& callback) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -218,7 +189,6 @@
 
     // This method is only here to handle the kIgnorePresentFences case.
     bool hasAnyEventListeners() {
-        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         return !mEventListeners.empty();
     }
@@ -226,7 +196,6 @@
 private:
 
     struct EventListener {
-        const char* mName;
         nsecs_t mPhase;
         nsecs_t mLastEventTime;
         sp<DispSync::Callback> mCallback;
@@ -238,8 +207,6 @@
     };
 
     nsecs_t computeNextEventTimeLocked(nsecs_t now) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] computeNextEventTimeLocked", mName);
         nsecs_t nextEventTime = INT64_MAX;
         for (size_t i = 0; i < mEventListeners.size(); i++) {
             nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
@@ -250,28 +217,21 @@
             }
         }
 
-        ALOGV("[%s] nextEventTime = %" PRId64, mName, ns2us(nextEventTime));
         return nextEventTime;
     }
 
     Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
-                ns2us(now));
-
         Vector<CallbackInvocation> callbackInvocations;
-        nsecs_t onePeriodAgo = now - mPeriod;
+        nsecs_t ref = now - mPeriod;
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
             nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
-                    onePeriodAgo);
+                    ref);
 
             if (t < now) {
                 CallbackInvocation ci;
                 ci.mCallback = mEventListeners[i].mCallback;
                 ci.mEventTime = t;
-                ALOGV("[%s] [%s] Preparing to fire", mName,
-                        mEventListeners[i].mName);
                 callbackInvocations.push(ci);
                 mEventListeners.editItemAt(i).mLastEventTime = t;
             }
@@ -281,67 +241,29 @@
     }
 
     nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
-            nsecs_t baseTime) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
-                mName, listener.mName, ns2us(baseTime));
+            nsecs_t ref) {
 
-        nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
-        ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
-        if (baseTime < lastEventTime) {
-            baseTime = lastEventTime;
-            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
-                    ns2us(baseTime));
+        nsecs_t lastEventTime = listener.mLastEventTime;
+        if (ref < lastEventTime) {
+            ref = lastEventTime;
         }
 
-        baseTime -= mReferenceTime;
-        ALOGV("[%s] Relative baseTime = %" PRId64, mName, ns2us(baseTime));
-        nsecs_t phase = mPhase + listener.mPhase;
-        ALOGV("[%s] Phase = %" PRId64, mName, ns2us(phase));
-        baseTime -= phase;
-        ALOGV("[%s] baseTime - phase = %" PRId64, mName, ns2us(baseTime));
+        nsecs_t phase = mReferenceTime + mPhase + listener.mPhase;
+        nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase;
 
-        // If our previous time is before the reference (because the reference
-        // has since been updated), the division by mPeriod will truncate
-        // towards zero instead of computing the floor. Since in all cases
-        // before the reference we want the next time to be effectively now, we
-        // set baseTime to -mPeriod so that numPeriods will be -1.
-        // When we add 1 and the phase, we will be at the correct event time for
-        // this period.
-        if (baseTime < 0) {
-            ALOGV("[%s] Correcting negative baseTime", mName);
-            baseTime = -mPeriod;
-        }
-
-        nsecs_t numPeriods = baseTime / mPeriod;
-        ALOGV("[%s] numPeriods = %" PRId64, mName, numPeriods);
-        nsecs_t t = (numPeriods + 1) * mPeriod + phase;
-        ALOGV("[%s] t = %" PRId64, mName, ns2us(t));
-        t += mReferenceTime;
-        ALOGV("[%s] Absolute t = %" PRId64, mName, ns2us(t));
-
-        // Check that it's been slightly more than half a period since the last
-        // event so that we don't accidentally fall into double-rate vsyncs
-        if (t - listener.mLastEventTime < (3 * mPeriod / 5)) {
+        if (t - listener.mLastEventTime < mPeriod / 2) {
             t += mPeriod;
-            ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }
 
-        t -= mWakeupLatency;
-        ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t));
-
         return t;
     }
 
     void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
         for (size_t i = 0; i < callbacks.size(); i++) {
             callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
         }
     }
 
-    const char* const mName;
-
     bool mStop;
 
     nsecs_t mPeriod;
@@ -349,17 +271,12 @@
     nsecs_t mReferenceTime;
     nsecs_t mWakeupLatency;
 
-    int64_t mFrameNumber;
-
     Vector<EventListener> mEventListeners;
 
     Mutex mMutex;
     Condition mCond;
 };
 
-#undef LOG_TAG
-#define LOG_TAG "DispSync"
-
 class ZeroPhaseTracer : public DispSync::Callback {
 public:
     ZeroPhaseTracer() : mParity(false) {}
@@ -373,10 +290,9 @@
     bool mParity;
 };
 
-DispSync::DispSync(const char* name) :
-        mName(name),
+DispSync::DispSync() :
         mRefreshSkipCount(0),
-        mThread(new DispSyncThread(name)) {
+        mThread(new DispSyncThread()) {
 
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 
@@ -389,8 +305,8 @@
         // Even if we're just ignoring the fences, the zero-phase tracing is
         // not needed because any time there is an event registered we will
         // turn on the HW vsync events.
-        if (!kIgnorePresentFences && kEnableZeroPhaseTracer) {
-            addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
+        if (!kIgnorePresentFences) {
+            addEventListener(0, new ZeroPhaseTracer());
         }
     }
 }
@@ -435,7 +351,7 @@
 
 void DispSync::beginResync() {
     Mutex::Autolock lock(mMutex);
-    ALOGV("[%s] beginResync", mName);
+
     mModelUpdated = false;
     mNumResyncSamples = 0;
 }
@@ -443,17 +359,11 @@
 bool DispSync::addResyncSample(nsecs_t timestamp) {
     Mutex::Autolock lock(mMutex);
 
-    ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
-
     size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
     mResyncSamples[idx] = timestamp;
     if (mNumResyncSamples == 0) {
         mPhase = 0;
         mReferenceTime = timestamp;
-        ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
-                "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
-                ns2us(mReferenceTime));
-        mThread->updateModel(mPeriod, mPhase, mReferenceTime);
     }
 
     if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
@@ -477,21 +387,17 @@
         return mThread->hasAnyEventListeners();
     }
 
-    // Check against kErrorThreshold / 2 to add some hysteresis before having to
-    // resync again
-    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
-    ALOGV("[%s] addResyncSample returning %s", mName,
-            modelLocked ? "locked" : "unlocked");
-    return !modelLocked;
+    return !mModelUpdated || mError > kErrorThreshold;
 }
 
 void DispSync::endResync() {
 }
 
-status_t DispSync::addEventListener(const char* name, nsecs_t phase,
+status_t DispSync::addEventListener(nsecs_t phase,
         const sp<Callback>& callback) {
+
     Mutex::Autolock lock(mMutex);
-    return mThread->addEventListener(name, phase, callback);
+    return mThread->addEventListener(phase, callback);
 }
 
 void DispSync::setRefreshSkipCount(int count) {
@@ -521,32 +427,20 @@
 }
 
 void DispSync::updateModelLocked() {
-    ALOGV("[%s] updateModelLocked %zu", mName, mNumResyncSamples);
     if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
-        ALOGV("[%s] Computing...", mName);
         nsecs_t durationSum = 0;
-        nsecs_t minDuration = INT64_MAX;
-        nsecs_t maxDuration = 0;
         for (size_t i = 1; i < mNumResyncSamples; i++) {
             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
             size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
-            nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
-            durationSum += duration;
-            minDuration = min(minDuration, duration);
-            maxDuration = max(maxDuration, duration);
+            durationSum += mResyncSamples[idx] - mResyncSamples[prev];
         }
 
-        // Exclude the min and max from the average
-        durationSum -= minDuration + maxDuration;
-        mPeriod = durationSum / (mNumResyncSamples - 3);
-
-        ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
+        mPeriod = durationSum / (mNumResyncSamples - 1);
 
         double sampleAvgX = 0;
         double sampleAvgY = 0;
         double scale = 2.0 * M_PI / double(mPeriod);
-        // Intentionally skip the first sample
-        for (size_t i = 1; i < mNumResyncSamples; i++) {
+        for (size_t i = 0; i < mNumResyncSamples; i++) {
             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
             nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
             double samplePhase = double(sample % mPeriod) * scale;
@@ -554,21 +448,18 @@
             sampleAvgY += sin(samplePhase);
         }
 
-        sampleAvgX /= double(mNumResyncSamples - 1);
-        sampleAvgY /= double(mNumResyncSamples - 1);
+        sampleAvgX /= double(mNumResyncSamples);
+        sampleAvgY /= double(mNumResyncSamples);
 
         mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
 
-        ALOGV("[%s] mPhase = %" PRId64, mName, ns2us(mPhase));
-
-        if (mPhase < -(mPeriod / 2)) {
+        if (mPhase < 0) {
             mPhase += mPeriod;
-            ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
         }
 
         if (kTraceDetailedInfo) {
             ATRACE_INT64("DispSync:Period", mPeriod);
-            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
+            ATRACE_INT64("DispSync:Phase", mPhase);
         }
 
         // Artificially inflate the period if requested.
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 537c81b..a8524b9 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -26,8 +26,11 @@
 namespace android {
 
 // Ignore present (retire) fences if the device doesn't have support for the
-// sync framework
-#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK)
+// sync framework, or if all phase offsets are zero.  The latter is useful
+// because it allows us to avoid resync bursts on devices that don't need
+// phase-offset VSYNC events.
+#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \
+        (VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0)
 static const bool kIgnorePresentFences = true;
 #else
 static const bool kIgnorePresentFences = false;
@@ -61,7 +64,7 @@
         virtual void onDispSyncEvent(nsecs_t when) = 0;
     };
 
-    DispSync(const char* name);
+    DispSync();
     ~DispSync();
 
     // reset clears the resync samples and error value.
@@ -111,8 +114,7 @@
     // given phase offset from the hardware vsync events.  The callback is
     // called from a separate thread and it should return reasonably quickly
     // (i.e. within a few hundred microseconds).
-    status_t addEventListener(const char* name, nsecs_t phase,
-            const sp<Callback>& callback);
+    status_t addEventListener(nsecs_t phase, const sp<Callback>& callback);
 
     // removeEventListener removes an already-registered event callback.  Once
     // this method returns that callback will no longer be called by the
@@ -135,12 +137,10 @@
     void resetErrorLocked();
 
     enum { MAX_RESYNC_SAMPLES = 32 };
-    enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
+    enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
     enum { NUM_PRESENT_SAMPLES = 8 };
     enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
 
-    const char* const mName;
-
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
     nsecs_t mPeriod;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index d37fcb2..4afd8a2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -926,16 +926,19 @@
 protected:
     HWCTYPE* const mLayerList;
     HWCTYPE* mCurrentLayer;
-    Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { }
+    Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer),
+            mIndex(0) { }
     inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
     inline HWCTYPE* getLayer() { return mCurrentLayer; }
     virtual ~Iterable() { }
+    size_t mIndex;
 private:
     // returns a copy of ourselves
     virtual HWComposer::HWCLayer* dup() {
         return new CONCRETE( static_cast<const CONCRETE&>(*this) );
     }
     virtual status_t setLayer(size_t index) {
+        mIndex = index;
         mCurrentLayer = &mLayerList[index];
         return NO_ERROR;
     }
@@ -948,8 +951,12 @@
 class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
     struct hwc_composer_device_1* mHwc;
 public:
-    HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer)
-        : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc) { }
+    HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer,
+            Vector<Region>* visibleRegions,
+            Vector<Region>* surfaceDamageRegions)
+        : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc),
+          mVisibleRegions(visibleRegions),
+          mSurfaceDamageRegions(surfaceDamageRegions) {}
 
     virtual int32_t getCompositionType() const {
         return getLayer()->compositionType;
@@ -1037,9 +1044,10 @@
     }
     virtual void setVisibleRegionScreen(const Region& reg) {
         hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
-        mVisibleRegion = reg;
+        mVisibleRegions->editItemAt(mIndex) = reg;
         visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(
-                mVisibleRegion.getArray(&visibleRegion.numRects));
+                mVisibleRegions->itemAt(mIndex).getArray(
+                &visibleRegion.numRects));
     }
     virtual void setSurfaceDamage(const Region& reg) {
         if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
@@ -1053,9 +1061,10 @@
             surfaceDamage.rects = NULL;
             return;
         }
-        mSurfaceDamage = reg;
+        mSurfaceDamageRegions->editItemAt(mIndex) = reg;
         surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(
-                mSurfaceDamage.getArray(&surfaceDamage.numRects));
+                mSurfaceDamageRegions->itemAt(mIndex).getArray(
+                &surfaceDamage.numRects));
     }
     virtual void setSidebandStream(const sp<NativeHandle>& stream) {
         ALOG_ASSERT(stream->handle() != NULL);
@@ -1081,11 +1090,10 @@
     }
 
 protected:
-    // We need to hold "copies" of these for memory management purposes. The
-    // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
-    // internally doesn't copy the memory unless one of the copies is modified.
-    Region mVisibleRegion;
-    Region mSurfaceDamage;
+    // Pointers to the vectors of Region backing-memory held in DisplayData.
+    // Only the Region at mIndex corresponds to this Layer.
+    Vector<Region>* mVisibleRegions;
+    Vector<Region>* mSurfaceDamageRegions;
 };
 
 /*
@@ -1095,11 +1103,18 @@
     if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
         return LayerListIterator();
     }
-    const DisplayData& disp(mDisplayData[id]);
+    DisplayData& disp(mDisplayData[id]);
     if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
         return LayerListIterator();
     }
-    return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers), index);
+    if (disp.visibleRegions.size() < disp.list->numHwLayers) {
+        disp.visibleRegions.resize(disp.list->numHwLayers);
+    }
+    if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) {
+        disp.surfaceDamageRegions.resize(disp.list->numHwLayers);
+    }
+    return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers,
+            &disp.visibleRegions, &disp.surfaceDamageRegions), index);
 }
 
 /*
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index f5f7d77..c861817 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -346,6 +346,13 @@
 
         // protected by mEventControlLock
         int32_t events;
+
+        // We need to hold "copies" of these for memory management purposes. The
+        // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
+        // internally doesn't copy the memory unless one of the copies is
+        // modified.
+        Vector<Region> visibleRegions;
+        Vector<Region> surfaceDamageRegions;
     };
 
     sp<SurfaceFlinger>              mFlinger;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index dd88adb..f760200 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -44,9 +44,8 @@
     return;
 }
 
-EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger)
+EventThread::EventThread(const sp<VSyncSource>& src)
     : mVSyncSource(src),
-      mFlinger(flinger),
       mUseSoftwareVSync(false),
       mVsyncEnabled(false),
       mDebugVsyncEnabled(false),
@@ -127,9 +126,6 @@
 void EventThread::requestNextVsync(
         const sp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
-
-    mFlinger.resyncWithRateLimit();
-
     if (connection->count < 0) {
         connection->count = 0;
         mCondition.broadcast();
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 34654fa..9ba179a 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -77,7 +77,7 @@
 
 public:
 
-    EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger);
+    EventThread(const sp<VSyncSource>& src);
 
     sp<Connection> createEventConnection() const;
     status_t registerDisplayEventConnection(const sp<Connection>& connection);
@@ -116,7 +116,6 @@
     // constants
     sp<VSyncSource> mVSyncSource;
     PowerHAL mPowerHAL;
-    SurfaceFlinger& mFlinger;
 
     mutable Mutex mLock;
     mutable Condition mCondition;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a448639..1f85bee 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,7 +149,6 @@
         mLastTransactionTime(0),
         mBootFinished(false),
         mForceFullDamage(false),
-        mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mDaltonize(false),
@@ -332,12 +331,11 @@
 class DispSyncSource : public VSyncSource, private DispSync::Callback {
 public:
     DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
-        const char* name) :
-            mName(name),
+        const char* label) :
             mValue(0),
             mTraceVsync(traceVsync),
-            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
-            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
+            mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
+            mVsyncEventLabel(String8::format("VSYNC-%s", label)),
             mDispSync(dispSync),
             mCallbackMutex(),
             mCallback(),
@@ -350,7 +348,7 @@
     virtual void setVSyncEnabled(bool enable) {
         Mutex::Autolock lock(mVsyncMutex);
         if (enable) {
-            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
+            status_t err = mDispSync->addEventListener(mPhaseOffset,
                     static_cast<DispSync::Callback*>(this));
             if (err != NO_ERROR) {
                 ALOGE("error registering vsync callback: %s (%d)",
@@ -401,7 +399,7 @@
         }
 
         // Add a listener with the new offset
-        err = mDispSync->addEventListener(mName, mPhaseOffset,
+        err = mDispSync->addEventListener(mPhaseOffset,
                 static_cast<DispSync::Callback*>(this));
         if (err != NO_ERROR) {
             ALOGE("error registering vsync callback: %s (%d)",
@@ -427,8 +425,6 @@
         }
     }
 
-    const char* const mName;
-
     int mValue;
 
     const bool mTraceVsync;
@@ -459,10 +455,10 @@
         // start the EventThread
         sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                 vsyncPhaseOffsetNs, true, "app");
-        mEventThread = new EventThread(vsyncSrc, *this);
+        mEventThread = new EventThread(vsyncSrc);
         sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                 sfVsyncPhaseOffsetNs, true, "sf");
-        mSFEventThread = new EventThread(sfVsyncSrc, *this);
+        mSFEventThread = new EventThread(sfVsyncSrc);
         mEventQueue.setEventThread(mSFEventThread);
 
         // Get a RenderEngine for the given display / config (can't fail)
@@ -831,13 +827,6 @@
     }
 }
 
-void SurfaceFlinger::resyncWithRateLimit() {
-    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
-    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
-        resyncToHardwareVsync(true);
-    }
-}
-
 void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
     bool needsHwVsync = false;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 633e956..8c974d0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -409,11 +409,8 @@
      * VSync
      */
      void enableHardwareVsync();
-     void resyncToHardwareVsync(bool makeAvailable);
      void disableHardwareVsync(bool makeUnavailable);
-public:
-     void resyncWithRateLimit();
-private:
+     void resyncToHardwareVsync(bool makeAvailable);
 
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
@@ -525,7 +522,7 @@
     static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
     nsecs_t mFrameBuckets[NUM_BUCKETS];
     nsecs_t mTotalTime;
-    std::atomic<nsecs_t> mLastSwapTime;
+    nsecs_t mLastSwapTime;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index ea685e7..e9b3d99 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -148,7 +148,6 @@
         mLastTransactionTime(0),
         mBootFinished(false),
         mForceFullDamage(false),
-        mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mDaltonize(false),
@@ -330,12 +329,11 @@
 class DispSyncSource : public VSyncSource, private DispSync::Callback {
 public:
     DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
-        const char* name) :
-            mName(name),
+        const char* label) :
             mValue(0),
             mTraceVsync(traceVsync),
-            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
-            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
+            mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
+            mVsyncEventLabel(String8::format("VSYNC-%s", label)),
             mDispSync(dispSync),
             mCallbackMutex(),
             mCallback(),
@@ -348,7 +346,7 @@
     virtual void setVSyncEnabled(bool enable) {
         Mutex::Autolock lock(mVsyncMutex);
         if (enable) {
-            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
+            status_t err = mDispSync->addEventListener(mPhaseOffset,
                     static_cast<DispSync::Callback*>(this));
             if (err != NO_ERROR) {
                 ALOGE("error registering vsync callback: %s (%d)",
@@ -399,7 +397,7 @@
         }
 
         // Add a listener with the new offset
-        err = mDispSync->addEventListener(mName, mPhaseOffset,
+        err = mDispSync->addEventListener(mPhaseOffset,
                 static_cast<DispSync::Callback*>(this));
         if (err != NO_ERROR) {
             ALOGE("error registering vsync callback: %s (%d)",
@@ -425,8 +423,6 @@
         }
     }
 
-    const char* const mName;
-
     int mValue;
 
     const bool mTraceVsync;
@@ -456,10 +452,10 @@
     // start the EventThread
     sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
             vsyncPhaseOffsetNs, true, "app");
-    mEventThread = new EventThread(vsyncSrc, *this);
+    mEventThread = new EventThread(vsyncSrc);
     sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
             sfVsyncPhaseOffsetNs, true, "sf");
-    mSFEventThread = new EventThread(sfVsyncSrc, *this);
+    mSFEventThread = new EventThread(sfVsyncSrc);
     mEventQueue.setEventThread(mSFEventThread);
 
     // Initialize the H/W composer object.  There may or may not be an
@@ -851,13 +847,6 @@
     }
 }
 
-void SurfaceFlinger::resyncWithRateLimit() {
-    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
-    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
-        resyncToHardwareVsync(true);
-    }
-}
-
 void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
     bool needsHwVsync = false;