When adding event listener, use fuzzy window for last event time.

* We track the last callback time anyways, so there's no risk of
double-firing
* Without this we might risk missing a dispsync event. E.g., if vsyncs
are at T and T+11, and we're considering SF events with +1 offset, then
SF will fire at T+1. If we immediately deregister the SF listener, then
re-register later at T+13, we miss the event at T+12. But we would
probably be ok to fire at T+13 anyways.

Note that the old last event time inference did allow for this.
See change I742b30a8d28780a44592c4d3077f33d23cf65789...

listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;

...with +2/+6 offsets and 16.6ms period, then if SF registers at +7ms
after vsync, then last event time is inferred to be T-1.3ms, and with
reference time T-16.6ms, then the next computed event time ends up being
(floor(((T-1.3) - (T-16.6) - 6)/16.6) + 1)* 16.6 + 6 + T-16.6, which ends up
being T+6ms, which would immediately cause a wakeup. So this change
reintroduces that behavior while keeping the math right.

Bug: 128918820
Test: systrace
Change-Id: If45be5a579628045ba3d9bfe282bf8831fdb5275
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 5296da9..43fe32b 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -211,13 +211,14 @@
             const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
             const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
             const nsecs_t phaseCorrection = mPhase + listener.mPhase;
-            const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
-            if (predictedLastEventTime >= now) {
-                // Make sure that the last event time does not exceed the current time.
-                // If it would, then back the last event time by a period.
-                listener.mLastEventTime = predictedLastEventTime - mPeriod;
-            } else {
-                listener.mLastEventTime = predictedLastEventTime;
+            listener.mLastEventTime = predictedReference + phaseCorrection;
+            // If we're very close in time to the predicted last event time,
+            // then we need to back up the last event time so that we can
+            // attempt to fire an event immediately.
+            //
+            // Otherwise, keep the last event time that we predicted.
+            if (isShorterThanPeriod(now - listener.mLastEventTime)) {
+                listener.mLastEventTime -= mPeriod;
             }
         } else {
             listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -314,7 +315,7 @@
 
     // Sanity check that the duration is close enough in length to a period without
     // falling into double-rate vsyncs.
-    bool isCloseToPeriod(nsecs_t duration) {
+    bool isShorterThanPeriod(nsecs_t duration) {
         // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
         return duration < (3 * mPeriod) / 5;
     }
@@ -330,7 +331,7 @@
             nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
 
             if (t < now) {
-                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
+                if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
                     eventListener.mLastEventTime = t;
                     eventListener.mLastCallbackTime = now;
                     ALOGV("[%s] [%s] Skipping event due to model error", mName,
@@ -391,7 +392,7 @@
 
         // 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 (isCloseToPeriod(t - listener.mLastEventTime)) {
+        if (isShorterThanPeriod(t - listener.mLastEventTime)) {
             t += mPeriod;
             ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }