Merge "systrace: forbid FrameEventHistory from stealing the fence"
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 4f0b3bb..718e996 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -101,7 +101,7 @@
 
         mPhaseIntervalSetting = Phase::ZERO;
         mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
-            sync.addEventListener("SamplingThreadDispSyncListener", 0, this);
+            sync.addEventListener("SamplingThreadDispSyncListener", 0, this, mLastCallbackTime);
         });
         mVsyncListening = true;
     }
@@ -115,8 +115,9 @@
     void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ {
         if (!mVsyncListening) return;
 
-        mScheduler.withPrimaryDispSync(
-                [this](android::DispSync& sync) { sync.removeEventListener(this); });
+        mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
+            sync.removeEventListener(this, &mLastCallbackTime);
+        });
         mVsyncListening = false;
     }
 
@@ -147,6 +148,7 @@
     Scheduler& mScheduler;
     const std::chrono::nanoseconds mTargetSamplingOffset;
     mutable std::mutex mMutex;
+    nsecs_t mLastCallbackTime = 0;
     enum class Phase {
         ZERO,
         SAMPLING
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 1eccf9a..8cb48b1 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -76,9 +76,18 @@
     void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
         if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
-        mPeriod = period;
+
         mPhase = phase;
         mReferenceTime = referenceTime;
+        if (mPeriod != 0 && mPeriod != period && mReferenceTime != 0) {
+            // Inflate the reference time to be the most recent predicted
+            // vsync before the current time.
+            const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+            const nsecs_t baseTime = now - mReferenceTime;
+            const nsecs_t numOldPeriods = baseTime / mPeriod;
+            mReferenceTime = mReferenceTime + (numOldPeriods)*mPeriod;
+        }
+        mPeriod = period;
         if (mTraceDetailedInfo) {
             ATRACE_INT64("DispSync:Period", mPeriod);
             ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
@@ -176,7 +185,8 @@
         return false;
     }
 
-    status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
+    status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
+                              nsecs_t lastCallbackTime) {
         if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
@@ -192,8 +202,34 @@
         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. To do this extrapolate from
+        // mReferenceTime the most recent hardware vsync, and pin the
+        // last event time there.
+        const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        if (mPeriod != 0) {
+            const nsecs_t baseTime = now - mReferenceTime;
+            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;
+            }
+        } else {
+            listener.mLastEventTime = now + mPhase - mWakeupLatency;
+        }
+
+        if (lastCallbackTime <= 0) {
+            // If there is no prior callback time, try to infer one based on the
+            // logical last event time.
+            listener.mLastCallbackTime = listener.mLastEventTime + mWakeupLatency;
+        } else {
+            listener.mLastCallbackTime = lastCallbackTime;
+        }
 
         mEventListeners.push_back(listener);
 
@@ -202,13 +238,14 @@
         return NO_ERROR;
     }
 
-    status_t removeEventListener(DispSync::Callback* callback) {
+    status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback) {
         if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (std::vector<EventListener>::iterator it = mEventListeners.begin();
              it != mEventListeners.end(); ++it) {
             if (it->mCallback == callback) {
+                *outLastCallback = it->mLastCallbackTime;
                 mEventListeners.erase(it);
                 mCond.signal();
                 return NO_ERROR;
@@ -250,6 +287,7 @@
         const char* mName;
         nsecs_t mPhase;
         nsecs_t mLastEventTime;
+        nsecs_t mLastCallbackTime;
         DispSync::Callback* mCallback;
     };
 
@@ -274,6 +312,13 @@
         return nextEventTime;
     }
 
+    // Sanity check that the duration is close enough in length to a period without
+    // falling into double-rate vsyncs.
+    bool isCloseToPeriod(nsecs_t duration) {
+        // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
+        return duration < (3 * mPeriod) / 5;
+    }
+
     std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
         if (mTraceDetailedInfo) ATRACE_CALL();
         ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
@@ -285,12 +330,21 @@
             nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
 
             if (t < now) {
+                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
+                    eventListener.mLastEventTime = t;
+                    eventListener.mLastCallbackTime = now;
+                    ALOGV("[%s] [%s] Skipping event due to model error", mName,
+                          eventListener.mName);
+                    continue;
+                }
                 CallbackInvocation ci;
                 ci.mCallback = eventListener.mCallback;
                 ci.mEventTime = t;
-                ALOGV("[%s] [%s] Preparing to fire", mName, eventListener.mName);
+                ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName,
+                      t - eventListener.mLastEventTime);
                 callbackInvocations.push_back(ci);
                 eventListener.mLastEventTime = t;
+                eventListener.mLastCallbackTime = now;
             }
         }
 
@@ -337,7 +391,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 (t - listener.mLastEventTime < (3 * mPeriod / 5)) {
+        if (isCloseToPeriod(t - listener.mLastEventTime)) {
             t += mPeriod;
             ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }
@@ -418,7 +472,7 @@
 
     if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
         mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
-        addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
+        addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get(), 0);
     }
 }
 
@@ -429,8 +483,16 @@
 
 void DispSync::resetLocked() {
     mPhase = 0;
-    mReferenceTime = 0;
+    const size_t lastSampleIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES;
+    // Keep the most recent sample, when we resync to hardware we'll overwrite this
+    // with a more accurate signal
+    if (mResyncSamples[lastSampleIdx] != 0) {
+        mReferenceTime = mResyncSamples[lastSampleIdx];
+    }
     mModelUpdated = false;
+    for (size_t i = 0; i < MAX_RESYNC_SAMPLES; i++) {
+        mResyncSamples[i] = 0;
+    }
     mNumResyncSamples = 0;
     mFirstResyncSample = 0;
     mNumResyncSamplesSincePresent = 0;
@@ -504,9 +566,10 @@
 
 void DispSync::endResync() {}
 
-status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback) {
+status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback,
+                                    nsecs_t lastCallbackTime) {
     Mutex::Autolock lock(mMutex);
-    return mThread->addEventListener(name, phase, callback);
+    return mThread->addEventListener(name, phase, callback, lastCallbackTime);
 }
 
 void DispSync::setRefreshSkipCount(int count) {
@@ -516,9 +579,9 @@
     updateModelLocked();
 }
 
-status_t DispSync::removeEventListener(Callback* callback) {
+status_t DispSync::removeEventListener(Callback* callback, nsecs_t* outLastCallbackTime) {
     Mutex::Autolock lock(mMutex);
-    return mThread->removeEventListener(callback);
+    return mThread->removeEventListener(callback, outLastCallbackTime);
 }
 
 status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
@@ -530,7 +593,6 @@
     Mutex::Autolock lock(mMutex);
     mPeriod = period;
     mPhase = 0;
-    mReferenceTime = 0;
     mThread->updateModel(mPeriod, mPhase, mReferenceTime);
 }
 
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index f629697..de2b874 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -54,8 +54,9 @@
     virtual void setPeriod(nsecs_t period) = 0;
     virtual nsecs_t getPeriod() = 0;
     virtual void setRefreshSkipCount(int count) = 0;
-    virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
-    virtual status_t removeEventListener(Callback* callback) = 0;
+    virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
+                                      nsecs_t lastCallbackTime) = 0;
+    virtual status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) = 0;
     virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
     virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
     virtual void setIgnorePresentFences(bool ignore) = 0;
@@ -139,12 +140,21 @@
     // 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, Callback* callback) override;
+    // If the callback was previously registered, and the last clock time the
+    // callback was invoked was known to the caller (e.g. via removeEventListener),
+    // then the caller may pass that through to lastCallbackTime, so that
+    // callbacks do not accidentally double-fire if they are unregistered and
+    // reregistered in rapid succession.
+    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
+                              nsecs_t lastCallbackTime) override;
 
     // removeEventListener removes an already-registered event callback.  Once
     // this method returns that callback will no longer be called by the
     // DispSync object.
-    status_t removeEventListener(Callback* callback) override;
+    // outLastCallbackTime will contain the last time that the callback was invoked.
+    // If the caller wishes to reregister the same callback, they should pass the
+    // callback time back into lastCallbackTime (see addEventListener).
+    status_t removeEventListener(Callback* callback, nsecs_t* outLastCallbackTime) override;
 
     // changePhaseOffset changes the phase offset of an already-registered event callback. The
     // method will make sure that there is no skipping or double-firing on the listener per frame,
@@ -213,7 +223,7 @@
     // These member variables are the state used during the resynchronization
     // process to store information about the hardware vsync event times used
     // to compute the model.
-    nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES];
+    nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0};
     size_t mFirstResyncSample;
     size_t mNumResyncSamples;
     int mNumResyncSamplesSincePresent;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index d848c97..6e89648 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -40,13 +40,15 @@
     std::lock_guard lock(mVsyncMutex);
     if (enable) {
         status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
-                                                   static_cast<DispSync::Callback*>(this));
+                                                   static_cast<DispSync::Callback*>(this),
+                                                   mLastCallbackTime);
         if (err != NO_ERROR) {
             ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
         }
         // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
     } else {
-        status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this));
+        status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this),
+                                                      &mLastCallbackTime);
         if (err != NO_ERROR) {
             ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err);
         }
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 5e3d181..2858678 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -45,6 +45,7 @@
     const bool mTraceVsync;
     const std::string mVsyncOnLabel;
     const std::string mVsyncEventLabel;
+    nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
 
     DispSync* mDispSync;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee033a0..c37028e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1615,6 +1615,14 @@
                 mTimeStats->incrementMissedFrames();
             }
 
+            if (hwcFrameMissed) {
+                mHwcFrameMissedCount++;
+            }
+
+            if (gpuFrameMissed) {
+                mGpuFrameMissedCount++;
+            }
+
             if (mUseSmart90ForVideo) {
                 // This call is made each time SF wakes up and creates a new frame. It is part
                 // of video detection feature.
@@ -4663,7 +4671,9 @@
     dumpStaticScreenStats(result);
     result.append("\n");
 
-    StringAppendF(&result, "Missed frame count: %u\n\n", mFrameMissedCount.load());
+    StringAppendF(&result, "Total missed frame count: %u\n", mFrameMissedCount.load());
+    StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
+    StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
 
     dumpBufferingStats(result);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 42d79e1..776d39b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1018,6 +1018,8 @@
     std::shared_ptr<TimeStats> mTimeStats;
     bool mUseHwcVirtualDisplays = false;
     std::atomic<uint32_t> mFrameMissedCount{0};
+    std::atomic<uint32_t> mHwcFrameMissedCount{0};
+    std::atomic<uint32_t> mGpuFrameMissedCount{0};
 
     TransactionCompletedThread mTransactionCompletedThread;
 
diff --git a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp b/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp
new file mode 100644
index 0000000..4274254
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include <memory>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "AllowedDisplayConfigs.h"
+
+namespace android {
+namespace {
+
+class AllowedDisplayConfigsTest : public testing::Test {
+protected:
+    AllowedDisplayConfigsTest();
+    ~AllowedDisplayConfigsTest() override;
+
+    void buildAllowedConfigs();
+
+    const std::vector<int32_t> expectedConfigs = {0, 2, 7, 129};
+    constexpr static int32_t notAllowedConfig = 5;
+    std::unique_ptr<const AllowedDisplayConfigs> mAllowedConfigs;
+};
+
+AllowedDisplayConfigsTest::AllowedDisplayConfigsTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+AllowedDisplayConfigsTest::~AllowedDisplayConfigsTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+void AllowedDisplayConfigsTest::buildAllowedConfigs() {
+    AllowedDisplayConfigs::Builder builder;
+    for (int config : expectedConfigs) {
+        builder.addConfig(config);
+    }
+    mAllowedConfigs = builder.build();
+}
+
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+
+TEST_F(AllowedDisplayConfigsTest, checkConfigs) {
+    buildAllowedConfigs();
+
+    // Check that all expected configs are allowed
+    for (int config : expectedConfigs) {
+        EXPECT_TRUE(mAllowedConfigs->isConfigAllowed(config));
+    }
+
+    // Check that all the allowed configs are expected
+    std::vector<int32_t> allowedConfigVector;
+    mAllowedConfigs->getAllowedConfigs(&allowedConfigVector);
+    EXPECT_EQ(allowedConfigVector, expectedConfigs);
+
+    // Check that notAllowedConfig is indeed not allowed
+    EXPECT_TRUE(std::find(expectedConfigs.begin(), expectedConfigs.end(), notAllowedConfig) ==
+                expectedConfigs.end());
+    EXPECT_FALSE(mAllowedConfigs->isConfigAllowed(notAllowedConfig));
+}
+
+TEST_F(AllowedDisplayConfigsTest, getAllowedConfigsNullptr) {
+    buildAllowedConfigs();
+
+    // No other expectations rather than no crash
+    mAllowedConfigs->getAllowedConfigs(nullptr);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index b1d45f39..32bf66a 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -35,6 +35,7 @@
     srcs: [
         ":libsurfaceflinger_sources",
         "libsurfaceflinger_unittest_main.cpp",
+        "AllowedDisplayConfigsTest.cpp",
         "CompositionTest.cpp",
         "DisplayIdentificationTest.cpp",
         "DisplayTransactionTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 9213ae5..901cf15 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -36,8 +36,8 @@
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(getPeriod, nsecs_t());
     MOCK_METHOD1(setRefreshSkipCount, void(int));
-    MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
-    MOCK_METHOD1(removeEventListener, status_t(Callback*));
+    MOCK_METHOD4(addEventListener, status_t(const char*, nsecs_t, Callback*, nsecs_t));
+    MOCK_METHOD2(removeEventListener, status_t(Callback*, nsecs_t*));
     MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
     MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
     MOCK_METHOD1(setIgnorePresentFences, void(bool));