Bag of scheduling tweaks

 Bug: 15118640

 * Prevent over-stuffing the queue by dropping frames
 * Prevent double-drawing in one pulse by RT by deferring
   vsync registration until post-draw so that it catches
   the next vsync pulse instead of the current one
 * Bias vsync race condition towards the UI thread
 * Fix queueDelay to actually work

Change-Id: Ibf584258bd93ebcbba058bd976dc8b307f1c6155
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index a902ce7..3c4d83f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -579,6 +579,12 @@
     abstract void fence();
 
     /**
+     * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
+     */
+    public void notifyFramePending() {
+    }
+
+    /**
      * Describes a series of frames that should be drawn on screen as a graph.
      * Each frame is composed of 1 or more elements.
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 704d516..8417887 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -291,6 +291,11 @@
     }
 
     @Override
+    public void notifyFramePending() {
+        nNotifyFramePending(mNativeProxy);
+    }
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             nDeleteProxy(mNativeProxy);
@@ -364,4 +369,5 @@
     private static native void nDestroyLayer(long nativeProxy, long layer);
 
     private static native void nFence(long nativeProxy);
+    private static native void nNotifyFramePending(long nativeProxy);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 799a406..fc7bf0e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -999,6 +999,17 @@
         }
     }
 
+    /**
+     * Notifies the HardwareRenderer that a new frame will be coming soon.
+     * Currently only {@link ThreadedRenderer} cares about this, and uses
+     * this knowledge to adjust the scheduling of off-thread animations
+     */
+    void notifyRendererOfFramePending() {
+        if (mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.notifyFramePending();
+        }
+    }
+
     void scheduleTraversals() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
@@ -1006,6 +1017,7 @@
             mChoreographer.postCallback(
                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
             scheduleConsumeBatchedInput();
+            notifyRendererOfFramePending();
         }
     }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 48fb729..5bc0f62 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -299,6 +299,12 @@
     proxy->fence();
 }
 
+static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->notifyFramePending();
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -329,6 +335,7 @@
     { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
     { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
+    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
 #endif
 };