Merge changes from topic 'drvup-master'

* changes:
  EGL: Load updated EGL/GLES drivers
  Load updated drivers using derived loader namespace
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a693737..edcb3e9 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -288,12 +288,13 @@
         }
     }
 
+    mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
     if (st.st_uid != uid) {
         // Mismatched UID is real trouble; we can't recover
         LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid
                 << " but expected " << uid;
         return -1;
-    } else if (st.st_gid == gid && st.st_mode == target_mode) {
+    } else if (st.st_gid == gid && actual_mode == target_mode) {
         // Everything looks good!
         return 0;
     }
@@ -337,6 +338,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -344,10 +346,15 @@
     // Assume invalid inode unless filled in below
     if (_aidl_return != nullptr) *_aidl_return = -1;
 
-    uid_t uid = multiuser_get_uid(userId, appId);
-    gid_t cacheGid = multiuser_get_cache_gid(userId, appId);
+    int32_t uid = multiuser_get_uid(userId, appId);
+    int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
     mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
 
+    // If UID doesn't have a specific cache GID, use UID value
+    if (cacheGid == -1) {
+        cacheGid = uid;
+    }
+
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
         bool existing = (access(path.c_str(), F_OK) == 0);
@@ -423,6 +430,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -465,6 +473,7 @@
 binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     binder::Status res = ok();
@@ -482,6 +491,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -541,6 +551,7 @@
 binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     binder::Status res = ok();
@@ -561,6 +572,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -594,6 +606,7 @@
     CHECK_ARGUMENT_UUID(fromUuid);
     CHECK_ARGUMENT_UUID(toUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
     const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
@@ -728,6 +741,7 @@
         int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     if (flags & FLAG_STORAGE_DE) {
@@ -744,6 +758,7 @@
         int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     binder::Status res = ok();
@@ -787,6 +802,7 @@
         int64_t freeStorageSize) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     cache_t* cache;
@@ -829,6 +845,8 @@
 binder::Status InstalldNativeService::rmdex(const std::string& codePath,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     char dex_path[PKG_PATH_MAX];
 
     const char* path = codePath.c_str();
@@ -1044,6 +1062,7 @@
     for (auto packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     // When modifying this logic, always verify using tests:
     // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
@@ -1143,6 +1162,7 @@
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     // When modifying this logic, always verify using tests:
     // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
@@ -1238,6 +1258,7 @@
         int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     // When modifying this logic, always verify using tests:
     // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
@@ -1349,6 +1370,7 @@
         const std::string& codePaths, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     const char* code_paths = codePaths.c_str();
@@ -1362,6 +1384,7 @@
         bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* pkgname = packageName.c_str();
     *_aidl_return = analyse_profiles(uid, pkgname);
@@ -1378,6 +1401,7 @@
     if (packageName && *packageName != "*") {
         CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
     }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
     const char* pkgname = packageName ? packageName->c_str() : "*";
@@ -1394,6 +1418,8 @@
 
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* instruction_set = instructionSet.c_str();
 
     char boot_marker_path[PKG_PATH_MAX];
@@ -1437,6 +1463,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
@@ -1559,6 +1586,8 @@
 binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
         const std::string& overlayApkPath, int32_t uid) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* target_apk = targetApkPath.c_str();
     const char* overlay_apk = overlayApkPath.c_str();
     ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
@@ -1630,6 +1659,7 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     binder::Status res = ok();
 
@@ -1658,6 +1688,8 @@
 binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* oat_dir = oatDir.c_str();
     const char* instruction_set = instructionSet.c_str();
     char oat_instr_dir[PKG_PATH_MAX];
@@ -1680,6 +1712,8 @@
 
 binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     if (validate_apk_path(packageDir.c_str())) {
         return error("Invalid path " + packageDir);
     }
@@ -1692,6 +1726,8 @@
 binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
         const std::string& fromBase, const std::string& toBase) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* relative_path = relativePath.c_str();
     const char* from_base = fromBase.c_str();
     const char* to_base = toBase.c_str();
@@ -1718,6 +1754,7 @@
 binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
         const std::string& instructionSet, const std::string& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
     const char* instruction_set = instructionSet.c_str();
@@ -1730,6 +1767,7 @@
 binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
         const std::string& instructionSet, const std::string& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
     const char* instruction_set = instructionSet.c_str();
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5397a74..ec81462 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -99,6 +99,9 @@
             const std::string& outputPath);
     binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
             const std::string& outputPath);
+
+private:
+    std::recursive_mutex mLock;
 };
 
 }  // namespace installd
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index e2bafec..da574ec 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -22,6 +22,7 @@
 
 #include <gui/BufferQueueDefs.h>
 #include <gui/IGraphicBufferConsumer.h>
+#include <utils/String8.h>
 
 namespace android {
 
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 7d62706..46ca2c2 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -44,6 +44,7 @@
     GL_COMPOSITION_DONE,
     DISPLAY_PRESENT,
     DISPLAY_RETIRE,
+    DEQUEUE_READY,
     RELEASE,
     EVENT_COUNT, // Not an actual event.
 };
@@ -61,6 +62,7 @@
     bool hasDisplayPresentInfo() const;
     bool hasDisplayRetireInfo() const;
     bool hasReleaseInfo() const;
+    bool hasDequeueReadyInfo() const;
 
     void checkFencesForCompletion();
     void dump(String8& outString) const;
@@ -84,6 +86,7 @@
     nsecs_t latchTime{-1};
     nsecs_t firstRefreshStartTime{-1};
     nsecs_t lastRefreshStartTime{-1};
+    nsecs_t dequeueReadyTime{-1};
 
     std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
@@ -194,7 +197,7 @@
             const std::shared_ptr<FenceTime>& displayPresent);
     void addRetire(uint64_t frameNumber,
             const std::shared_ptr<FenceTime>& displayRetire);
-    void addRelease(uint64_t frameNumber,
+    void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
             std::shared_ptr<FenceTime>&& release);
 
     void getAndResetDelta(FrameEventHistoryDelta* delta);
@@ -255,6 +258,7 @@
     nsecs_t mLatchTime{0};
     nsecs_t mFirstRefreshStartTime{0};
     nsecs_t mLastRefreshStartTime{0};
+    nsecs_t mDequeueReadyTime{0};
 
     FenceTime::Snapshot mGpuCompositionDoneFence;
     FenceTime::Snapshot mDisplayPresentFence;
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 43b8d96..0b6a8f7 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -146,9 +146,10 @@
     // See IGraphicBufferProducer::getFrameTimestamps
     status_t getFrameTimestamps(uint64_t frameNumber,
             nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
-            nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+            nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+            nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
             nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
-            nsecs_t* outReleaseTime);
+            nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
 
     status_t getUniqueId(uint64_t* outId) const;
 
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 99b39d8..58df24c 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -18,21 +18,17 @@
 #define ANDROID_FENCE_H
 
 #include <stdint.h>
-#include <sys/types.h>
 
-#include <ui/ANativeObjectBase.h>
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
 #include <utils/Flattenable.h>
-#include <utils/String8.h>
+#include <utils/RefBase.h>
 #include <utils/Timers.h>
 
 #include <experimental/optional>
 
-struct ANativeWindowBuffer;
-
 namespace android {
 
+class String8;
+
 // ===========================================================================
 // Fence
 // ===========================================================================
@@ -62,6 +58,12 @@
     // closed.
     explicit Fence(int fenceFd);
 
+    // Not copyable or movable.
+    Fence(const Fence& rhs) = delete;
+    Fence& operator=(const Fence& rhs) = delete;
+    Fence(Fence&& rhs) = delete;
+    Fence& operator=(Fence&& rhs) = delete;
+
     // Check whether the Fence has an open fence file descriptor. Most Fence
     // methods treat an invalid file descriptor just like a valid fence that
     // is already signalled, so using this is usually not necessary.
@@ -135,11 +137,6 @@
     friend class LightRefBase<Fence>;
     ~Fence();
 
-    // Disallow copying
-    Fence(const Fence& rhs);
-    Fence& operator = (const Fence& rhs);
-    const Fence& operator = (const Fence& rhs) const;
-
     int mFenceFd;
 };
 
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 46ca974..73537bf 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -18,6 +18,7 @@
 
 #include <cutils/compiler.h>  // For CC_[UN]LIKELY
 #include <inttypes.h>
+#include <utils/Log.h>
 #include <utils/String8.h>
 
 #include <algorithm>
@@ -54,6 +55,10 @@
     return addRetireCalled || addReleaseCalled;
 }
 
+bool FrameEvents::hasDequeueReadyInfo() const {
+    return Fence::isValidTimestamp(dequeueReadyTime);
+}
+
 bool FrameEvents::hasAcquireInfo() const {
     return acquireFence->isValid();
 }
@@ -140,6 +145,14 @@
             !addPostCompositeCalled, *displayPresentFence);
     dumpFenceTime(outString, "Display Retire    \t",
             !addRetireCalled, *displayRetireFence);
+
+    outString.appendFormat("--- DequeueReady  \t");
+    if (Fence::isValidTimestamp(dequeueReadyTime)) {
+        outString.appendFormat("%" PRId64 "\n", dequeueReadyTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
     dumpFenceTime(outString, "Release           \t",
             true, *releaseFence);
 }
@@ -261,6 +274,7 @@
         frame.latchTime = d.mLatchTime;
         frame.firstRefreshStartTime = d.mFirstRefreshStartTime;
         frame.lastRefreshStartTime = d.mLastRefreshStartTime;
+        frame.dequeueReadyTime = d.mDequeueReadyTime;
 
         if (frame.frameNumber != d.mFrameNumber) {
             // We got a new frame. Initialize some of the fields.
@@ -410,14 +424,15 @@
     mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>();
 }
 
-void ConsumerFrameEventHistory::addRelease(
-        uint64_t frameNumber, std::shared_ptr<FenceTime>&& release) {
+void ConsumerFrameEventHistory::addRelease(uint64_t frameNumber,
+        nsecs_t dequeueReadyTime, std::shared_ptr<FenceTime>&& release) {
     FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
     if (frame == nullptr) {
         ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame.");
         return;
     }
     frame->addReleaseCalled = true;
+    frame->dequeueReadyTime = dequeueReadyTime;
     frame->releaseFence = std::move(release);
     mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>();
 }
@@ -466,7 +481,8 @@
       mRequestedPresentTime(frameTimestamps.requestedPresentTime),
       mLatchTime(frameTimestamps.latchTime),
       mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
-      mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) {
+      mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime),
+      mDequeueReadyTime(frameTimestamps.dequeueReadyTime) {
     if (dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>()) {
         mGpuCompositionDoneFence =
                 frameTimestamps.gpuCompositionDoneFence->getSnapshot();
@@ -494,7 +510,8 @@
             sizeof(FrameEventsDelta::mRequestedPresentTime) +
             sizeof(FrameEventsDelta::mLatchTime) +
             sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
-            sizeof(FrameEventsDelta::mLastRefreshStartTime);
+            sizeof(FrameEventsDelta::mLastRefreshStartTime) +
+            sizeof(FrameEventsDelta::mDequeueReadyTime);
     return min;
 }
 
@@ -543,6 +560,7 @@
     FlattenableUtils::write(buffer, size, mLatchTime);
     FlattenableUtils::write(buffer, size, mFirstRefreshStartTime);
     FlattenableUtils::write(buffer, size, mLastRefreshStartTime);
+    FlattenableUtils::write(buffer, size, mDequeueReadyTime);
 
     // Fences
     for (auto fence : allFences(this)) {
@@ -581,6 +599,7 @@
     FlattenableUtils::read(buffer, size, mLatchTime);
     FlattenableUtils::read(buffer, size, mFirstRefreshStartTime);
     FlattenableUtils::read(buffer, size, mLastRefreshStartTime);
+    FlattenableUtils::read(buffer, size, mDequeueReadyTime);
 
     // Fences
     for (auto fence : allFences(this)) {
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 2401464..ef770e8 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -19,6 +19,7 @@
 
 #include <utils/Errors.h>
 #include <utils/NativeHandle.h>
+#include <utils/String8.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index e37b65b..18a80e8 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -20,6 +20,7 @@
 #include <utils/Errors.h>
 #include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ead8ecb..c859828 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -150,27 +150,39 @@
 
 static bool checkConsumerForUpdates(
         const FrameEvents* e, const uint64_t lastFrameNumber,
-        const nsecs_t* outRefreshStartTime,
+        const nsecs_t* outLatchTime,
+        const nsecs_t* outFirstRefreshStartTime,
+        const nsecs_t* outLastRefreshStartTime,
         const nsecs_t* outGlCompositionDoneTime,
         const nsecs_t* outDisplayPresentTime,
         const nsecs_t* outDisplayRetireTime,
+        const nsecs_t* outDequeueReadyTime,
         const nsecs_t* outReleaseTime) {
-    bool checkForRefreshStart = (outRefreshStartTime != nullptr) &&
+    bool checkForLatch = (outLatchTime != nullptr) && !e->hasLatchInfo();
+    bool checkForFirstRefreshStart = (outFirstRefreshStartTime != nullptr) &&
             !e->hasFirstRefreshStartInfo();
     bool checkForGlCompositionDone = (outGlCompositionDoneTime != nullptr) &&
             !e->hasGpuCompositionDoneInfo();
     bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
             !e->hasDisplayPresentInfo();
 
-    // DisplayRetire and Release are never available for the last frame.
+    // LastRefreshStart, DisplayRetire, DequeueReady, and Release are never
+    // available for the last frame.
+    bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
+            !e->hasLastRefreshStartInfo() &&
+            (e->frameNumber != lastFrameNumber);
     bool checkForDisplayRetire = (outDisplayRetireTime != nullptr) &&
             !e->hasDisplayRetireInfo() && (e->frameNumber != lastFrameNumber);
+    bool checkForDequeueReady = (outDequeueReadyTime != nullptr) &&
+            !e->hasDequeueReadyInfo() && (e->frameNumber != lastFrameNumber);
     bool checkForRelease = (outReleaseTime != nullptr) &&
             !e->hasReleaseInfo() && (e->frameNumber != lastFrameNumber);
 
     // RequestedPresent and Acquire info are always available producer-side.
-    return checkForRefreshStart || checkForGlCompositionDone ||
-            checkForDisplayPresent || checkForDisplayRetire || checkForRelease;
+    return checkForLatch || checkForFirstRefreshStart ||
+            checkForLastRefreshStart || checkForGlCompositionDone ||
+            checkForDisplayPresent || checkForDisplayRetire ||
+            checkForDequeueReady || checkForRelease;
 }
 
 static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
@@ -188,9 +200,10 @@
 
 status_t Surface::getFrameTimestamps(uint64_t frameNumber,
         nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
-        nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+        nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+        nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
         nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
-        nsecs_t* outReleaseTime) {
+        nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime) {
     ATRACE_CALL();
 
     Mutex::Autolock lock(mMutex);
@@ -217,8 +230,9 @@
 
     // Update our cache of events if the requested events are not available.
     if (checkConsumerForUpdates(events, mLastFrameNumber,
-            outRefreshStartTime, outGlCompositionDoneTime,
-            outDisplayPresentTime, outDisplayRetireTime, outReleaseTime)) {
+            outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGlCompositionDoneTime, outDisplayPresentTime,
+            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime)) {
         FrameEventHistoryDelta delta;
         mGraphicBufferProducer->getFrameTimestamps(&delta);
         mFrameEventHistory->applyDelta(delta);
@@ -232,7 +246,10 @@
     }
 
     getFrameTimestamp(outRequestedPresentTime, events->requestedPresentTime);
-    getFrameTimestamp(outRefreshStartTime, events->firstRefreshStartTime);
+    getFrameTimestamp(outLatchTime, events->latchTime);
+    getFrameTimestamp(outFirstRefreshStartTime, events->firstRefreshStartTime);
+    getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime);
+    getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime);
 
     getFrameTimestampFence(outAcquireTime, events->acquireFence);
     getFrameTimestampFence(
@@ -941,15 +958,19 @@
     uint32_t framesAgo = va_arg(args, uint32_t);
     nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*);
     nsecs_t* outAcquireTime = va_arg(args, int64_t*);
-    nsecs_t* outRefreshStartTime = va_arg(args, int64_t*);
+    nsecs_t* outLatchTime = va_arg(args, int64_t*);
+    nsecs_t* outFirstRefreshStartTime = va_arg(args, int64_t*);
+    nsecs_t* outLastRefreshStartTime = va_arg(args, int64_t*);
     nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
     nsecs_t* outDisplayPresentTime = va_arg(args, int64_t*);
     nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
+    nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
     nsecs_t* outReleaseTime = va_arg(args, int64_t*);
     return getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
-            outRequestedPresentTime, outAcquireTime, outRefreshStartTime,
+            outRequestedPresentTime, outAcquireTime, outLatchTime,
+            outFirstRefreshStartTime, outLastRefreshStartTime,
             outGlCompositionDoneTime, outDisplayPresentTime,
-            outDisplayRetireTime, outReleaseTime);
+            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
 }
 
 int Surface::connect(int api) {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2206902..e40b4eb 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -357,8 +357,11 @@
         *outSupported = {
                 FrameEvent::REQUESTED_PRESENT,
                 FrameEvent::ACQUIRE,
+                FrameEvent::LATCH,
                 FrameEvent::FIRST_REFRESH_START,
+                FrameEvent::LAST_REFRESH_START,
                 FrameEvent::GL_COMPOSITION_DONE,
+                FrameEvent::DEQUEUE_READY,
                 FrameEvent::RELEASE
         };
         if (mSupportsPresent) {
@@ -522,8 +525,9 @@
               kProducerAcquireTime(frameStartTime + 300),
               kConsumerAcquireTime(frameStartTime + 301),
               kLatchTime(frameStartTime + 500),
-              kRetireTime(frameStartTime + 600),
-              kReleaseTime(frameStartTime + 700),
+              kDequeueReadyTime(frameStartTime + 600),
+              kRetireTime(frameStartTime + 700),
+              kReleaseTime(frameStartTime + 800),
               mRefreshes {
                     { mFenceMap, frameStartTime + 410 },
                     { mFenceMap, frameStartTime + 420 },
@@ -559,6 +563,7 @@
         const nsecs_t kProducerAcquireTime;
         const nsecs_t kConsumerAcquireTime;
         const nsecs_t kLatchTime;
+        const nsecs_t kDequeueReadyTime;
         const nsecs_t kRetireTime;
         const nsecs_t kReleaseTime;
 
@@ -589,13 +594,24 @@
         mFrameTimestampsEnabled = true;
     }
 
+    int getAllFrameTimestamps(uint32_t framesAgo) {
+        return native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+                &outRequestedPresentTime, &outAcquireTime, &outLatchTime,
+                &outFirstRefreshStartTime, &outLastRefreshStartTime,
+                &outGpuCompositionDoneTime, &outDisplayPresentTime,
+                &outDisplayRetireTime, &outDequeueReadyTime, &outReleaseTime);
+    }
+
     void resetTimestamps() {
         outRequestedPresentTime = -1;
         outAcquireTime = -1;
-        outRefreshStartTime = -1;
+        outLatchTime = -1;
+        outFirstRefreshStartTime = -1;
+        outLastRefreshStartTime = -1;
         outGpuCompositionDoneTime = -1;
         outDisplayPresentTime = -1;
         outDisplayRetireTime = -1;
+        outDequeueReadyTime = -1;
         outReleaseTime = -1;
     }
 
@@ -645,6 +661,19 @@
         // that's okay for the purposes of this test.
         std::shared_ptr<FenceTime> gpuDoneFenceTime = FenceTime::NO_FENCE;
 
+        // Composite the previous frame one more time, which helps verify
+        // LastRefresh is updated properly.
+        if (oldFrame != nullptr) {
+            mCfeh->addPreComposition(nOldFrame,
+                                     oldFrame->mRefreshes[2].kStartTime);
+            gpuDoneFenceTime = gpuComposited ?
+                    oldFrame->mRefreshes[2].mGpuCompositionDone.mFenceTime :
+                    FenceTime::NO_FENCE;
+            mCfeh->addPostComposition(nOldFrame, gpuDoneFenceTime,
+                    oldFrame->mRefreshes[2].mPresent.mFenceTime);
+        }
+
+        // Latch the new frame.
         mCfeh->addLatch(nNewFrame, newFrame->kLatchTime);
 
         mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[0].kStartTime);
@@ -654,7 +683,7 @@
         // HWC2 releases the previous buffer after a new latch just before
         // calling postComposition.
         if (oldFrame != nullptr) {
-            mCfeh->addRelease(nOldFrame,
+            mCfeh->addRelease(nOldFrame, oldFrame->kDequeueReadyTime,
                     std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
         }
         mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
@@ -671,12 +700,6 @@
                 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(
@@ -697,10 +720,13 @@
 
     int64_t outRequestedPresentTime = -1;
     int64_t outAcquireTime = -1;
-    int64_t outRefreshStartTime = -1;
+    int64_t outLatchTime = -1;
+    int64_t outFirstRefreshStartTime = -1;
+    int64_t outLastRefreshStartTime = -1;
     int64_t outGpuCompositionDoneTime = -1;
     int64_t outDisplayPresentTime = -1;
     int64_t outDisplayRetireTime = -1;
+    int64_t outDequeueReadyTime = -1;
     int64_t outReleaseTime = -1;
 
     FrameEvents mFrames[2] { { mFenceMap, 1000 }, { mFenceMap, 2000 } };
@@ -732,10 +758,7 @@
 
     // 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);
+    int result = getAllFrameTimestamps(framesAgo);
     EXPECT_EQ(INVALID_OPERATION, result);
     EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
 }
@@ -776,10 +799,7 @@
     // 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);
+    int result = getAllFrameTimestamps(framesAgo);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
 }
@@ -831,35 +851,35 @@
     // 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);
+    int result = getAllFrameTimestamps(framesAgo);
     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].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     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].kDequeueReadyTime, outDequeueReadyTime);
     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);
+    result = getAllFrameTimestamps(framesAgo);
     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].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
     EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 }
 
@@ -881,7 +901,7 @@
     int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -893,7 +913,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -909,7 +929,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -921,7 +941,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -950,7 +970,9 @@
     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);
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+            nullptr, nullptr, nullptr);
+    EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
 }
 
@@ -978,18 +1000,18 @@
     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);
+    int result = getAllFrameTimestamps(framesAgo);
     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(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
     EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
     // Verify available timestamps are correct for frame 1 again, before any
@@ -998,18 +1020,18 @@
     framesAgo = 1;
     resetTimestamps();
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
-    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
-            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
-            &outGpuCompositionDoneTime, &outDisplayPresentTime,
-            &outDisplayRetireTime, &outReleaseTime);
+    result = getAllFrameTimestamps(framesAgo);
     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].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
     EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
     // Signal the fences for frame 1.
@@ -1020,19 +1042,19 @@
     framesAgo = 1;
     resetTimestamps();
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
-    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
-            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
-            &outGpuCompositionDoneTime, &outDisplayPresentTime,
-            &outDisplayRetireTime, &outReleaseTime);
+    result = getAllFrameTimestamps(framesAgo);
     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].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     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].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 }
 
@@ -1062,18 +1084,18 @@
     // 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);
+    int result = getAllFrameTimestamps(framesAgo);
     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(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
     EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
     // Signal the fences for frame 1.
@@ -1084,23 +1106,23 @@
     // sync call.
     resetTimestamps();
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
-    result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
-            &outRequestedPresentTime, &outAcquireTime, &outRefreshStartTime,
-            &outGpuCompositionDoneTime, &outDisplayPresentTime,
-            &outDisplayRetireTime, &outReleaseTime);
+    result = getAllFrameTimestamps(framesAgo);
     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].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
     EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     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.
+// This test verifies that if the certain timestamps can't possibly exist for
+// the most recent frame, then a sync call is not done.
 TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
     enableFrameTimestamps();
     mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
@@ -1123,18 +1145,18 @@
     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);
+    int result = getAllFrameTimestamps(framesAgo);
     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(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
     EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
     mFrames[0].signalRefreshFences();
@@ -1142,24 +1164,25 @@
     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.
+    // Even though the lastRefresh, retire, dequeueReady, and release times aren't
+    // available, a sync call should not occur because it's not possible for f2
+    // to encounter the final value for those events 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);
+    result = getAllFrameTimestamps(framesAgo);
     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(mFrames[1].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
     EXPECT_EQ(0, outDisplayRetireTime);
+    EXPECT_EQ(0, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 }
 
@@ -1181,10 +1204,10 @@
     resetTimestamps();
     int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
-            nullptr, nullptr, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
             displayPresentSupported ? nullptr : &outDisplayPresentTime,
             displayRetireSupported ? nullptr : &outDisplayRetireTime,
-            nullptr);
+            nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(BAD_VALUE, result);
     EXPECT_EQ(-1, outDisplayRetireTime);
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index a1dda3a..02d4137 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <ui/Fence.h>
+
 #define LOG_TAG "Fence"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
@@ -25,9 +27,10 @@
 #include <sync/sync.h>
 #pragma clang diagnostic pop
 
-#include <ui/Fence.h>
+#include <sys/types.h>
 #include <unistd.h>
 #include <utils/Log.h>
+#include <utils/String8.h>
 #include <utils/Trace.h>
 
 namespace android {
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index edcec99..8106b16 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -17,6 +17,7 @@
 #include <ui/FenceTime.h>
 
 #include <cutils/compiler.h>  // For CC_[UN]LIKELY
+#include <utils/Log.h>
 #include <inttypes.h>
 #include <stdlib.h>
 
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 874e712..8b754d5 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -634,11 +634,14 @@
 #define EGL_TIMESTAMPS_ANDROID 0x314D
 #define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
 #define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
-#define EGL_COMPOSITION_START_TIME_ANDROID 0x3430
-#define EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431
-#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3432
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3433
-#define EGL_READS_DONE_TIME_ANDROID 0x3434
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
+#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
+#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
+#define EGL_READS_DONE_TIME_ANDROID 0x3157
 #ifdef EGL_EGLEXT_PROTOTYPES
 EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
 EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c4541a2..97343a1 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -2041,10 +2041,13 @@
 
     nsecs_t* requestedPresentTime = nullptr;
     nsecs_t* acquireTime = nullptr;
-    nsecs_t* refreshStartTime = nullptr;
+    nsecs_t* latchTime = nullptr;
+    nsecs_t* firstRefreshStartTime = nullptr;
     nsecs_t* GLCompositionDoneTime = nullptr;
+    nsecs_t* lastRefreshStartTime = nullptr;
     nsecs_t* displayPresentTime = nullptr;
     nsecs_t* displayRetireTime = nullptr;
+    nsecs_t* dequeueReadyTime = nullptr;
     nsecs_t* releaseTime = nullptr;
 
     for (int i = 0; i < numTimestamps; i++) {
@@ -2055,10 +2058,16 @@
             case EGL_RENDERING_COMPLETE_TIME_ANDROID:
                 acquireTime = &values[i];
                 break;
-            case EGL_COMPOSITION_START_TIME_ANDROID:
-                refreshStartTime = &values[i];
+            case EGL_COMPOSITION_LATCH_TIME_ANDROID:
+                latchTime = &values[i];
                 break;
-            case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
+            case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
+                firstRefreshStartTime = &values[i];
+                break;
+            case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
+                lastRefreshStartTime = &values[i];
+                break;
+            case EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID:
                 GLCompositionDoneTime = &values[i];
                 break;
             case EGL_DISPLAY_PRESENT_TIME_ANDROID:
@@ -2067,6 +2076,9 @@
             case EGL_DISPLAY_RETIRE_TIME_ANDROID:
                 displayRetireTime = &values[i];
                 break;
+            case EGL_DEQUEUE_READY_TIME_ANDROID:
+                dequeueReadyTime = &values[i];
+                break;
             case EGL_READS_DONE_TIME_ANDROID:
                 releaseTime = &values[i];
                 break;
@@ -2076,9 +2088,9 @@
     }
 
     status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo,
-            requestedPresentTime, acquireTime, refreshStartTime,
-            GLCompositionDoneTime, displayPresentTime, displayRetireTime,
-            releaseTime);
+            requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
+            lastRefreshStartTime, GLCompositionDoneTime, displayPresentTime,
+            displayRetireTime, dequeueReadyTime, releaseTime);
 
     switch (ret) {
       case NO_ERROR:
@@ -2122,8 +2134,11 @@
 #if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
         case EGL_REQUESTED_PRESENT_TIME_ANDROID:
         case EGL_RENDERING_COMPLETE_TIME_ANDROID:
-        case EGL_COMPOSITION_START_TIME_ANDROID:
-        case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
+        case EGL_COMPOSITION_LATCH_TIME_ANDROID:
+        case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
+        case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
+        case EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID:
+        case EGL_DEQUEUE_READY_TIME_ANDROID:
         case EGL_READS_DONE_TIME_ANDROID:
             return EGL_TRUE;
         case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index b5b6eb5..7aa0d30 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -69,11 +69,14 @@
     EGL_TIMESTAMPS_ANDROID 0x314D
     EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
     EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
-    EGL_COMPOSITION_START_TIME_ANDROID 0x3430
-    EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431
-    EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3432
-    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3433
-    EGL_READS_DONE_TIME_ANDROID 0x3434
+    EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
+    EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
+    EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
+    EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
+    EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
+    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
+    EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
+    EGL_READS_DONE_TIME_ANDROID 0x3157
 
 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
 "Surface Attributes", page 43:
@@ -119,16 +122,31 @@
           this will correspond to buffer's queue time.
         - EGL_RENDERING_COMPLETE_TIME_ANDROID - The time when all of the
           application's rendering to the surface was completed.
-        - EGL_COMPOSITION_START_TIME_ANDROID - The time at which the compositor
-          began preparing composition for this frame.
-        - EGL_COMPOSITION_FINISHED_TIME_ANDROID - The time at which the
+        - EGL_COMPOSITION_LATCH_TIME_ANDROID - The time when the compositor
+          selected this frame as the one to use for the next composition. The
+          latch is the earliest indication that the frame was submitted in time
+          to be composited.
+        - EGL_FIRST_COMPOSITION_START_TIME_ANDROID - The first time at which
+          the compositor began preparing composition for this frame.
+        - EGL_LAST_COMPOSITION_START_TIME_ANDROID - The last time at which the
+          compositor began preparing composition for this frame. If this frame
+          is composited only once, it will have the same value as
+          EGL_FIRST_COMPOSITION_START_TIME_ANDROID. If the value is not equal,
+          that indicates the subsequent frame was not submitted in time to be
+          latched by the compositor. Note: The value may not be updated for
+          every display refresh if the compositor becomes idle.
+        - EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID - The time at which the
           compositor's rendering work for this frame finished. This will be zero
           if composition was handled by the display and the compositor didn't do
           any rendering.
         - EGL_DISPLAY_PRESENT_TIME_ANDROID - The time at which this frame
-          started to scan out on the physical display.
+          started to scan out to the physical display.
         - EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was
           replaced by the next frame on-screen.
+        - EGL_DEQUEUE_READY_TIME_ANDROID - The time when the buffer became
+          available for reuse as a buffer the client can target without
+          blocking. This is generally the point when all read commands of the
+          buffer have been submitted, but not necessarily completed.
         - EGL_READS_DONE_TIME_ANDROID - The time at which all reads for the
           purpose of display/composition were completed for this frame.
 
@@ -152,3 +170,8 @@
 #2 (Brian Anderson, July 22, 2016)
     - Replace EGL_QUEUE_TIME_ANDROID with EGL_REQUESTED_PRESENT_TIME_ANDROID.
     - Add DISPLAY_PRESENT_TIME_ANDROID.
+
+#3 (Brian Anderson, November 30, 2016)
+    - Add EGL_COMPOSITION_LATCH_TIME_ANDROID,
+      EGL_LAST_COMPOSITION_START_TIME_ANDROID, and
+      EGL_DEQUEUE_READY_TIME_ANDROID.
diff --git a/opengl/specs/README b/opengl/specs/README
index 1ee99fb..8a3a7aa 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -22,9 +22,12 @@
 0x314D               EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
 0x314E               EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
 0x314F               EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3430               EGL_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3431               EGL_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3432               EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3433               EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3434               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3435 - 0x343F      (unused)
+0x3150               EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3151               EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3152               EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3153               EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3154               EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3155               EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3156               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3157               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3158 - 0x315F      (unused)
diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h
index f2e6491..d56b1c8 100644
--- a/services/surfaceflinger/Colorizer.h
+++ b/services/surfaceflinger/Colorizer.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_SURFACE_FLINGER_COLORIZER_H
 #define ANDROID_SURFACE_FLINGER_COLORIZER_H
 
+#include <utils/String8.h>
+
 namespace android {
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9eaf57b..72f6a7e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1796,7 +1796,7 @@
 }
 
 #ifdef USE_HWC2
-void Layer::releasePendingBuffer() {
+void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
     mSurfaceFlingerConsumer->releasePendingBuffer();
     auto releaseFenceTime = std::make_shared<FenceTime>(
             mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
@@ -1804,7 +1804,7 @@
 
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     mFrameEventHistory.addRelease(
-            mPreviousFrameNumber, std::move(releaseFenceTime));
+            mPreviousFrameNumber, dequeueReadyTime, std::move(releaseFenceTime));
 }
 #endif
 
@@ -1981,7 +1981,7 @@
                 mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
         mReleaseTimeline.push(releaseFenceTime);
         mFrameEventHistory.addRelease(
-                mPreviousFrameNumber, std::move(releaseFenceTime));
+                mPreviousFrameNumber, latchTime, std::move(releaseFenceTime));
 #endif
     }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c3eab37..92d2292 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -286,7 +286,7 @@
 
 #ifdef USE_HWC2
     // If a buffer was replaced this frame, release the former buffer
-    void releasePendingBuffer();
+    void releasePendingBuffer(nsecs_t dequeueReadyTime);
 #endif
 
     /*
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index db6b366..5f25ef5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -575,10 +575,13 @@
     *outSupported = {
         FrameEvent::REQUESTED_PRESENT,
         FrameEvent::ACQUIRE,
+        FrameEvent::LATCH,
         FrameEvent::FIRST_REFRESH_START,
+        FrameEvent::LAST_REFRESH_START,
         FrameEvent::GL_COMPOSITION_DONE,
         getHwComposer().presentFenceRepresentsStartOfScanout() ?
                 FrameEvent::DISPLAY_PRESENT : FrameEvent::DISPLAY_RETIRE,
+        FrameEvent::DEQUEUE_READY,
         FrameEvent::RELEASE,
     };
     return NO_ERROR;
@@ -1226,8 +1229,9 @@
     ALOGV("postComposition");
 
     // Release any buffers which were replaced this frame
+    nsecs_t dequeueReadyTime = systemTime();
     for (auto& layer : mLayersWithQueuedFrames) {
-        layer->releasePendingBuffer();
+        layer->releasePendingBuffer(dequeueReadyTime);
     }
 
     const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0d05e9e..fcf0185 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -608,9 +608,12 @@
     *outSupported = {
         FrameEvent::REQUESTED_PRESENT,
         FrameEvent::ACQUIRE,
+        FrameEvent::LATCH,
         FrameEvent::FIRST_REFRESH_START,
+        FrameEvent::LAST_REFRESH_START,
         FrameEvent::GL_COMPOSITION_DONE,
         FrameEvent::DISPLAY_RETIRE,
+        FrameEvent::DEQUEUE_READY,
         FrameEvent::RELEASE,
     };
     return NO_ERROR;