Merge "BQ: Remove getNextFrameNumber Binder call" into nyc-mr1-dev
diff --git a/docs/Makefile b/docs/Makefile
index 5104d81..c655e0c 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,13 +1,12 @@
 HEADERS := $(wildcard ../include/android/*.h)
 
-all: html jd
+all: html website
 
 html: $(HEADERS) Doxyfile
 	mkdir -p html
 	doxygen
 
-jd: $(HEADERS) Doxyfile header.jd
-	mkdir -p jd
-	HTML_HEADER=header.jd HTML_FOOTER=footer.jd HTML_OUTPUT=jd doxygen
-	for file in jd/*.html; do mv "$${file}" "$${file/.html/.jd}"; done
-	rm -f jd/index.jd
+website: $(HEADERS) Doxyfile header.html
+	mkdir -p website
+	HTML_HEADER=header.html HTML_FOOTER=footer.html HTML_OUTPUT=website doxygen
+	rm -f website/index.html
diff --git a/docs/footer.html b/docs/footer.html
new file mode 100644
index 0000000..308b1d0
--- /dev/null
+++ b/docs/footer.html
@@ -0,0 +1,2 @@
+</body>
+</html>
diff --git a/docs/footer.jd b/docs/footer.jd
deleted file mode 100644
index e69de29..0000000
--- a/docs/footer.jd
+++ /dev/null
diff --git a/docs/header.html b/docs/header.html
new file mode 100644
index 0000000..04727b3
--- /dev/null
+++ b/docs/header.html
@@ -0,0 +1,10 @@
+<html devsite>
+<head>
+  <meta name="top_category" value="ndk" />
+  <meta name="subcategory" value="reference" />
+  <meta name="book_path" value="/ndk/reference/_book.yaml" />
+  <title>$title</title>
+  <link rel="stylesheet" type="text/css" href="doxygen-dac.css">
+</head>
+<body>
+<div id="top"><!-- we must have this tag, it's closed by doxygen. ¯\_(ツ)_/¯ -->
diff --git a/docs/header.jd b/docs/header.jd
deleted file mode 100644
index e50f41b..0000000
--- a/docs/header.jd
+++ /dev/null
@@ -1,3 +0,0 @@
-page.title=$title
-page.customHeadTag=<link rel="stylesheet" type="text/css" href="doxygen-dac.css">
-@jd:body
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 37e2bec..8177ec6 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -198,7 +198,6 @@
     virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
     virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
     virtual int perform(int operation, va_list args);
-    virtual int query(int what, int* value) const;
     virtual int setSwapInterval(int interval);
 
     virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
@@ -224,6 +223,7 @@
     virtual int setAutoRefresh(bool autoRefresh);
     virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
     virtual int unlockAndPost();
+    virtual int query(int what, int* value) const;
 
     virtual int connect(int api, const sp<IProducerListener>& listener);
     virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
@@ -370,6 +370,10 @@
     // used to prevent a mismatch between the number of queue/dequeue calls.
     bool mSharedBufferHasBeenQueued;
 
+    // These are used to satisfy the NATIVE_WINDOW_LAST_*_DURATION queries
+    nsecs_t mLastDequeueDuration = 0;
+    nsecs_t mLastQueueDuration = 0;
+
     Condition mQueueBufferCondition;
 
     uint64_t mNextFrameNumber;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index c7e8ff2..e88ae29 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1795,15 +1795,16 @@
        return NO_ERROR;
     }
 
-    ssize_t utf8Size = utf16_to_utf8_length(src, utf16Size);
-    if (utf8Size < 0) {
+    // Allow for closing '\0'
+    ssize_t utf8Size = utf16_to_utf8_length(src, utf16Size) + 1;
+    if (utf8Size < 1) {
         return BAD_VALUE;
     }
     // Note that while it is probably safe to assume string::resize keeps a
-    // spare byte around for the trailing null, we're going to be explicit.
-    str->resize(utf8Size + 1);
-    utf16_to_utf8(src, utf16Size, &((*str)[0]));
+    // spare byte around for the trailing null, we still pass the size including the trailing null
     str->resize(utf8Size);
+    utf16_to_utf8(src, utf16Size, &((*str)[0]), utf8Size);
+    str->resize(utf8Size - 1);
     return NO_ERROR;
 }
 
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index a6252af..fbd704d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -133,7 +133,11 @@
         bool nonNull = reply.readInt32();
         if (nonNull) {
             *fence = new Fence();
-            reply.read(**fence);
+            result = reply.read(**fence);
+            if (result != NO_ERROR) {
+                fence->clear();
+                return result;
+            }
         }
         result = reply.readInt32();
         return result;
@@ -171,12 +175,21 @@
             bool nonNull = reply.readInt32();
             if (nonNull) {
                 *outBuffer = new GraphicBuffer;
-                reply.read(**outBuffer);
+                result = reply.read(**outBuffer);
+                if (result != NO_ERROR) {
+                    outBuffer->clear();
+                    return result;
+                }
             }
             nonNull = reply.readInt32();
             if (nonNull) {
                 *outFence = new Fence;
-                reply.read(**outFence);
+                result = reply.read(**outFence);
+                if (result != NO_ERROR) {
+                    outBuffer->clear();
+                    outFence->clear();
+                    return result;
+                }
             }
         }
         return result;
@@ -548,9 +561,11 @@
         case ATTACH_BUFFER: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
             sp<GraphicBuffer> buffer = new GraphicBuffer();
-            data.read(*buffer.get());
+            status_t result = data.read(*buffer.get());
             int slot = 0;
-            int result = attachBuffer(&slot, buffer);
+            if (result == NO_ERROR) {
+                result = attachBuffer(&slot, buffer);
+            }
             reply->writeInt32(slot);
             reply->writeInt32(result);
             return NO_ERROR;
@@ -571,8 +586,10 @@
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
             int buf = data.readInt32();
             sp<Fence> fence = new Fence();
-            data.read(*fence.get());
-            status_t result = cancelBuffer(buf, fence);
+            status_t result = data.read(*fence.get());
+            if (result == NO_ERROR) {
+                result = cancelBuffer(buf, fence);
+            }
             reply->writeInt32(result);
             return NO_ERROR;
         }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 55a7769..dbf8114 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -294,8 +294,10 @@
 
     int buf = -1;
     sp<Fence> fence;
+    nsecs_t now = systemTime();
     status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
             reqWidth, reqHeight, reqFormat, reqUsage);
+    mLastDequeueDuration = systemTime() - now;
 
     if (result < 0) {
         ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
@@ -498,7 +500,9 @@
         input.setSurfaceDamage(flippedRegion);
     }
 
+    nsecs_t now = systemTime();
     status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
+    mLastQueueDuration = systemTime() - now;
     if (err != OK)  {
         ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
     }
@@ -577,6 +581,20 @@
                 }
                 return err;
             }
+            case NATIVE_WINDOW_LAST_DEQUEUE_DURATION: {
+                int64_t durationUs = mLastDequeueDuration / 1000;
+                *value = durationUs > std::numeric_limits<int>::max() ?
+                        std::numeric_limits<int>::max() :
+                        static_cast<int>(durationUs);
+                return NO_ERROR;
+            }
+            case NATIVE_WINDOW_LAST_QUEUE_DURATION: {
+                int64_t durationUs = mLastQueueDuration / 1000;
+                *value = durationUs > std::numeric_limits<int>::max() ?
+                        std::numeric_limits<int>::max() :
+                        static_cast<int>(durationUs);
+                return NO_ERROR;
+            }
         }
     }
     return mGraphicBufferProducer->query(what, value);
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index bef5f02..2e18698 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -621,6 +621,24 @@
 #define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
 #endif
 
+#ifndef EGL_ANDROID_get_frame_timestamps
+#define EGL_ANDROID_get_frame_timestamps 1
+#define EGL_TIMESTAMPS_ANDROID 0x314D
+#define EGL_QUEUE_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_RETIRE_TIME_ANDROID 0x3432
+#define EGL_READS_DONE_TIME_ANDROID 0x3433
+#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);
+#else
+typedef EGLAPI EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+typedef EGLAPI EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index e793852..7a0cce4 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -84,6 +84,7 @@
         "EGL_KHR_swap_buffers_with_damage "
         "EGL_ANDROID_create_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
+        "EGL_ANDROID_get_frame_timestamps "
         ;
 extern char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
@@ -207,6 +208,12 @@
             (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR },
     { "eglCreateStreamFromFileDescriptorKHR",
             (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
+
+    // EGL_ANDROID_get_frame_timestamps
+    { "eglGetFrameTimestampsANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
+    { "eglQueryTimestampSupportedANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglQueryTimestampSupportedANDROID },
 };
 
 /*
@@ -1196,7 +1203,7 @@
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
-    egl_surface_t const * const s = get_surface(surface);
+    egl_surface_t * const s = get_surface(surface);
 
     if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
         int err = native_window_set_auto_refresh(s->win.get(),
@@ -1205,6 +1212,11 @@
             setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
+    if (attribute == EGL_TIMESTAMPS_ANDROID) {
+        s->enableTimestamps = value;
+        return EGL_TRUE;
+    }
+
     if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
                 dp->disp.dpy, s->surface, attribute, value);
@@ -1935,3 +1947,103 @@
 
     return EGL_FALSE;
 }
+
+EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
+        EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
+        EGLnsecsANDROID *values)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) {
+        setError(EGL_BAD_DISPLAY, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    SurfaceRef _s(dp.get(), surface);
+    if (!_s.get()) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    egl_surface_t const * const s = get_surface(surface);
+
+    if (!s->enableTimestamps) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    nsecs_t* postedTime = nullptr;
+    nsecs_t* acquireTime = nullptr;
+    nsecs_t* refreshStartTime = nullptr;
+    nsecs_t* GLCompositionDoneTime = nullptr;
+    nsecs_t* displayRetireTime = nullptr;
+    nsecs_t* releaseTime = nullptr;
+
+    for (int i = 0; i < numTimestamps; i++) {
+        switch (timestamps[i]) {
+            case EGL_QUEUE_TIME_ANDROID:
+                postedTime = &values[i];
+                break;
+            case EGL_RENDERING_COMPLETE_TIME_ANDROID:
+                acquireTime = &values[i];
+                break;
+            case EGL_COMPOSITION_START_TIME_ANDROID:
+                refreshStartTime = &values[i];
+                break;
+            case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
+                GLCompositionDoneTime = &values[i];
+                break;
+            case EGL_DISPLAY_RETIRE_TIME_ANDROID:
+                displayRetireTime = &values[i];
+                break;
+            case EGL_READS_DONE_TIME_ANDROID:
+                releaseTime = &values[i];
+                break;
+            default:
+                setError(EGL_BAD_PARAMETER, EGL_FALSE);
+                return EGL_FALSE;
+        }
+    }
+
+    status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo,
+            postedTime, acquireTime, refreshStartTime, GLCompositionDoneTime,
+            displayRetireTime, releaseTime);
+
+    if (ret != NO_ERROR) {
+        setError(EGL_BAD_ACCESS, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    return EGL_TRUE;
+}
+
+EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface,
+        EGLint timestamp)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) {
+        setError(EGL_BAD_DISPLAY, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    SurfaceRef _s(dp.get(), surface);
+    if (!_s.get()) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    switch (timestamp) {
+        case EGL_QUEUE_TIME_ANDROID:
+        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;
+        default:
+            return EGL_FALSE;
+    }
+}
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 90f27d1..cfecf77 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -68,7 +68,7 @@
         EGLNativeWindowType win, EGLSurface surface,
         egl_connection_t const* cnx) :
     egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
-    connected(true)
+    enableTimestamps(false), connected(true)
 {
     if (win) {
         getDisplay()->onWindowSurfaceCreated();
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 8f3b9cb..97eda4c 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -139,6 +139,7 @@
     EGLConfig config;
     sp<ANativeWindow> win;
     egl_connection_t const* cnx;
+    bool enableTimestamps;
 private:
     bool connected;
     void disconnect();
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
new file mode 100644
index 0000000..30337ad
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -0,0 +1,145 @@
+Name
+
+    ANDROID_get_frame_timestamps
+
+Name Strings
+
+    EGL_ANDROID_get_frame_timestamps
+
+Contributors
+
+    Pablo Ceballos
+
+Contact
+
+    Pablo Ceballos, Google Inc. (pceballos 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, May 31, 2016
+
+Number
+
+    EGL Extension #XXX
+
+Dependencies
+
+    Requires EGL 1.2
+
+    This extension is written against the wording of the EGL 1.5 Specification
+
+Overview
+
+    This extension allows querying various timestamps related to the composition
+    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 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
+          long the compositor's rendering work took. In combination these can be
+          used to help determine if the system is GPU or CPU bound.
+
+New Types
+
+    /*
+     * EGLnsecsANDROID is a signed integer type for representing a time in
+     * nanoseconds.
+     */
+    #include <khrplatform.h>
+    typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+
+New Procedures and Functions
+
+    EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
+            EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
+            EGLnsecsANDROID *values);
+
+    EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
+            surface, EGLint timestamp);
+
+New Tokens
+
+    EGL_TIMESTAMPS_ANDROID 0x314D
+    EGL_QUEUE_TIME_ANDROID 0x314E
+    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
+
+Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
+"Surface Attributes", page 43:
+
+    If attribute is EGL_TIMESTAMPS_ANDROID, then values specifies whether to
+    enable/disable timestamp collection for this surface. A value of EGL_TRUE
+    enables timestamp collection, while a value of EGL_FALSE disables it. The
+    initial value is false. If surface is not a window surface this has no
+    effect.
+
+Changes to Chapter 3 of the EGL 1.5 Specification (EGL Functions and Errors)
+
+    Add a new subsection under Section 3,
+
+    "3.13 Composition and Display Timestamps
+
+    The function
+
+        EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface
+            surface, EGLint framesAgo, EGLint numTimestamps,
+            const EGLint *timestamps, EGLnsecsANDROID *values);
+
+    allows querying various timestamps related to the composition and display of
+    a window surface.
+
+    The framesAgo parameter indicates how many frames before the last posted
+    frame to query. So a value of zero would indicate that the query is for the
+    last posted frame. Note that the implementation maintains a limited history
+    of timestamp data. If a query is made for a frame whose timestamp history
+    no longer exists then EGL_BAD_ACCESS is generated. If timestamp collection
+    has not been enabled for the surface then EGL_BAD_SURFACE is generated.
+    Timestamps for events that will not occur or have not yet occurred will be
+    zero. Timestamp queries that are not supported will generate an
+    EGL_BAD_PARAMETER error. If any error is generated the function will return
+    EGL_FALSE.
+
+    The eglGetFrameTimestampsANDROID function takes an array of timestamps to
+    query and returns timestamps in the corresponding indices of the values
+    array. The possible timestamps that can be queried are:
+        - EGL_QUEUE_TIME_ANDROID - The time this frame was queued by the
+          application.
+        - 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
+          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_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
+    function
+
+        EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
+            surface, EGLint timestamp);
+
+    allows querying which timestamps are supported on the implementation."
+
+Issues
+
+    None
+
+Revision History
+
+#1 (Pablo Ceballos, May 31, 2016)
+    - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
index 8f1eaf3..f0c024e 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -19,4 +19,11 @@
 0x314A               EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
 0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
 0x314C               EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
-0x314D - 0x314F      (unused)
+0x314D               EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x314E               EGL_QUEUE_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_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3433               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3434 - 0x343F      (unused)
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index fb83eff..0c4dc26 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -435,15 +435,15 @@
                     continue;
                 }
                 if (reg_info.mActivated) {
-                   result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x "
-                           "samplingRate=%dus maxReportLatency=%dus\n",
-                           reg_info.mHour, reg_info.mMin, reg_info.mSec,
-                           reg_info.mPackageName.string(), reg_info.mSensorHandle,
-                           reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs);
+                   result.appendFormat("%02d:%02d:%02d activated handle=0x%08x "
+                           "samplingRate=%dus maxReportLatency=%dus package=%s\n",
+                           reg_info.mHour, reg_info.mMin, reg_info.mSec, reg_info.mSensorHandle,
+                           reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs,
+                           reg_info.mPackageName.string());
                 } else {
-                   result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n",
+                   result.appendFormat("%02d:%02d:%02d de-activated handle=0x%08x package=%s\n",
                            reg_info.mHour, reg_info.mMin, reg_info.mSec,
-                           reg_info.mPackageName.string(), reg_info.mSensorHandle);
+                           reg_info.mSensorHandle, reg_info.mPackageName.string());
                 }
                 currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
                         SENSOR_REGISTRATIONS_BUF_SIZE;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index c8de621..68d4154 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -53,7 +53,7 @@
 // For older HALs which don't support batching, use a smaller socket buffer size.
 #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
 
-#define SENSOR_REGISTRATIONS_BUF_SIZE 20
+#define SENSOR_REGISTRATIONS_BUF_SIZE 200
 
 namespace android {
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5145a3f..548b048 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1100,6 +1100,25 @@
     }
 }
 
+bool Layer::headFenceHasSignaled() const {
+#ifdef USE_HWC2
+    Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems.empty()) {
+        return true;
+    }
+    if (mQueueItems[0].mIsDroppable) {
+        // Even though this buffer's fence may not have signaled yet, it could
+        // be replaced by another buffer before it has a chance to, which means
+        // that it's possible to get into a situation where a buffer is never
+        // able to be latched. To avoid this, grab this buffer anyway.
+        return true;
+    }
+    return mQueueItems[0].mFence->getSignalTime() != INT64_MAX;
+#else
+    return true;
+#endif
+}
+
 bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
     if (point->getFrameNumber() <= mCurrentFrameNumber) {
         // Don't bother with a SyncPoint, since we've already latched the
@@ -1357,9 +1376,10 @@
 
 void Layer::notifyAvailableFrames() {
     auto headFrameNumber = getHeadFrameNumber();
+    bool headFenceSignaled = headFenceHasSignaled();
     Mutex::Autolock lock(mLocalSyncPointMutex);
     for (auto& point : mLocalSyncPoints) {
-        if (headFrameNumber >= point->getFrameNumber()) {
+        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
             point->setFrameAvailable();
         }
     }
@@ -1756,6 +1776,13 @@
             return outDirtyRegion;
         }
 
+        // If the head buffer's acquire fence hasn't signaled yet, return and
+        // try again later
+        if (!headFenceHasSignaled()) {
+            mFlinger->signalLayerUpdate();
+            return outDirtyRegion;
+        }
+
         // Capture the old state of the layer for comparisons later
         const State& s(getDrawingState());
         const bool oldOpacity = isOpaque(s);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a51c804..78a8427 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -510,6 +510,7 @@
     std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
 
     uint64_t getHeadFrameNumber() const;
+    bool headFenceHasSignaled() const;
 
     // Returns false if the relevant frame has already been latched
     bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 34dc24b..974c7a3 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -134,31 +134,12 @@
 }
 
 
-/* when INVALIDATE_ON_VSYNC is set SF only processes
- * buffer updates on VSYNC and performs a refresh immediately
- * after.
- *
- * when INVALIDATE_ON_VSYNC is set to false, SF will instead
- * perform the buffer updates immediately, but the refresh only
- * at the next VSYNC.
- * THIS MODE IS BUGGY ON GALAXY NEXUS AND WILL CAUSE HANGS
- */
-#define INVALIDATE_ON_VSYNC 1
-
 void MessageQueue::invalidate() {
-#if INVALIDATE_ON_VSYNC
     mEvents->requestNextVsync();
-#else
-    mHandler->dispatchInvalidate();
-#endif
 }
 
 void MessageQueue::refresh() {
-#if INVALIDATE_ON_VSYNC
     mHandler->dispatchRefresh();
-#else
-    mEvents->requestNextVsync();
-#endif
 }
 
 int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
@@ -172,11 +153,7 @@
     while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
         for (int i=0 ; i<n ; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-#if INVALIDATE_ON_VSYNC
                 mHandler->dispatchInvalidate();
-#else
-                mHandler->dispatchRefresh();
-#endif
                 break;
             }
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9a2747d..e156e1a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -167,9 +167,6 @@
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
     mGpuToCpuSupported = !atoi(value);
 
-    property_get("debug.sf.drop_missed_frames", value, "0");
-    mDropMissedFrames = atoi(value);
-
     property_get("debug.sf.showupdates", value, "0");
     mDebugRegion = atoi(value);
 
@@ -465,6 +462,18 @@
         mSFEventThread = new EventThread(sfVsyncSrc, *this);
         mEventQueue.setEventThread(mSFEventThread);
 
+        // set EventThread and SFEventThread to SCHED_FIFO for minimum jitter
+        struct sched_param param = {0};
+        param.sched_priority = 1;
+        if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
+            ALOGE("Couldn't set SCHED_FIFO for EventThread");
+        }
+
+        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
+            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
+        }
+
+
         // Get a RenderEngine for the given display / config (can't fail)
         mRenderEngine = RenderEngine::create(mEGLDisplay,
                 HAL_PIXEL_FORMAT_RGBA_8888);
@@ -904,6 +913,15 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
+            bool frameMissed = !mHadClientComposition &&
+                    mPreviousPresentFence != Fence::NO_FENCE &&
+                    mPreviousPresentFence->getSignalTime() == INT64_MAX;
+            ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+            if (frameMissed) {
+                signalLayerUpdate();
+                break;
+            }
+
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
             refreshNeeded |= mRepaintEverything;
@@ -940,36 +958,22 @@
     ATRACE_CALL();
 
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    static nsecs_t previousExpectedPresent = 0;
-    nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
-    static bool previousFrameMissed = false;
-    bool frameMissed = (expectedPresent == previousExpectedPresent);
-    if (frameMissed != previousFrameMissed) {
-        ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
-    }
-    previousFrameMissed = frameMissed;
 
-    if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
-        // Latch buffers, but don't send anything to HWC, then signal another
-        // wakeup for the next vsync
-        preComposition();
-        repaintEverything();
-    } else {
-        preComposition();
-        rebuildLayerStacks();
-        setUpHWComposer();
-        doDebugFlashRegions();
-        doComposition();
-        postComposition(refreshStartTime);
-    }
+    preComposition();
+    rebuildLayerStacks();
+    setUpHWComposer();
+    doDebugFlashRegions();
+    doComposition();
+    postComposition(refreshStartTime);
+
+    mPreviousPresentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
+    mHadClientComposition = mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY);
 
     // Release any buffers which were replaced this frame
     for (auto& layer : mLayersWithQueuedFrames) {
         layer->releasePendingBuffer();
     }
     mLayersWithQueuedFrames.clear();
-
-    previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
 }
 
 void SurfaceFlinger::doDebugFlashRegions()
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 28666e2..0df39a4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -468,7 +468,6 @@
     RenderEngine* mRenderEngine;
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
-    bool mDropMissedFrames;
     sp<EventThread> mEventThread;
     sp<EventThread> mSFEventThread;
     sp<EventControlThread> mEventControlThread;
@@ -488,6 +487,8 @@
     bool mAnimCompositionPending;
 #ifdef USE_HWC2
     std::vector<sp<Layer>> mLayersWithQueuedFrames;
+    sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
+    bool mHadClientComposition = false;
 #endif
 
     // this may only be written from the main thread with mStateLock held
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 83f7b08..69fb8c5 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -166,9 +166,6 @@
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
     mGpuToCpuSupported = !atoi(value);
 
-    property_get("debug.sf.drop_missed_frames", value, "0");
-    mDropMissedFrames = atoi(value);
-
     property_get("debug.sf.showupdates", value, "0");
     mDebugRegion = atoi(value);
 
@@ -462,6 +459,18 @@
     mSFEventThread = new EventThread(sfVsyncSrc, *this);
     mEventQueue.setEventThread(mSFEventThread);
 
+    // set EventThread and SFEventThread to SCHED_FIFO for minimum jitter
+    struct sched_param param = {0};
+    param.sched_priority = 1;
+    if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for EventThread");
+    }
+
+    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
+    }
+
+
     // Initialize the H/W composer object.  There may or may not be an
     // actual hardware composer underneath.
     mHwc = new HWComposer(this,
@@ -944,30 +953,13 @@
     ATRACE_CALL();
 
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    static nsecs_t previousExpectedPresent = 0;
-    nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
-    static bool previousFrameMissed = false;
-    bool frameMissed = (expectedPresent == previousExpectedPresent);
-    if (frameMissed != previousFrameMissed) {
-        ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
-    }
-    previousFrameMissed = frameMissed;
 
-    if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
-        // Latch buffers, but don't send anything to HWC, then signal another
-        // wakeup for the next vsync
-        preComposition();
-        repaintEverything();
-    } else {
-        preComposition();
-        rebuildLayerStacks();
-        setUpHWComposer();
-        doDebugFlashRegions();
-        doComposition();
-        postComposition(refreshStartTime);
-    }
-
-    previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
+    preComposition();
+    rebuildLayerStacks();
+    setUpHWComposer();
+    doDebugFlashRegions();
+    doComposition();
+    postComposition(refreshStartTime);
 }
 
 void SurfaceFlinger::doDebugFlashRegions()
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 97a1e8b..543d0c7 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -16,6 +16,8 @@
 
 #include <sys/resource.h>
 
+#include <sched.h>
+
 #include <cutils/sched_policy.h>
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
@@ -61,6 +63,12 @@
     sp<GpuService> gpuservice = new GpuService();
     sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
 
+    struct sched_param param = {0};
+    param.sched_priority = 1;
+    if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO");
+    }
+
     // run surface flinger in this thread
     flinger->run();