Merge "Fix typo on function comment"
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 17352cc..b8bfcd7 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -22,23 +22,25 @@
 
 namespace android {
 
-struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
-    FrameTimestamps() :
-        frameNumber(0),
-        requestedPresentTime(0),
-        acquireTime(0),
-        refreshStartTime(0),
-        glCompositionDoneTime(0),
-        displayRetireTime(0),
-        releaseTime(0) {}
+enum class SupportableFrameTimestamps {
+    REQUESTED_PRESENT,
+    ACQUIRE,
+    REFRESH_START,
+    GL_COMPOSITION_DONE_TIME,
+    DISPLAY_PRESENT_TIME,
+    DISPLAY_RETIRE_TIME,
+    RELEASE_TIME,
+};
 
-    uint64_t frameNumber;
-    nsecs_t requestedPresentTime;
-    nsecs_t acquireTime;
-    nsecs_t refreshStartTime;
-    nsecs_t glCompositionDoneTime;
-    nsecs_t displayRetireTime;
-    nsecs_t releaseTime;
+struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
+    uint64_t frameNumber{0};
+    nsecs_t requestedPresentTime{0};
+    nsecs_t acquireTime{0};
+    nsecs_t refreshStartTime{0};
+    nsecs_t glCompositionDoneTime{0};
+    nsecs_t displayPresentTime{0};
+    nsecs_t displayRetireTime{0};
+    nsecs_t releaseTime{0};
 };
 
 } // namespace android
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index a3ee798..bc36970 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -32,6 +32,8 @@
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposerClient.h>
 
+#include <vector>
+
 namespace android {
 // ----------------------------------------------------------------------------
 
@@ -43,6 +45,7 @@
 class IDisplayEventConnection;
 class IMemoryHeap;
 class Rect;
+enum class SupportableFrameTimestamps;
 
 /*
  * This class defines the Binder IPC interface for accessing various
@@ -112,6 +115,11 @@
     virtual bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& surface) const = 0;
 
+    /* Returns the frame timestamps supported by SurfaceFlinger.
+     */
+    virtual status_t getSupportedFrameTimestamps(
+            std::vector<SupportableFrameTimestamps>* outSupported) const = 0;
+
     /* set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
      * requires ACCESS_SURFACE_FLINGER permission.
@@ -193,6 +201,7 @@
         GET_BUILT_IN_DISPLAY,
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
+        GET_SUPPORTED_FRAME_TIMESTAMPS,
         GET_DISPLAY_CONFIGS,
         GET_ACTIVE_CONFIG,
         SET_ACTIVE_CONFIG,
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 470992c..aa5657f 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -135,10 +135,11 @@
             sp<Fence>* outFence, float outTransformMatrix[16]);
 
     // See IGraphicBufferProducer::getFrameTimestamps
-    bool getFrameTimestamps(uint64_t frameNumber,
+    status_t getFrameTimestamps(uint64_t frameNumber,
             nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
             nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
-            nsecs_t* outDisplayRetireTime, nsecs_t* outReleaseTime);
+            nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
+            nsecs_t* outReleaseTime);
 
     status_t getUniqueId(uint64_t* outId) const;
 
@@ -238,6 +239,8 @@
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
 
 private:
+    void querySupportedTimestampsLocked() const;
+
     void freeAllBuffers();
     int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
 
@@ -380,6 +383,11 @@
     Condition mQueueBufferCondition;
 
     uint64_t mNextFrameNumber;
+
+    // Mutable because ANativeWindow::query needs this class const.
+    mutable bool mQueriedSupportedTimestamps;
+    mutable bool mFrameTimestampsSupportsPresent;
+    mutable bool mFrameTimestampsSupportsRetire;
 };
 
 namespace view {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6c1662c..b5fe266 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -158,6 +158,50 @@
         return result != 0;
     }
 
+    virtual status_t getSupportedFrameTimestamps(
+            std::vector<SupportableFrameTimestamps>* outSupported) const {
+        if (!outSupported) {
+            return UNEXPECTED_NULL;
+        }
+        outSupported->clear();
+
+        Parcel data, reply;
+
+        status_t err = data.writeInterfaceToken(
+                ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = remote()->transact(
+                BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
+                data, &reply);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        std::vector<int32_t> supported;
+        err = reply.readInt32Vector(&supported);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        outSupported->reserve(supported.size());
+        for (int32_t s : supported) {
+            outSupported->push_back(static_cast<SupportableFrameTimestamps>(s));
+        }
+        return NO_ERROR;
+    }
+
     virtual sp<IDisplayEventConnection> createDisplayEventConnection()
     {
         Parcel data, reply;
@@ -520,6 +564,25 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case GET_SUPPORTED_FRAME_TIMESTAMPS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            std::vector<SupportableFrameTimestamps> supportedTimestamps;
+            status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
+            status_t err = reply->writeInt32(result);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            if (result != NO_ERROR) {
+                return result;
+            }
+
+            std::vector<int32_t> supported;
+            supported.reserve(supportedTimestamps.size());
+            for (SupportableFrameTimestamps s : supportedTimestamps) {
+                supported.push_back(static_cast<int32_t>(s));
+            }
+            return reply->writeInt32Vector(supported);
+        }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IDisplayEventConnection> connection(createDisplayEventConnection());
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ac93c53..5203cce 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -49,7 +49,10 @@
       mAutoRefresh(false),
       mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
       mSharedBufferHasBeenQueued(false),
-      mNextFrameNumber(1)
+      mNextFrameNumber(1),
+      mQueriedSupportedTimestamps(false),
+      mFrameTimestampsSupportsPresent(false),
+      mFrameTimestampsSupportsRetire(false)
 {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
@@ -135,37 +138,57 @@
             outTransformMatrix);
 }
 
-bool Surface::getFrameTimestamps(uint64_t frameNumber,
+status_t Surface::getFrameTimestamps(uint64_t frameNumber,
         nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
         nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
-        nsecs_t* outDisplayRetireTime, nsecs_t* outReleaseTime) {
+        nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
+        nsecs_t* outReleaseTime) {
     ATRACE_CALL();
 
+    {
+        Mutex::Autolock lock(mMutex);
+
+        // Verify the requested timestamps are supported.
+        querySupportedTimestampsLocked();
+        if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
+            return BAD_VALUE;
+        }
+        if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
+            return BAD_VALUE;
+        }
+    }
+
     FrameTimestamps timestamps;
     bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
             &timestamps);
-    if (found) {
-        if (outRequestedPresentTime) {
-            *outRequestedPresentTime = timestamps.requestedPresentTime;
-        }
-        if (outAcquireTime) {
-            *outAcquireTime = timestamps.acquireTime;
-        }
-        if (outRefreshStartTime) {
-            *outRefreshStartTime = timestamps.refreshStartTime;
-        }
-        if (outGlCompositionDoneTime) {
-            *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
-        }
-        if (outDisplayRetireTime) {
-            *outDisplayRetireTime = timestamps.displayRetireTime;
-        }
-        if (outReleaseTime) {
-            *outReleaseTime = timestamps.releaseTime;
-        }
-        return true;
+
+    if (!found) {
+        return NAME_NOT_FOUND;
     }
-    return false;
+
+    if (outRequestedPresentTime) {
+        *outRequestedPresentTime = timestamps.requestedPresentTime;
+    }
+    if (outAcquireTime) {
+        *outAcquireTime = timestamps.acquireTime;
+    }
+    if (outRefreshStartTime) {
+        *outRefreshStartTime = timestamps.refreshStartTime;
+    }
+    if (outGlCompositionDoneTime) {
+        *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
+    }
+    if (outDisplayPresentTime) {
+        *outDisplayPresentTime = timestamps.displayPresentTime;
+    }
+    if (outDisplayRetireTime) {
+        *outDisplayRetireTime = timestamps.displayRetireTime;
+    }
+    if (outReleaseTime) {
+        *outReleaseTime = timestamps.releaseTime;
+    }
+
+    return NO_ERROR;
 }
 
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
@@ -533,6 +556,32 @@
     return err;
 }
 
+void Surface::querySupportedTimestampsLocked() const {
+    // mMutex must be locked when calling this method.
+
+    if (mQueriedSupportedTimestamps) {
+        return;
+    }
+    mQueriedSupportedTimestamps = true;
+
+    std::vector<SupportableFrameTimestamps> supportedFrameTimestamps;
+    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+    status_t err = composer->getSupportedFrameTimestamps(
+            &supportedFrameTimestamps);
+
+    if (err != NO_ERROR) {
+        return;
+    }
+
+    for (auto sft : supportedFrameTimestamps) {
+        if (sft == SupportableFrameTimestamps::DISPLAY_PRESENT_TIME) {
+            mFrameTimestampsSupportsPresent = true;
+        } else if (sft == SupportableFrameTimestamps::DISPLAY_RETIRE_TIME) {
+            mFrameTimestampsSupportsRetire = true;
+        }
+    }
+}
+
 int Surface::query(int what, int* value) const {
     ATRACE_CALL();
     ALOGV("Surface::query");
@@ -595,6 +644,16 @@
                         static_cast<int>(durationUs);
                 return NO_ERROR;
             }
+            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: {
+                querySupportedTimestampsLocked();
+                *value = mFrameTimestampsSupportsPresent ? 1 : 0;
+                return NO_ERROR;
+            }
+            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE: {
+                querySupportedTimestampsLocked();
+                *value = mFrameTimestampsSupportsRetire ? 1 : 0;
+                return NO_ERROR;
+            }
         }
     }
     return mGraphicBufferProducer->query(what, value);
@@ -799,12 +858,13 @@
     nsecs_t* outAcquireTime = va_arg(args, int64_t*);
     nsecs_t* outRefreshStartTime = 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* outReleaseTime = va_arg(args, int64_t*);
-    bool ret = getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
+    return getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
             outRequestedPresentTime, outAcquireTime, outRefreshStartTime,
-            outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
-    return ret ? NO_ERROR : BAD_VALUE;
+            outGlCompositionDoneTime, outDisplayPresentTime,
+            outDisplayRetireTime, outReleaseTime);
 }
 
 int Surface::connect(int api) {
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index c2fa43f..73e5e07 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -636,8 +636,9 @@
 #define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
 #define EGL_COMPOSITION_START_TIME_ANDROID 0x3430
 #define EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3432
-#define EGL_READS_DONE_TIME_ANDROID 0x3433
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3432
+#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3433
+#define EGL_READS_DONE_TIME_ANDROID 0x3434
 #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 1acdeb08..d5a02e3 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1204,6 +1204,9 @@
     egl_surface_t * const s = get_surface(surface);
 
     if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
+        if (!s->win.get()) {
+            setError(EGL_BAD_SURFACE, EGL_FALSE);
+        }
         int err = native_window_set_auto_refresh(s->win.get(),
             value ? true : false);
         return (err == NO_ERROR) ? EGL_TRUE :
@@ -1212,8 +1215,14 @@
 
 #if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
     if (attribute == EGL_TIMESTAMPS_ANDROID) {
+        if (!s->win.get()) {
+            return setError(EGL_BAD_SURFACE, EGL_FALSE);
+        }
         s->enableTimestamps = value;
-        return EGL_TRUE;
+        int err = native_window_enable_frame_timestamps(
+                s->win.get(), value ? true : false);
+        return (err == NO_ERROR) ? EGL_TRUE :
+            setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 #endif
 
@@ -2021,27 +2030,25 @@
 
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) {
-        setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        return EGL_FALSE;
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     }
 
     SurfaceRef _s(dp.get(), surface);
     if (!_s.get()) {
-        setError(EGL_BAD_SURFACE, EGL_FALSE);
-        return EGL_FALSE;
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
     egl_surface_t const * const s = get_surface(surface);
 
     if (!s->enableTimestamps) {
-        setError(EGL_BAD_SURFACE, EGL_FALSE);
-        return EGL_FALSE;
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
     nsecs_t* requestedPresentTime = nullptr;
     nsecs_t* acquireTime = nullptr;
     nsecs_t* refreshStartTime = nullptr;
     nsecs_t* GLCompositionDoneTime = nullptr;
+    nsecs_t* displayPresentTime = nullptr;
     nsecs_t* displayRetireTime = nullptr;
     nsecs_t* releaseTime = nullptr;
 
@@ -2059,6 +2066,9 @@
             case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
                 GLCompositionDoneTime = &values[i];
                 break;
+            case EGL_DISPLAY_PRESENT_TIME_ANDROID:
+                displayPresentTime = &values[i];
+                break;
             case EGL_DISPLAY_RETIRE_TIME_ANDROID:
                 displayRetireTime = &values[i];
                 break;
@@ -2066,21 +2076,27 @@
                 releaseTime = &values[i];
                 break;
             default:
-                setError(EGL_BAD_PARAMETER, EGL_FALSE);
-                return EGL_FALSE;
+                return setError(EGL_BAD_PARAMETER, EGL_FALSE);
         }
     }
 
     status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo,
             requestedPresentTime, acquireTime, refreshStartTime,
-            GLCompositionDoneTime, displayRetireTime, releaseTime);
+            GLCompositionDoneTime, displayPresentTime, displayRetireTime,
+            releaseTime);
 
-    if (ret != NO_ERROR) {
-        setError(EGL_BAD_ACCESS, EGL_FALSE);
-        return EGL_FALSE;
+    switch (ret) {
+      case NO_ERROR:
+        return EGL_TRUE;
+      case NAME_NOT_FOUND:
+        return setError(EGL_BAD_ACCESS, EGL_FALSE);
+      case BAD_VALUE:
+        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+      default:
+        // This should not happen. Return an error that is not in the spec
+        // so it's obvious something is very wrong.
+        return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
     }
-
-    return EGL_TRUE;
 }
 
 EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface,
@@ -2090,14 +2106,19 @@
 
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) {
-        setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        return EGL_FALSE;
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     }
 
     SurfaceRef _s(dp.get(), surface);
     if (!_s.get()) {
-        setError(EGL_BAD_SURFACE, EGL_FALSE);
-        return EGL_FALSE;
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    }
+
+    egl_surface_t const * const s = get_surface(surface);
+
+    ANativeWindow* window = s->win.get();
+    if (!window) {
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
     switch (timestamp) {
@@ -2106,9 +2127,20 @@
         case EGL_RENDERING_COMPLETE_TIME_ANDROID:
         case EGL_COMPOSITION_START_TIME_ANDROID:
         case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
-        case EGL_DISPLAY_RETIRE_TIME_ANDROID:
         case EGL_READS_DONE_TIME_ANDROID:
             return EGL_TRUE;
+        case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
+            int value = 0;
+            window->query(window,
+                    NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
+            return value == 0 ? EGL_FALSE : EGL_TRUE;
+        }
+        case EGL_DISPLAY_RETIRE_TIME_ANDROID: {
+            int value = 0;
+            window->query(window,
+                    NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &value);
+            return value == 0 ? EGL_FALSE : EGL_TRUE;
+        }
 #endif
         default:
             return EGL_FALSE;
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index 0882cef..b5b6eb5 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -38,8 +38,8 @@
     and display of window surfaces.
 
     Some examples of how this might be used:
-        - The display retire time can be used to calculate end-to-end latency of
-          the entire graphics pipeline.
+        - The display present or retire time can be used to calculate end-to-end
+          latency of the entire graphics pipeline.
         - The queue time and rendering complete time can be used to determine
           how long the application's rendering took to complete. Likewise, the
           composition start time and finish time can be used to determine how
@@ -71,8 +71,9 @@
     EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
     EGL_COMPOSITION_START_TIME_ANDROID 0x3430
     EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431
-    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3432
-    EGL_READS_DONE_TIME_ANDROID 0x3433
+    EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3432
+    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3433
+    EGL_READS_DONE_TIME_ANDROID 0x3434
 
 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
 "Surface Attributes", page 43:
@@ -124,12 +125,14 @@
           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.
         - EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was
           replaced by the next frame on-screen.
         - EGL_READS_DONE_TIME_ANDROID - The time at which all reads for the
           purpose of display/composition were completed for this frame.
 
-    Not all implementations may support all off the above timestamp queries. The
+    Not all implementations may support all of the above timestamp queries. The
     function
 
         EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
@@ -148,4 +151,4 @@
 
 #2 (Brian Anderson, July 22, 2016)
     - Replace EGL_QUEUE_TIME_ANDROID with EGL_REQUESTED_PRESENT_TIME_ANDROID.
-
+    - Add DISPLAY_PRESENT_TIME_ANDROID.
diff --git a/opengl/specs/README b/opengl/specs/README
index 8414d05..1ee99fb 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -24,6 +24,7 @@
 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_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3433               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3434 - 0x343F      (unused)
+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)
diff --git a/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java b/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java
index c966e11..57338c7 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java
@@ -1,5 +1,9 @@
     // C function void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params )
 
+    /**
+     * The {@link java.nio.Buffer} instance returned by this method is guaranteed
+     * to be an instance of {@link java.nio.ByteBuffer}.
+     */
     public static native java.nio.Buffer glGetBufferPointerv(
         int target,
         int pname
diff --git a/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java b/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java
index 482ea99..7b1966b 100644
--- a/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java
+++ b/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java
@@ -1,5 +1,9 @@
     // C function GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access )
 
+    /**
+     * The {@link java.nio.Buffer} instance returned by this method is guaranteed
+     * to be an instance of {@link java.nio.ByteBuffer}.
+     */
     public static native java.nio.Buffer glMapBufferRange(
         int target,
         int offset,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 82a900c..f0520c6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -309,22 +309,22 @@
     return layer;
 }
 
-nsecs_t HWComposer::getRefreshTimestamp(int32_t disp) const {
+nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
     // this returns the last refresh timestamp.
     // if the last one is not available, we estimate it based on
     // the refresh period and whatever closest timestamp we have.
     Mutex::Autolock _l(mLock);
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    auto vsyncPeriod = getActiveConfig(disp)->getVsyncPeriod();
-    return now - ((now - mLastHwVSync[disp]) % vsyncPeriod);
+    auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod();
+    return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod);
 }
 
-bool HWComposer::isConnected(int32_t disp) const {
-    if (!isValidDisplay(disp)) {
-        ALOGE("isConnected: Attempted to access invalid display %d", disp);
+bool HWComposer::isConnected(int32_t displayId) const {
+    if (!isValidDisplay(displayId)) {
+        ALOGE("isConnected: Attempted to access invalid display %d", displayId);
         return false;
     }
-    return mDisplayData[disp].hwcDisplay->isConnected();
+    return mDisplayData[displayId].hwcDisplay->isConnected();
 }
 
 std::vector<std::shared_ptr<const HWC2::Display::Config>>
@@ -408,14 +408,15 @@
 }
 
 
-void HWComposer::setVsyncEnabled(int32_t disp, HWC2::Vsync enabled) {
-    if (disp < 0 || disp >= HWC_DISPLAY_VIRTUAL) {
-        ALOGD("setVsyncEnabled: Ignoring for virtual display %d", disp);
+void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
+    if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) {
+        ALOGD("setVsyncEnabled: Ignoring for virtual display %d", displayId);
         return;
     }
 
-    if (!isValidDisplay(disp)) {
-        ALOGE("setVsyncEnabled: Attempted to access invalid display %d", disp);
+    if (!isValidDisplay(displayId)) {
+        ALOGE("setVsyncEnabled: Attempted to access invalid display %d",
+               displayId);
         return;
     }
 
@@ -424,7 +425,7 @@
     // that even if HWC blocks (which it shouldn't), it won't
     // affect other threads.
     Mutex::Autolock _l(mVsyncLock);
-    auto& displayData = mDisplayData[disp];
+    auto& displayData = mDisplayData[displayId];
     if (enabled != displayData.vsyncEnabled) {
         ATRACE_CALL();
         auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
@@ -432,12 +433,12 @@
             displayData.vsyncEnabled = enabled;
 
             char tag[16];
-            snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
+            snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
             ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
         } else {
             ALOGE("setVsyncEnabled: Failed to set vsync to %s on %d/%" PRIu64
-                    ": %s (%d)", to_string(enabled).c_str(), disp,
-                    mDisplayData[disp].hwcDisplay->getId(),
+                    ": %s (%d)", to_string(enabled).c_str(), displayId,
+                    mDisplayData[displayId].hwcDisplay->getId(),
                     to_string(error).c_str(), static_cast<int32_t>(error));
         }
     }
@@ -601,6 +602,10 @@
     return mDisplayData[displayId].lastRetireFence;
 }
 
+bool HWComposer::retireFenceRepresentsStartOfScanout() const {
+    return mAdapter ? false : true;
+}
+
 sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
         const std::shared_ptr<HWC2::Layer>& layer) const {
     if (!isValidDisplay(displayId)) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 41671f6..9d03e94 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -122,6 +122,11 @@
     // last call to presentDisplay
     sp<Fence> getRetireFence(int32_t displayId) const;
 
+    // Returns true if the retire fence represents the start of the display
+    // controller's scan out. This should be true for all HWC2 implementations,
+    // except for the wrapper around HWC1 implementations.
+    bool retireFenceRepresentsStartOfScanout() const;
+
     // Get last release fence for the given layer
     sp<Fence> getLayerReleaseFence(int32_t displayId,
             const std::shared_ptr<HWC2::Layer>& layer) const;
@@ -140,12 +145,12 @@
 
     // Events handling ---------------------------------------------------------
 
-    void setVsyncEnabled(int32_t disp, HWC2::Vsync enabled);
+    void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
 
     // Query display parameters.  Pass in a display index (e.g.
     // HWC_DISPLAY_PRIMARY).
-    nsecs_t getRefreshTimestamp(int32_t disp) const;
-    bool isConnected(int32_t disp) const;
+    nsecs_t getRefreshTimestamp(int32_t displayId) const;
+    bool isConnected(int32_t displayId) const;
 
     // Non-const because it can update configMap inside of mDisplayData
     std::vector<std::shared_ptr<const HWC2::Display::Config>>
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
index 276890d..742c00d 100644
--- a/services/surfaceflinger/FenceTracker.cpp
+++ b/services/surfaceflinger/FenceTracker.cpp
@@ -48,12 +48,21 @@
         } else if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
             outString->append("- GLES done\tNot signaled\n");
         }
+
+        if (frame.presentTime) {
+            outString->appendFormat("- Present\t%" PRId64 "\n",
+                    frame.presentTime);
+        } else if (frame.presentFence != Fence::NO_FENCE) {
+            outString->append("- Present\tNot signaled\n");
+        }
+
         if (frame.retireTime) {
             outString->appendFormat("- Retire\t%" PRId64 "\n",
                     frame.retireTime);
-        } else {
+        } else if (frame.retireFence != Fence::NO_FENCE) {
             outString->append("- Retire\tNot signaled\n");
         }
+
         for (const auto& kv : frame.layers) {
             const LayerRecord& layer = kv.second;
             outString->appendFormat("-- %s\n", layer.name.string());
@@ -85,6 +94,13 @@
 void FenceTracker::checkFencesForCompletion() {
     ATRACE_CALL();
     for (auto& frame : mFrames) {
+        if (frame.presentFence != Fence::NO_FENCE) {
+            nsecs_t time = frame.presentFence->getSignalTime();
+            if (isValidTimestamp(time)) {
+                frame.presentTime = time;
+                frame.presentFence = Fence::NO_FENCE;
+            }
+        }
         if (frame.retireFence != Fence::NO_FENCE) {
             nsecs_t time = frame.retireFence->getSignalTime();
             if (isValidTimestamp(time)) {
@@ -119,8 +135,9 @@
     }
 }
 
-void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
-        const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence) {
+void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> presentFence,
+        sp<Fence> retireFence, const Vector<sp<Layer>>& layers,
+        sp<Fence> glDoneFence) {
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
     FrameRecord& frame = mFrames[mOffset];
@@ -177,8 +194,10 @@
 
     frame.frameId = mFrameCounter;
     frame.refreshStartTime = refreshStartTime;
+    frame.presentTime = 0;
     frame.retireTime = 0;
     frame.glesCompositionDoneTime = 0;
+    frame.presentFence = presentFence;
     prevFrame.retireFence = retireFence;
     frame.retireFence = Fence::NO_FENCE;
     frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
@@ -212,6 +231,7 @@
     outTimestamps->acquireTime = layerRecord.acquireTime;
     outTimestamps->refreshStartTime = frameRecord.refreshStartTime;
     outTimestamps->glCompositionDoneTime = frameRecord.glesCompositionDoneTime;
+    outTimestamps->displayPresentTime = frameRecord.presentTime;
     outTimestamps->displayRetireTime = frameRecord.retireTime;
     outTimestamps->releaseTime = layerRecord.releaseTime;
     return true;
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
index 385c970..3b429d1 100644
--- a/services/surfaceflinger/FenceTracker.h
+++ b/services/surfaceflinger/FenceTracker.h
@@ -38,8 +38,9 @@
 public:
      FenceTracker();
      void dump(String8* outString);
-     void addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
-             const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence);
+     void addFrame(nsecs_t refreshStartTime, sp<Fence> presentFence,
+             sp<Fence> retireFence, const Vector<sp<Layer>>& layers,
+             sp<Fence> glDoneFence);
      bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
              FrameTimestamps* outTimestamps);
 
@@ -79,18 +80,22 @@
          std::unordered_map<int32_t, LayerRecord> layers;
          // timestamp for when SurfaceFlinger::handleMessageRefresh() was called
          nsecs_t refreshStartTime;
+         // timestamp from the present fence
+         nsecs_t presentTime;
          // timestamp from the retire fence
          nsecs_t retireTime;
          // timestamp from the GLES composition completion fence
          nsecs_t glesCompositionDoneTime;
+         // primary display present fence for this frame
+         sp<Fence> presentFence;
          // primary display retire fence for this frame
          sp<Fence> retireFence;
          // if GLES composition was done, the fence for its completion
          sp<Fence> glesCompositionDoneFence;
 
          FrameRecord() : frameId(0), layers(), refreshStartTime(0),
-                 retireTime(0), glesCompositionDoneTime(0),
-                 retireFence(Fence::NO_FENCE),
+                 presentTime(0), retireTime(0), glesCompositionDoneTime(0),
+                 presentFence(Fence::NO_FENCE), retireFence(Fence::NO_FENCE),
                  glesCompositionDoneFence(Fence::NO_FENCE) {}
      };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 328594b..acde412 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -566,6 +566,21 @@
     return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
 }
 
+status_t SurfaceFlinger::getSupportedFrameTimestamps(
+        std::vector<SupportableFrameTimestamps>* outSupported) const {
+    *outSupported = {
+        SupportableFrameTimestamps::REQUESTED_PRESENT,
+        SupportableFrameTimestamps::ACQUIRE,
+        SupportableFrameTimestamps::REFRESH_START,
+        SupportableFrameTimestamps::GL_COMPOSITION_DONE_TIME,
+        getHwComposer().retireFenceRepresentsStartOfScanout() ?
+                SupportableFrameTimestamps::DISPLAY_PRESENT_TIME :
+                SupportableFrameTimestamps::DISPLAY_RETIRE_TIME,
+        SupportableFrameTimestamps::RELEASE_TIME,
+    };
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
     if ((configs == NULL) || (display.get() == NULL)) {
@@ -1238,7 +1253,17 @@
         }
     }
 
-    mFenceTracker.addFrame(refreshStartTime, presentFence,
+    sp<Fence> fenceTrackerPresentFence;
+    sp<Fence> fenceTrackerRetireFence;
+    if (mHwc->retireFenceRepresentsStartOfScanout()) {
+        fenceTrackerPresentFence = presentFence;
+        fenceTrackerRetireFence = Fence::NO_FENCE;
+    } else {
+        fenceTrackerPresentFence = Fence::NO_FENCE;
+        fenceTrackerRetireFence = presentFence;
+    }
+    mFenceTracker.addFrame(refreshStartTime,
+            fenceTrackerPresentFence, fenceTrackerRetireFence,
             hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
 
     if (mAnimCompositionPending) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3af1754..bdb2614 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -200,6 +200,8 @@
     virtual void bootFinished();
     virtual bool authenticateSurfaceTexture(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
+    virtual status_t getSupportedFrameTimestamps(
+            std::vector<SupportableFrameTimestamps>* outSupported) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection();
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 8e5c565..0143d99 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -599,6 +599,19 @@
     return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
 }
 
+status_t SurfaceFlinger::getSupportedFrameTimestamps(
+        std::vector<SupportableFrameTimestamps>* outSupported) const {
+    *outSupported = {
+        SupportableFrameTimestamps::REQUESTED_PRESENT,
+        SupportableFrameTimestamps::ACQUIRE,
+        SupportableFrameTimestamps::REFRESH_START,
+        SupportableFrameTimestamps::GL_COMPOSITION_DONE_TIME,
+        SupportableFrameTimestamps::DISPLAY_RETIRE_TIME,
+        SupportableFrameTimestamps::RELEASE_TIME,
+    };
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
     if ((configs == NULL) || (display.get() == NULL)) {
@@ -1148,7 +1161,8 @@
         }
     }
 
-    mFenceTracker.addFrame(refreshStartTime, presentFence,
+    // The present fence is actually a retire fence in HWC1.
+    mFenceTracker.addFrame(refreshStartTime, Fence::NO_FENCE, presentFence,
             hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
 
     if (mAnimCompositionPending) {