Surface unit tests for getFrameTimestamps.

Verifies the following:

1) The timestamps and fences aren't transferred if the
   feature isn't explicitly enabled.
2) Attempts to get the timestamps will fail if not enabled.
3) Timestamps are transferred if enabled.
4) The support for Present/Retire timestamps are properly
   queried from the ISurfaceComposer.
5) Timestamps correspond to the correct frame.
6) The consumer doesn't send the acquire fence back to the
   producer and a sync call isn't made to try and get it
   from the producer.
7) A sync call isn't made when no timestamps are requested.
8) If the consumer sent the producer fences, the consumer
   can get the timestamps without a sync call.
9) If there was no GL composite performed, a sync call
   isn't made to get a non-existant fence/time.
10) When asking for the retire or release time of the most
   recent frame, a sync call isn't made.
11) Requests for unsupported timestamps return an error and
   do not result in a sync call.

Test: Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*

Change-Id: I6f728af0d4a0f431c9e47131da64584a589559e7
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 8a3fa39..7d62706 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -116,13 +116,22 @@
 public:
     ~ProducerFrameEventHistory() override;
 
-    void updateAcquireFence(
+    // virtual for testing.
+    virtual void updateAcquireFence(
             uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
     void applyDelta(const FrameEventHistoryDelta& delta);
 
     void updateSignalTimes();
 
-private:
+protected:
+    void applyFenceDelta(FenceTimeline* timeline,
+            std::shared_ptr<FenceTime>* dst,
+            const FenceTime::Snapshot& src) const;
+
+    // virtual for testing.
+    virtual std::shared_ptr<FenceTime> createFenceTime(
+            const sp<Fence>& fence) const;
+
     size_t mAcquireOffset{0};
 
     // The consumer updates it's timelines in Layer and SurfaceFlinger since
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 451bd68..43b8d96 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -33,6 +33,8 @@
 
 namespace android {
 
+class ISurfaceComposer;
+
 /*
  * An implementation of ANativeWindow that feeds graphics buffers into a
  * BufferQueue.
@@ -66,7 +68,8 @@
      * the controlledByApp flag indicates that this Surface (producer) is
      * controlled by the application. This flag is used at connect time.
      */
-    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
+    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
+            bool controlledByApp = false);
 
     /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
      * Surface was created with. Usually it's an error to use the
@@ -152,6 +155,9 @@
 protected:
     virtual ~Surface();
 
+    // Virtual for testing.
+    virtual sp<ISurfaceComposer> composerService() const;
+
 private:
     // can't be copied
     Surface& operator = (const Surface& rhs);
@@ -245,7 +251,6 @@
     enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
 
-private:
     void querySupportedTimestampsLocked() const;
 
     void freeAllBuffers();
@@ -399,7 +404,7 @@
 
     // A cached copy of the FrameEventHistory maintained by the consumer.
     bool mEnableFrameTimestamps = false;
-    ProducerFrameEventHistory mFrameEventHistory;
+    std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
 };
 
 namespace view {
diff --git a/include/ui/FenceTime.h b/include/ui/FenceTime.h
index 27cc720..871fcf2 100644
--- a/include/ui/FenceTime.h
+++ b/include/ui/FenceTime.h
@@ -24,13 +24,17 @@
 #include <atomic>
 #include <mutex>
 #include <queue>
+#include <unordered_map>
 
 namespace android {
 
+class FenceToFenceTimeMap;
+
 // A wrapper around fence that only implements isValid and getSignalTime.
 // It automatically closes the fence in a thread-safe manner once the signal
 // time is known.
 class FenceTime {
+friend class FenceToFenceTimeMap;
 public:
     // An atomic snapshot of the FenceTime that is flattenable.
     //
@@ -107,15 +111,22 @@
     // Returns a snapshot of the FenceTime in its current state.
     Snapshot getSnapshot() const;
 
+    void signalForTest(nsecs_t signalTime);
+
     // Override new and delete since this needs 8-byte alignment, which
     // is not guaranteed on x86.
     static void* operator new(size_t nbytes) noexcept;
     static void operator delete(void *p);
 
 private:
+    // For tests only. If forceValidForTest is true, then getSignalTime will
+    // never return SIGNAL_TIME_INVALID and isValid will always return true.
+    FenceTime(const sp<Fence>& fence, bool forceValidForTest);
+
     enum class State {
         VALID,
         INVALID,
+        FORCED_VALID_FOR_TEST,
     };
 
     const State mState{State::INVALID};
@@ -156,6 +167,42 @@
     std::queue<std::weak_ptr<FenceTime>> mQueue;
 };
 
+// Used by test code to create or get FenceTimes for a given Fence.
+//
+// By design, Fences cannot be signaled from user space. However, this class
+// allows test code to set the apparent signalTime of a Fence and
+// have it be visible to all FenceTimes. Release code should not use
+// FenceToFenceTimeMap.
+//
+// FenceToFenceTimeMap keeps a weak reference to the FenceTime and automatically
+// garbage collects entries every time a new FenceTime is created to avoid
+// leaks. This prevents us from having to make the Fence destructor
+// automatically notify that the underlying fence has been destroyed, which
+// would affect release code paths. Garbage collecting so often is inefficient,
+// but acceptable for testing.
+//
+// Since FenceTimes maintain a strong reference to underlying Fences, there
+// should not be any aliasing issues where a new Fence happens to have the same
+// address as a previous Fence; the previous entry will be garbage collected
+// before the new one is added.
+class FenceToFenceTimeMap {
+public:
+    // Create a new FenceTime with that wraps the provided Fence.
+    std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence);
+
+    // Signals all FenceTimes created through this class that are wrappers
+    // around |fence|.
+    void signalAllForTest(const sp<Fence>& fence, nsecs_t signalTime);
+
+private:
+    // Cleans up the entries that no longer have a strong reference.
+    void garbageCollectLocked();
+
+    mutable std::mutex mMutex;
+    std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap;
+};
+
+
 }; // namespace android
 
 #endif // ANDROID_FENCE_TIME_H
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index c9b8948..46ca974 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -241,33 +241,6 @@
     }
 }
 
-static void applyFenceDelta(FenceTimeline* timeline,
-        std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) {
-    if (CC_UNLIKELY(dst == nullptr)) {
-        ALOGE("applyFenceDelta: dst is null.");
-        return;
-    }
-
-    switch (src.state) {
-        case FenceTime::Snapshot::State::EMPTY:
-            return;
-        case FenceTime::Snapshot::State::FENCE:
-            if (CC_UNLIKELY((*dst)->isValid())) {
-                ALOGE("applyFenceDelta: Unexpected fence.");
-            }
-            *dst = std::make_shared<FenceTime>(src.fence);
-            timeline->push(*dst);
-            return;
-        case FenceTime::Snapshot::State::SIGNAL_TIME:
-            if ((*dst)->isValid()) {
-                (*dst)->applyTrustedSnapshot(src);
-            } else {
-                *dst = std::make_shared<FenceTime>(src.signalTime);
-            }
-            return;
-    }
-}
-
 void ProducerFrameEventHistory::applyDelta(
         const FrameEventHistoryDelta& delta) {
     for (auto& d : delta.mDeltas) {
@@ -320,6 +293,38 @@
     mReleaseTimeline.updateSignalTimes();
 }
 
+void ProducerFrameEventHistory::applyFenceDelta(FenceTimeline* timeline,
+        std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) const {
+    if (CC_UNLIKELY(dst == nullptr)) {
+        ALOGE("applyFenceDelta: dst is null.");
+        return;
+    }
+
+    switch (src.state) {
+        case FenceTime::Snapshot::State::EMPTY:
+            return;
+        case FenceTime::Snapshot::State::FENCE:
+            if (CC_UNLIKELY((*dst)->isValid())) {
+                ALOGE("applyFenceDelta: Unexpected fence.");
+            }
+            *dst = createFenceTime(src.fence);
+            timeline->push(*dst);
+            return;
+        case FenceTime::Snapshot::State::SIGNAL_TIME:
+            if ((*dst)->isValid()) {
+                (*dst)->applyTrustedSnapshot(src);
+            } else {
+                *dst = std::make_shared<FenceTime>(src.signalTime);
+            }
+            return;
+    }
+}
+
+std::shared_ptr<FenceTime> ProducerFrameEventHistory::createFenceTime(
+        const sp<Fence>& fence) const {
+    return std::make_shared<FenceTime>(fence);
+}
+
 
 // ============================================================================
 // ConsumerFrameEventHistory
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a172c32..ead8ecb 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -52,7 +52,8 @@
       mQueriedSupportedTimestamps(false),
       mFrameTimestampsSupportsPresent(false),
       mFrameTimestampsSupportsRetire(false),
-      mEnableFrameTimestamps(false)
+      mEnableFrameTimestamps(false),
+      mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
 {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
@@ -96,6 +97,10 @@
     }
 }
 
+sp<ISurfaceComposer> Surface::composerService() const {
+    return ComposerService::getComposerService();
+}
+
 sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
     return mGraphicBufferProducer;
 }
@@ -203,7 +208,7 @@
         return BAD_VALUE;
     }
 
-    FrameEvents* events = mFrameEventHistory.getFrame(frameNumber);
+    FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
     if (events == nullptr) {
         // If the entry isn't available in the producer, it's definitely not
         // available in the consumer.
@@ -216,8 +221,8 @@
             outDisplayPresentTime, outDisplayRetireTime, outReleaseTime)) {
         FrameEventHistoryDelta delta;
         mGraphicBufferProducer->getFrameTimestamps(&delta);
-        mFrameEventHistory.applyDelta(delta);
-        events = mFrameEventHistory.getFrame(frameNumber);
+        mFrameEventHistory->applyDelta(delta);
+        events = mFrameEventHistory->getFrame(frameNumber);
     }
 
     if (events == nullptr) {
@@ -396,7 +401,7 @@
     }
 
     if (enableFrameTimestamps) {
-         mFrameEventHistory.applyDelta(frameTimestamps);
+         mFrameEventHistory->applyDelta(frameTimestamps);
     }
 
     if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
@@ -590,16 +595,16 @@
     }
 
     if (mEnableFrameTimestamps) {
-        mFrameEventHistory.applyDelta(output.frameTimestamps);
+        mFrameEventHistory->applyDelta(output.frameTimestamps);
         // Update timestamps with the local acquire fence.
         // The consumer doesn't send it back to prevent us from having two
         // file descriptors of the same fence.
-        mFrameEventHistory.updateAcquireFence(mNextFrameNumber,
+        mFrameEventHistory->updateAcquireFence(mNextFrameNumber,
                 std::make_shared<FenceTime>(std::move(fence)));
 
         // Cache timestamps of signaled fences so we can close their file
         // descriptors.
-        mFrameEventHistory.updateSignalTimes();
+        mFrameEventHistory->updateSignalTimes();
     }
 
     mLastFrameNumber = mNextFrameNumber;
@@ -638,8 +643,7 @@
     mQueriedSupportedTimestamps = true;
 
     std::vector<FrameEvent> supportedFrameTimestamps;
-    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-    status_t err = composer->getSupportedFrameTimestamps(
+    status_t err = composerService()->getSupportedFrameTimestamps(
             &supportedFrameTimestamps);
 
     if (err != NO_ERROR) {
@@ -668,9 +672,8 @@
                 }
                 break;
             case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
-                sp<ISurfaceComposer> composer(
-                        ComposerService::getComposerService());
-                if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+                if (composerService()->authenticateSurfaceTexture(
+                        mGraphicBufferProducer)) {
                     *value = 1;
                 } else {
                     *value = 0;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 66e1bb6..2206902 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -19,22 +19,28 @@
 #include <gtest/gtest.h>
 
 #include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+#include <gui/IDisplayEventConnection.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/BufferItemConsumer.h>
+#include <private/gui/ComposerService.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
 
-#include <private/gui/ComposerService.h>
-#include <binder/ProcessState.h>
-
+#include <limits>
 #include <thread>
 
 namespace android {
 
 using namespace std::chrono_literals;
 
+class FakeSurfaceComposer;
+class FakeProducerFrameEventHistory;
+
+static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max();
+
 class SurfaceTest : public ::testing::Test {
 protected:
 
@@ -102,7 +108,8 @@
     BufferQueue::createBufferQueue(&producer, &consumer);
     sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    sp<IBinder> display(sf->getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain));
     ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 
@@ -272,4 +279,924 @@
     ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence));
 }
 
+
+class FakeConsumer : public BnConsumerListener {
+public:
+    void onFrameAvailable(const BufferItem& /*item*/) override {}
+    void onBuffersReleased() override {}
+    void onSidebandStreamChanged() override {}
+
+    void addAndGetFrameTimestamps(
+            const NewFrameEventsEntry* newTimestamps,
+            FrameEventHistoryDelta* outDelta) override {
+        if (newTimestamps) {
+            if (mGetFrameTimestampsEnabled) {
+                EXPECT_GT(mNewFrameEntryOverride.frameNumber, 0u) <<
+                        "Test should set mNewFrameEntryOverride before queuing "
+                        "a frame.";
+                EXPECT_EQ(newTimestamps->frameNumber,
+                        mNewFrameEntryOverride.frameNumber) <<
+                        "Test attempting to add NewFrameEntryOverride with "
+                        "incorrect frame number.";
+                mFrameEventHistory.addQueue(mNewFrameEntryOverride);
+                mNewFrameEntryOverride.frameNumber = 0;
+            }
+            mAddFrameTimestampsCount++;
+            mLastAddedFrameNumber = newTimestamps->frameNumber;
+        }
+        if (outDelta) {
+            mFrameEventHistory.getAndResetDelta(outDelta);
+            mGetFrameTimestampsCount++;
+        }
+        mAddAndGetFrameTimestampsCallCount++;
+    }
+
+    bool mGetFrameTimestampsEnabled = false;
+
+    ConsumerFrameEventHistory mFrameEventHistory;
+    int mAddAndGetFrameTimestampsCallCount = 0;
+    int mAddFrameTimestampsCount = 0;
+    int mGetFrameTimestampsCount = 0;
+    uint64_t mLastAddedFrameNumber = NO_FRAME_INDEX;
+
+    NewFrameEventsEntry mNewFrameEntryOverride = { 0, 0, 0, nullptr };
+};
+
+
+class FakeSurfaceComposer : public ISurfaceComposer{
+public:
+    ~FakeSurfaceComposer() override {}
+
+    void setSupportedTimestamps(bool supportsPresent, bool supportsRetire) {
+        mSupportsPresent = supportsPresent;
+        mSupportsRetire = supportsRetire;
+    }
+
+    sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
+    sp<IGraphicBufferAlloc> createGraphicBufferAlloc() override {
+        return nullptr;
+    }
+    sp<IDisplayEventConnection> createDisplayEventConnection() override {
+        return nullptr;
+    }
+    sp<IBinder> createDisplay(const String8& /*displayName*/,
+            bool /*secure*/) override { return nullptr; }
+    void destroyDisplay(const sp<IBinder>& /*display */) override {}
+    sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
+    void setTransactionState(const Vector<ComposerState>& /*state*/,
+            const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/)
+            override {}
+    void bootFinished() override {}
+    bool authenticateSurfaceTexture(
+            const sp<IGraphicBufferProducer>& /*surface*/) const override {
+        return false;
+    }
+
+    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
+            const override {
+        *outSupported = {
+                FrameEvent::REQUESTED_PRESENT,
+                FrameEvent::ACQUIRE,
+                FrameEvent::FIRST_REFRESH_START,
+                FrameEvent::GL_COMPOSITION_DONE,
+                FrameEvent::RELEASE
+        };
+        if (mSupportsPresent) {
+            outSupported->push_back(
+                        FrameEvent::DISPLAY_PRESENT);
+        }
+        if (mSupportsRetire) {
+            outSupported->push_back(
+                        FrameEvent::DISPLAY_RETIRE);
+        }
+        return NO_ERROR;
+    }
+
+    void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
+    status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
+            Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
+    status_t getDisplayStats(const sp<IBinder>& /*display*/,
+            DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
+    int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
+    status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
+            override {
+        return NO_ERROR;
+    }
+    status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
+            Vector<android_color_mode_t>* /*outColorModes*/) override {
+        return NO_ERROR;
+    }
+    android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/)
+            override {
+        return HAL_COLOR_MODE_NATIVE;
+    }
+    status_t setActiveColorMode(const sp<IBinder>& /*display*/,
+            android_color_mode_t /*colorMode*/) override { return NO_ERROR; }
+    status_t captureScreen(const sp<IBinder>& /*display*/,
+            const sp<IGraphicBufferProducer>& /*producer*/,
+            Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+            uint32_t /*minLayerZ*/, uint32_t /*maxLayerZ*/,
+            bool /*useIdentityTransform*/,
+            Rotation /*rotation*/) override { return NO_ERROR; }
+    status_t clearAnimationFrameStats() override { return NO_ERROR; }
+    status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
+        return NO_ERROR;
+    }
+    status_t getHdrCapabilities(const sp<IBinder>& /*display*/,
+            HdrCapabilities* /*outCapabilities*/) const override {
+        return NO_ERROR;
+    }
+    status_t enableVSyncInjections(bool /*enable*/) override {
+        return NO_ERROR;
+    }
+    status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
+
+protected:
+    IBinder* onAsBinder() override { return nullptr; }
+
+private:
+    bool mSupportsPresent{true};
+    bool mSupportsRetire{true};
+};
+
+class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
+public:
+    FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap)
+        : mFenceMap(fenceMap) {}
+
+    ~FakeProducerFrameEventHistory() {}
+
+    void updateAcquireFence(uint64_t frameNumber,
+            std::shared_ptr<FenceTime>&& acquire) override {
+        // Verify the acquire fence being added isn't the one from the consumer.
+        EXPECT_NE(mConsumerAcquireFence, acquire);
+        // Override the fence, so we can verify this was called by the
+        // producer after the frame is queued.
+        ProducerFrameEventHistory::updateAcquireFence(frameNumber,
+                std::shared_ptr<FenceTime>(mAcquireFenceOverride));
+    }
+
+    void setAcquireFenceOverride(
+            const std::shared_ptr<FenceTime>& acquireFenceOverride,
+            const std::shared_ptr<FenceTime>& consumerAcquireFence) {
+        mAcquireFenceOverride = acquireFenceOverride;
+        mConsumerAcquireFence = consumerAcquireFence;
+    }
+
+protected:
+    std::shared_ptr<FenceTime> createFenceTime(const sp<Fence>& fence)
+            const override {
+        return mFenceMap->createFenceTimeForTest(fence);
+    }
+
+    FenceToFenceTimeMap* mFenceMap{nullptr};
+
+    std::shared_ptr<FenceTime> mAcquireFenceOverride{FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> mConsumerAcquireFence{FenceTime::NO_FENCE};
+};
+
+
+class TestSurface : public Surface {
+public:
+    TestSurface(const sp<IGraphicBufferProducer>& bufferProducer,
+            FenceToFenceTimeMap* fenceMap)
+        : Surface(bufferProducer),
+          mFakeSurfaceComposer(new FakeSurfaceComposer) {
+        mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap);
+        mFrameEventHistory.reset(mFakeFrameEventHistory);
+    }
+
+    ~TestSurface() override {}
+
+    sp<ISurfaceComposer> composerService() const override {
+        return mFakeSurfaceComposer;
+    }
+
+public:
+    sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+
+    // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
+    // but this raw pointer gives access to test functionality.
+    FakeProducerFrameEventHistory* mFakeFrameEventHistory;
+};
+
+
+class GetFrameTimestampsTest : public SurfaceTest {
+protected:
+    struct FenceAndFenceTime {
+        explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap)
+           : mFence(new Fence),
+             mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {}
+        sp<Fence> mFence { nullptr };
+        std::shared_ptr<FenceTime> mFenceTime { nullptr };
+    };
+
+    struct RefreshEvents {
+        RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart)
+            : mFenceMap(fenceMap),
+              kStartTime(refreshStart + 1),
+              kGpuCompositionDoneTime(refreshStart + 2),
+              kPresentTime(refreshStart + 3) {}
+
+        void signalPostCompositeFences() {
+            mFenceMap.signalAllForTest(
+                        mGpuCompositionDone.mFence, kGpuCompositionDoneTime);
+            mFenceMap.signalAllForTest(mPresent.mFence, kPresentTime);
+        }
+
+        FenceToFenceTimeMap& mFenceMap;
+
+        FenceAndFenceTime mGpuCompositionDone { mFenceMap };
+        FenceAndFenceTime mPresent { mFenceMap };
+
+        const nsecs_t kStartTime;
+        const nsecs_t kGpuCompositionDoneTime;
+        const nsecs_t kPresentTime;
+    };
+
+    struct FrameEvents {
+        FrameEvents(FenceToFenceTimeMap& fenceMap, nsecs_t frameStartTime)
+            : mFenceMap(fenceMap),
+              kPostedTime(frameStartTime + 100),
+              kRequestedPresentTime(frameStartTime + 200),
+              kProducerAcquireTime(frameStartTime + 300),
+              kConsumerAcquireTime(frameStartTime + 301),
+              kLatchTime(frameStartTime + 500),
+              kRetireTime(frameStartTime + 600),
+              kReleaseTime(frameStartTime + 700),
+              mRefreshes {
+                    { mFenceMap, frameStartTime + 410 },
+                    { mFenceMap, frameStartTime + 420 },
+                    { mFenceMap, frameStartTime + 430 } } {}
+
+        void signalQueueFences() {
+            mFenceMap.signalAllForTest(
+                        mAcquireConsumer.mFence, kConsumerAcquireTime);
+            mFenceMap.signalAllForTest(
+                        mAcquireProducer.mFence, kProducerAcquireTime);
+        }
+
+        void signalRefreshFences() {
+            for (auto& re : mRefreshes) {
+                re.signalPostCompositeFences();
+            }
+        }
+
+        void signalReleaseFences() {
+            mFenceMap.signalAllForTest(mRetire.mFence, kRetireTime);
+            mFenceMap.signalAllForTest(mRelease.mFence, kReleaseTime);
+        }
+
+        FenceToFenceTimeMap& mFenceMap;
+
+        FenceAndFenceTime mAcquireConsumer { mFenceMap };
+        FenceAndFenceTime mAcquireProducer { mFenceMap };
+        FenceAndFenceTime mRetire { mFenceMap };
+        FenceAndFenceTime mRelease { mFenceMap };
+
+        const nsecs_t kPostedTime;
+        const nsecs_t kRequestedPresentTime;
+        const nsecs_t kProducerAcquireTime;
+        const nsecs_t kConsumerAcquireTime;
+        const nsecs_t kLatchTime;
+        const nsecs_t kRetireTime;
+        const nsecs_t kReleaseTime;
+
+        RefreshEvents mRefreshes[3];
+    };
+
+    GetFrameTimestampsTest() : SurfaceTest() {}
+
+    virtual void SetUp() {
+        SurfaceTest::SetUp();
+
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mFakeConsumer = new FakeConsumer;
+        mCfeh = &mFakeConsumer->mFrameEventHistory;
+        mConsumer->consumerConnect(mFakeConsumer, false);
+        mConsumer->setConsumerName(String8("TestConsumer"));
+        mSurface = new TestSurface(mProducer, &mFenceMap);
+        mWindow = mSurface;
+
+        ASSERT_EQ(NO_ERROR, native_window_api_connect(mWindow.get(),
+                NATIVE_WINDOW_API_CPU));
+        native_window_set_buffer_count(mWindow.get(), 4);
+    }
+
+    void enableFrameTimestamps() {
+        mFakeConsumer->mGetFrameTimestampsEnabled = true;
+        native_window_enable_frame_timestamps(mWindow.get(), 1);
+        mFrameTimestampsEnabled = true;
+    }
+
+    void resetTimestamps() {
+        outRequestedPresentTime = -1;
+        outAcquireTime = -1;
+        outRefreshStartTime = -1;
+        outGpuCompositionDoneTime = -1;
+        outDisplayPresentTime = -1;
+        outDisplayRetireTime = -1;
+        outReleaseTime = -1;
+    }
+
+    void dequeueAndQueue(uint64_t frameIndex) {
+        int fence = -1;
+        ANativeWindowBuffer* buffer = nullptr;
+        ASSERT_EQ(NO_ERROR,
+                mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+
+        int oldAddFrameTimestampsCount =
+                mFakeConsumer->mAddFrameTimestampsCount;
+
+        FrameEvents* frame = &mFrames[frameIndex];
+        uint64_t frameNumber = frameIndex + 1;
+
+        NewFrameEventsEntry fe;
+        fe.frameNumber = frameNumber;
+        fe.postedTime = frame->kPostedTime;
+        fe.requestedPresentTime = frame->kRequestedPresentTime;
+        fe.acquireFence = frame->mAcquireConsumer.mFenceTime;
+        mFakeConsumer->mNewFrameEntryOverride = fe;
+
+        mSurface->mFakeFrameEventHistory->setAcquireFenceOverride(
+                    frame->mAcquireProducer.mFenceTime,
+                    frame->mAcquireConsumer.mFenceTime);
+
+        ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+
+        EXPECT_EQ(frameNumber, mFakeConsumer->mLastAddedFrameNumber);
+
+        EXPECT_EQ(
+                oldAddFrameTimestampsCount + (mFrameTimestampsEnabled ? 1 : 0),
+                mFakeConsumer->mAddFrameTimestampsCount);
+    }
+
+    void addFrameEvents(
+            bool gpuComposited, uint64_t iOldFrame, int64_t iNewFrame) {
+        FrameEvents* oldFrame =
+                (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
+        FrameEvents* newFrame = &mFrames[iNewFrame];
+
+        uint64_t nOldFrame = iOldFrame + 1;
+        uint64_t nNewFrame = iNewFrame + 1;
+
+        // Latch, Composite, Retire, and Release the frames in a plausible
+        // order. Note: The timestamps won't necessarily match the order, but
+        // that's okay for the purposes of this test.
+        std::shared_ptr<FenceTime> gpuDoneFenceTime = FenceTime::NO_FENCE;
+
+        mCfeh->addLatch(nNewFrame, newFrame->kLatchTime);
+
+        mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[0].kStartTime);
+        gpuDoneFenceTime = gpuComposited ?
+                newFrame->mRefreshes[0].mGpuCompositionDone.mFenceTime :
+                FenceTime::NO_FENCE;
+        // HWC2 releases the previous buffer after a new latch just before
+        // calling postComposition.
+        if (oldFrame != nullptr) {
+            mCfeh->addRelease(nOldFrame,
+                    std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
+        }
+        mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+                newFrame->mRefreshes[0].mPresent.mFenceTime);
+
+        // Retire the previous buffer just after compositing the new buffer.
+        if (oldFrame != nullptr) {
+            mCfeh->addRetire(nOldFrame, oldFrame->mRetire.mFenceTime);
+        }
+
+        mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[1].kStartTime);
+        gpuDoneFenceTime = gpuComposited ?
+                newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
+                FenceTime::NO_FENCE;
+        mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+                newFrame->mRefreshes[1].mPresent.mFenceTime);
+        mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[2].kStartTime);
+        gpuDoneFenceTime = gpuComposited ?
+                newFrame->mRefreshes[2].mGpuCompositionDone.mFenceTime :
+                FenceTime::NO_FENCE;
+        mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+                newFrame->mRefreshes[2].mPresent.mFenceTime);
+    }
+
+    void QueryPresentRetireSupported(
+            bool displayPresentSupported, bool displayRetireSupported);
+    void PresentOrRetireUnsupportedNoSyncTest(
+            bool displayPresentSupported, bool displayRetireSupported);
+
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<FakeConsumer> mFakeConsumer;
+    ConsumerFrameEventHistory* mCfeh;
+    sp<TestSurface> mSurface;
+    sp<ANativeWindow> mWindow;
+
+    FenceToFenceTimeMap mFenceMap;
+
+    bool mFrameTimestampsEnabled = false;
+
+    int64_t outRequestedPresentTime = -1;
+    int64_t outAcquireTime = -1;
+    int64_t outRefreshStartTime = -1;
+    int64_t outGpuCompositionDoneTime = -1;
+    int64_t outDisplayPresentTime = -1;
+    int64_t outDisplayRetireTime = -1;
+    int64_t outReleaseTime = -1;
+
+    FrameEvents mFrames[2] { { mFenceMap, 1000 }, { mFenceMap, 2000 } };
+};
+
+
+// This test verifies that the frame timestamps are not retrieved when not
+// explicitly enabled via native_window_enable_frame_timestamps.
+// We want to check this to make sure there's no overhead for users
+// that don't need the timestamp information.
+TEST_F(GetFrameTimestampsTest, DefaultDisabled) {
+    int fence;
+    ANativeWindowBuffer* buffer;
+
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify the producer doesn't get frame timestamps piggybacked on dequeue.
+    ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify the producer doesn't get frame timestamps piggybacked on queue.
+    // It is okay that frame timestamps are added in the consumer since it is
+    // still needed for SurfaceFlinger dumps.
+    ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+    EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify attempts to get frame timestamps fail.
+    const uint32_t framesAgo = 0;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(INVALID_OPERATION, result);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+// This test verifies that the frame timestamps are retrieved if explicitly
+// enabled via native_window_enable_frame_timestamps.
+TEST_F(GetFrameTimestampsTest, EnabledSimple) {
+    enableFrameTimestamps();
+
+    int fence;
+    ANativeWindowBuffer* buffer;
+
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify getFrameTimestamps is piggybacked on dequeue.
+    ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
+
+    NewFrameEventsEntry f1;
+    f1.frameNumber = 1;
+    f1.postedTime = mFrames[0].kPostedTime;
+    f1.requestedPresentTime = mFrames[0].kRequestedPresentTime;
+    f1.acquireFence = mFrames[0].mAcquireConsumer.mFenceTime;
+    mSurface->mFakeFrameEventHistory->setAcquireFenceOverride(
+            mFrames[0].mAcquireProducer.mFenceTime,
+            mFrames[0].mAcquireConsumer.mFenceTime);
+    mFakeConsumer->mNewFrameEntryOverride = f1;
+    mFrames[0].signalQueueFences();
+
+    // Verify getFrameTimestamps is piggybacked on queue.
+    ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+    EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(1u, mFakeConsumer->mLastAddedFrameNumber);
+    EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify queries for timestamps that the producer doesn't know about
+    // triggers a call to see if the consumer has any new timestamps.
+    const uint32_t framesAgo = 0;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+void GetFrameTimestampsTest::QueryPresentRetireSupported(
+        bool displayPresentSupported, bool displayRetireSupported) {
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
+            displayPresentSupported, displayRetireSupported);
+
+    // Verify supported bits are forwarded.
+    int supportsPresent = -1;
+    mWindow.get()->query(mWindow.get(),
+            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+    EXPECT_EQ(displayPresentSupported, supportsPresent);
+
+    int supportsRetire = -1;
+    mWindow.get()->query(mWindow.get(),
+            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &supportsRetire);
+    EXPECT_EQ(displayRetireSupported, supportsRetire);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
+   QueryPresentRetireSupported(true, false);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryRetireSupported) {
+   QueryPresentRetireSupported(false, true);
+}
+
+// This test verifies that:
+// 1) The timestamps recorded in the consumer's FrameTimestampsHistory are
+//    properly retrieved by the producer for the correct frames.
+// 2) When framesAgo is 0, it is querying for the most recently queued frame.
+TEST_F(GetFrameTimestampsTest, TimestampsAssociatedWithCorrectFrame) {
+    enableFrameTimestamps();
+
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+    mFrames[0].signalRefreshFences();
+    addFrameEvents(true, 0, 1);
+    mFrames[0].signalReleaseFences();
+    mFrames[1].signalRefreshFences();
+
+    // Verify timestamps are correct for frame 1.
+    uint32_t framesAgo = 1;
+    resetTimestamps();
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
+            outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+
+    // Verify timestamps are correct for frame 2.
+    framesAgo = 0;
+    resetTimestamps();
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
+            outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outReleaseTime);
+}
+
+// This test verifies the acquire fence recorded by the consumer is not sent
+// back to the producer and the producer saves its own fence.
+TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) {
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+    const uint32_t framesAgo = 0;
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+
+    // Verify queue-related timestamps for f1 are available immediately in the
+    // producer without asking the consumer again, even before signaling the
+    // acquire fence.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(0, outAcquireTime);
+
+    // Signal acquire fences. Verify a sync call still isn't necessary.
+    mFrames[0].signalQueueFences();
+
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+
+    // Verify queue-related timestamps for f2 are available immediately in the
+    // producer without asking the consumer again, even before signaling the
+    // acquire fence.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(0, outAcquireTime);
+
+    // Signal acquire fences. Verify a sync call still isn't necessary.
+    mFrames[1].signalQueueFences();
+
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+}
+
+TEST_F(GetFrameTimestampsTest, ZeroRequestedTimestampsNoSync) {
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+    mFrames[0].signalRefreshFences();
+    addFrameEvents(true, 0, 1);
+    mFrames[0].signalReleaseFences();
+    mFrames[1].signalRefreshFences();
+
+    // Verify a request for no timestamps doesn't result in a sync call.
+    const uint32_t framesAgo = 0;
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+// This test verifies that fences can signal and update timestamps producer
+// side without an additional sync call to the consumer.
+TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) {
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+    addFrameEvents(true, 0, 1);
+
+    // Verify available timestamps are correct for frame 1, before any
+    // fence has been signaled.
+    // Note: A sync call is necessary here since the events triggered by
+    // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+    uint32_t framesAgo = 1;
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(0, outGpuCompositionDoneTime);
+    EXPECT_EQ(0, outDisplayPresentTime);
+    EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outReleaseTime);
+
+    // Verify available timestamps are correct for frame 1 again, before any
+    // fence has been signaled.
+    // This time a sync call should not be necessary.
+    framesAgo = 1;
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(0, outGpuCompositionDoneTime);
+    EXPECT_EQ(0, outDisplayPresentTime);
+    EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outReleaseTime);
+
+    // Signal the fences for frame 1.
+    mFrames[0].signalRefreshFences();
+    mFrames[0].signalReleaseFences();
+
+    // Verify all timestamps are available without a sync call.
+    framesAgo = 1;
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
+            outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+}
+
+// This test verifies that if the frame wasn't GPU composited but has a refresh
+// event a sync call isn't made to get the GPU composite done time since it will
+// never exist.
+TEST_F(GetFrameTimestampsTest, NoGpuNoSync) {
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+    const uint32_t framesAgo = 1;
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(false, NO_FRAME_INDEX, 0);
+    addFrameEvents(false, 0, 1);
+
+    // Verify available timestamps are correct for frame 1, before any
+    // fence has been signaled.
+    // Note: A sync call is necessary here since the events triggered by
+    // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(0, outGpuCompositionDoneTime);
+    EXPECT_EQ(0, outDisplayPresentTime);
+    EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outReleaseTime);
+
+    // Signal the fences for frame 1.
+    mFrames[0].signalRefreshFences();
+    mFrames[0].signalReleaseFences();
+
+    // Verify all timestamps, except GPU composition, are available without a
+    // sync call.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(0, outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+}
+
+// This test verifies that if the retire/release info can't possibly exist,
+// a sync call is not done.
+TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(false, NO_FRAME_INDEX, 0);
+    addFrameEvents(false, 0, 1);
+
+    // Verify available timestamps are correct for frame 1, before any
+    // fence has been signaled.
+    // Note: A sync call is necessary here since the events triggered by
+    // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+    uint32_t framesAgo = 1;
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(0, outGpuCompositionDoneTime);
+    EXPECT_EQ(0, outDisplayPresentTime);
+    EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outReleaseTime);
+
+    mFrames[0].signalRefreshFences();
+    mFrames[0].signalReleaseFences();
+    mFrames[1].signalRefreshFences();
+
+    // Verify querying for all timestmaps of f2 does not do a sync call.
+    // Even though the retire and release times aren't available, a sync call
+    // should not occur because it's not possible for it to be retired or
+    // released until another frame is queued.
+    framesAgo = 0;
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
+            &outGpuCompositionDoneTime, &outDisplayPresentTime,
+            &outDisplayRetireTime, &outReleaseTime);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outRefreshStartTime);
+    EXPECT_EQ(0, outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outReleaseTime);
+}
+
+// This test verifies there are no sync calls for present or retire times
+// when they aren't supported and that an error is returned.
+void GetFrameTimestampsTest::PresentOrRetireUnsupportedNoSyncTest(
+        bool displayPresentSupported, bool displayRetireSupported) {
+
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
+        displayPresentSupported, displayRetireSupported);
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+
+    // Verify a query for the Present and Retire times do not trigger
+    // a sync call if they are not supported.
+    const uint32_t framesAgo = 0;
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+            nullptr, nullptr, nullptr, nullptr,
+            displayPresentSupported ? nullptr : &outDisplayPresentTime,
+            displayRetireSupported ? nullptr : &outDisplayRetireTime,
+            nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(BAD_VALUE, result);
+    EXPECT_EQ(-1, outDisplayRetireTime);
+    EXPECT_EQ(-1, outDisplayPresentTime);
+}
+
+TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
+   PresentOrRetireUnsupportedNoSyncTest(false, true);
+}
+
+TEST_F(GetFrameTimestampsTest, RetireUnsupportedNoSync) {
+   PresentOrRetireUnsupportedNoSyncTest(true, false);
+}
+
 }
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index c0245eb..edcec99 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -130,6 +130,14 @@
     // Make the system call without the lock held.
     signalTime = fence->getSignalTime();
 
+    // Allow tests to override SIGNAL_TIME_INVALID behavior, since tests
+    // use invalid underlying Fences without real file descriptors.
+    if (CC_UNLIKELY(mState == State::FORCED_VALID_FOR_TEST)) {
+        if (signalTime == Fence::SIGNAL_TIME_INVALID) {
+            signalTime = Fence::SIGNAL_TIME_PENDING;
+        }
+    }
+
     // Make the signal time visible to everyone if it is no longer pending
     // and remove the class' reference to the fence.
     if (signalTime != Fence::SIGNAL_TIME_PENDING) {
@@ -163,10 +171,28 @@
     return Snapshot(mFence);
 }
 
+// For tests only. If forceValidForTest is true, then getSignalTime will
+// never return SIGNAL_TIME_INVALID and isValid will always return true.
+FenceTime::FenceTime(const sp<Fence>& fence, bool forceValidForTest)
+  : mState(forceValidForTest ?
+            State::FORCED_VALID_FOR_TEST : State::INVALID),
+    mFence(fence),
+    mSignalTime(mState == State::INVALID ?
+            Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
+}
+
+void FenceTime::signalForTest(nsecs_t signalTime) {
+    // To be realistic, this should really set a hidden value that
+    // gets picked up in the next call to getSignalTime, but this should
+    // be good enough.
+    std::lock_guard<std::mutex> lock(mMutex);
+    mFence.clear();
+    mSignalTime.store(signalTime, std::memory_order_relaxed);
+}
+
 // ============================================================================
 // FenceTime::Snapshot
 // ============================================================================
-
 FenceTime::Snapshot::Snapshot(const sp<Fence>& srcFence)
     : state(State::FENCE), fence(srcFence) {
 }
@@ -279,4 +305,60 @@
     }
 }
 
+// ============================================================================
+// FenceToFenceTimeMap
+// ============================================================================
+std::shared_ptr<FenceTime> FenceToFenceTimeMap::createFenceTimeForTest(
+        const sp<Fence>& fence) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    // Always garbage collecting isn't efficient, but this is only for testing.
+    garbageCollectLocked();
+    std::shared_ptr<FenceTime> fenceTime(new FenceTime(fence, true));
+    mMap[fence.get()].push_back(fenceTime);
+    return fenceTime;
+}
+
+void FenceToFenceTimeMap::signalAllForTest(
+        const sp<Fence>& fence, nsecs_t signalTime) {
+    bool signaled = false;
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    auto it = mMap.find(fence.get());
+    if (it != mMap.end()) {
+        for (auto& weakFenceTime : it->second) {
+            std::shared_ptr<FenceTime> fenceTime = weakFenceTime.lock();
+            if (!fenceTime) {
+                continue;
+            }
+            ALOGE_IF(!fenceTime->isValid(),
+                    "FenceToFenceTimeMap::signalAllForTest: "
+                     "Signaling invalid fence.");
+            fenceTime->signalForTest(signalTime);
+            signaled = true;
+        }
+    }
+
+    if (!signaled) {
+        ALOGE("FenceToFenceTimeMap::signalAllForTest: Nothing to signal.");
+    }
+}
+
+void FenceToFenceTimeMap::garbageCollectLocked() {
+    for (auto& it : mMap) {
+        // Erase all expired weak pointers from the vector.
+        auto& vect = it.second;
+        vect.erase(
+                std::remove_if(vect.begin(), vect.end(),
+                        [](const std::weak_ptr<FenceTime>& ft) {
+                            return ft.expired();
+                        }),
+                vect.end());
+
+        // Also erase the map entry if the vector is now empty.
+        if (vect.empty()) {
+            mMap.erase(it.first);
+        }
+    }
+}
+
 } // namespace android