Properly run window animations at vsync-sf (1/2)

- Add new Choreographer instance that runs on vsync-sf
- Use this new Choreographer for WindowAnimator, and remove all
the hacks around it

Test: Open apps and close apps, notice no stutter
Test: Screen zoom animations
Test: go/wm-smoke
Bug: 36631902
Change-Id: I988ae25645effc3ac20efa7cb9b68f23444da0d0
(cherry picked from commit 34a0cdb98eb5561774ea4e7b3b602aad80c4a3cc)
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index aac5baa..597be68 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -16,6 +16,9 @@
 
 package android.view;
 
+import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
+import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
+
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Handler;
 import android.os.Looper;
@@ -102,10 +105,23 @@
             if (looper == null) {
                 throw new IllegalStateException("The current thread must have a looper!");
             }
-            return new Choreographer(looper);
+            return new Choreographer(looper, VSYNC_SOURCE_APP);
         }
     };
 
+    // Thread local storage for the SF choreographer.
+    private static final ThreadLocal<Choreographer> sSfThreadInstance =
+            new ThreadLocal<Choreographer>() {
+                @Override
+                protected Choreographer initialValue() {
+                    Looper looper = Looper.myLooper();
+                    if (looper == null) {
+                        throw new IllegalStateException("The current thread must have a looper!");
+                    }
+                    return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
+                }
+            };
+
     // Enable/disable vsync for animations and drawing.
     private static final boolean USE_VSYNC = SystemProperties.getBoolean(
             "debug.choreographer.vsync", true);
@@ -202,10 +218,12 @@
 
     private static final int CALLBACK_LAST = CALLBACK_COMMIT;
 
-    private Choreographer(Looper looper) {
+    private Choreographer(Looper looper, int vsyncSource) {
         mLooper = looper;
         mHandler = new FrameHandler(looper);
-        mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
+        mDisplayEventReceiver = USE_VSYNC
+                ? new FrameDisplayEventReceiver(looper, vsyncSource)
+                : null;
         mLastFrameTimeNanos = Long.MIN_VALUE;
 
         mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
@@ -233,6 +251,13 @@
         return sThreadInstance.get();
     }
 
+    /**
+     * @hide
+     */
+    public static Choreographer getSfInstance() {
+        return sSfThreadInstance.get();
+    }
+
     /** Destroys the calling thread's choreographer
      * @hide
      */
@@ -816,8 +841,8 @@
         private long mTimestampNanos;
         private int mFrame;
 
-        public FrameDisplayEventReceiver(Looper looper) {
-            super(looper);
+        public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
+            super(looper, vsyncSource);
         }
 
         @Override
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 67cdfc5..caadc36 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -35,6 +35,23 @@
  * @hide
  */
 public abstract class DisplayEventReceiver {
+
+    /**
+     * When retrieving vsync events, this specifies that the vsync event should happen at the normal
+     * vsync-app tick.
+     * <p>
+     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
+     */
+    public static final int VSYNC_SOURCE_APP = 0;
+
+    /**
+     * When retrieving vsync events, this specifies that the vsync event should happen whenever
+     * Surface Flinger is processing a frame.
+     * <p>
+     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
+     */
+    public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
+
     private static final String TAG = "DisplayEventReceiver";
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -46,7 +63,7 @@
     private MessageQueue mMessageQueue;
 
     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
-            MessageQueue messageQueue);
+            MessageQueue messageQueue, int vsyncSource);
     private static native void nativeDispose(long receiverPtr);
     @FastNative
     private static native void nativeScheduleVsync(long receiverPtr);
@@ -55,14 +72,16 @@
      * Creates a display event receiver.
      *
      * @param looper The looper to use when invoking callbacks.
+     * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
      */
-    public DisplayEventReceiver(Looper looper) {
+    public DisplayEventReceiver(Looper looper, int vsyncSource) {
         if (looper == null) {
             throw new IllegalArgumentException("looper must not be null");
         }
 
         mMessageQueue = looper.getQueue();
-        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
+        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
+                vsyncSource);
 
         mCloseGuard.open("dispose");
     }
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 2eada3e..831393bd 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -47,7 +47,7 @@
 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
 public:
     NativeDisplayEventReceiver(JNIEnv* env,
-            jobject receiverWeak, const sp<MessageQueue>& messageQueue);
+            jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource);
 
     void dispose();
 
@@ -65,8 +65,9 @@
 
 
 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
-        jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
-        DisplayEventDispatcher(messageQueue->getLooper()),
+        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource) :
+        DisplayEventDispatcher(messageQueue->getLooper(),
+                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource)),
         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
         mMessageQueue(messageQueue) {
     ALOGV("receiver %p ~ Initializing display event receiver.", this);
@@ -113,7 +114,7 @@
 
 
 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
-        jobject messageQueueObj) {
+        jobject messageQueueObj, jint vsyncSource) {
     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
     if (messageQueue == NULL) {
         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
@@ -121,7 +122,7 @@
     }
 
     sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
-            receiverWeak, messageQueue);
+            receiverWeak, messageQueue, vsyncSource);
     status_t status = receiver->initialize();
     if (status) {
         String8 message;
@@ -156,7 +157,7 @@
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
-            "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
+            "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;I)J",
             (void*)nativeInit },
     { "nativeDispose",
             "(J)V",
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
index b8ef9ea..7708e43 100644
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ b/libs/androidfw/DisplayEventDispatcher.cpp
@@ -33,8 +33,9 @@
 // using just a few large reads.
 static const size_t EVENT_BUFFER_SIZE = 100;
 
-DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper) :
-        mLooper(looper), mWaitingForVsync(false) {
+DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
+        ISurfaceComposer::VsyncSource vsyncSource) :
+        mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index 3ade215..e1dfb94 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -22,7 +22,8 @@
 
 class DisplayEventDispatcher : public LooperCallback {
 public:
-    DisplayEventDispatcher(const sp<Looper>& looper);
+    DisplayEventDispatcher(const sp<Looper>& looper,
+            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
 
     status_t initialize();
     void dispose();
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 841a951..cdc973b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -668,7 +668,7 @@
 
     private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
         public HotplugDisplayEventReceiver(Looper looper) {
-            super(looper);
+            super(looper, VSYNC_SOURCE_APP);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index d85dd0c..03b5b827 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -83,10 +83,6 @@
     // check if some got replaced and can be removed.
     private boolean mRemoveReplacedWindows = false;
 
-    private long mCurrentFrameTime;
-    private final Runnable mAnimationTick;
-    private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
-
     private Choreographer mChoreographer;
 
     /**
@@ -95,40 +91,19 @@
      */
     private boolean mAnimationFrameCallbackScheduled;
 
-    /**
-     * Indicates whether we have an animation tick scheduled. The tick is the thing that actually
-     * executes the animation step, which will happen at vsync-sf.
-     */
-    private boolean mAnimationTickScheduled;
-
     WindowAnimator(final WindowManagerService service) {
         mService = service;
         mContext = service.mContext;
         mPolicy = service.mPolicy;
         mWindowPlacerLocked = service.mWindowPlacerLocked;
         AnimationThread.getHandler().runWithScissors(
-                () -> mChoreographer = Choreographer.getInstance(), 0 /* timeout */);
+                () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
 
-        // TODO: Multi-display: If displays have different vsync tick, have a separate tick per
-        // display.
-        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(AnimationThread.getHandler(),
-                mService.getDefaultDisplayContentLocked().getDisplay(), mChoreographer);
-        mAnimationTick = () -> {
-            synchronized (mService.mWindowMap) {
-                mAnimationTickScheduled = false;
-            }
-            animate(mCurrentFrameTime);
-        };
         mAnimationFrameCallback = frameTimeNs -> {
             synchronized (mService.mWindowMap) {
-                mCurrentFrameTime = frameTimeNs;
                 mAnimationFrameCallbackScheduled = false;
-                if (mAnimationTickScheduled) {
-                    return;
-                }
-                mAnimationTickScheduled = true;
             }
-            mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
+            animate(frameTimeNs);
         };
     }
 
@@ -422,7 +397,7 @@
     }
 
     boolean isAnimationScheduled() {
-        return mAnimationFrameCallbackScheduled || mAnimationTickScheduled;
+        return mAnimationFrameCallbackScheduled;
     }
 
     Choreographer getChoreographer() {