Attempting to fix the black flicker

Bug: 79231206
Test: Repro steps from bug

Merged-In: I4c2810c42a7a4358f64584da3ab0cdf1499e71b6
Change-Id: I4c2810c42a7a4358f64584da3ab0cdf1499e71b6
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 7481f1c..ee9a123 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -15,9 +15,11 @@
  */
 
 #define LOG_TAG "ThreadedRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
 
 #include <algorithm>
 #include <atomic>
+#include <inttypes.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -37,6 +39,7 @@
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
+#include <utils/TraceUtils.h>
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
 
@@ -72,6 +75,10 @@
     jmethodID onFrameDraw;
 } gFrameDrawingCallback;
 
+struct {
+    jmethodID onFrameComplete;
+} gFrameCompleteCallback;
+
 static JNIEnv* getenv(JavaVM* vm) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -153,6 +160,49 @@
     std::string mMessage;
 };
 
+class FrameCompleteWrapper : public MessageHandler {
+public:
+    FrameCompleteWrapper(JNIEnv* env, jobject jobject) {
+        mLooper = Looper::getForThread();
+        LOG_ALWAYS_FATAL_IF(!mLooper.get(), "Must create runnable on a Looper thread!");
+        env->GetJavaVM(&mVm);
+        mObject = env->NewGlobalRef(jobject);
+        LOG_ALWAYS_FATAL_IF(!mObject, "Failed to make global ref");
+    }
+
+    virtual ~FrameCompleteWrapper() {
+        releaseObject();
+    }
+
+    void postFrameComplete(int64_t frameNr) {
+        if (mObject) {
+            mFrameNr = frameNr;
+            mLooper->sendMessage(this, 0);
+        }
+    }
+
+    virtual void handleMessage(const Message&) {
+        if (mObject) {
+            ATRACE_FORMAT("frameComplete %" PRId64, mFrameNr);
+            getenv(mVm)->CallVoidMethod(mObject, gFrameCompleteCallback.onFrameComplete, mFrameNr);
+            releaseObject();
+        }
+    }
+
+private:
+    JavaVM* mVm;
+    jobject mObject;
+    sp<Looper> mLooper;
+    int64_t mFrameNr = -1;
+
+    void releaseObject() {
+        if (mObject) {
+            getenv(mVm)->DeleteGlobalRef(mObject);
+            mObject = nullptr;
+        }
+    }
+};
+
 class RootRenderNode : public RenderNode, ErrorHandler {
 public:
     explicit RootRenderNode(JNIEnv* env) : RenderNode() {
@@ -891,6 +941,19 @@
     }
 }
 
+static void android_view_ThreadedRenderer_setFrameCompleteCallback(JNIEnv* env,
+        jobject clazz, jlong proxyPtr, jobject callback) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    if (!callback) {
+        proxy->setFrameCompleteCallback(nullptr);
+    } else {
+        sp<FrameCompleteWrapper> wrapper = new FrameCompleteWrapper{env, callback};
+        proxy->setFrameCompleteCallback([wrapper](int64_t frameNr) {
+            wrapper->postFrameComplete(frameNr);
+        });
+    }
+}
+
 static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
         jobject clazz, jobject jsurface, jint left, jint top,
         jint right, jint bottom, jobject jbitmap) {
@@ -1091,6 +1154,8 @@
     { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
     { "nSetFrameCallback", "(JLandroid/view/ThreadedRenderer$FrameDrawingCallback;)V",
             (void*)android_view_ThreadedRenderer_setFrameCallback},
+    { "nSetFrameCompleteCallback", "(JLandroid/view/ThreadedRenderer$FrameCompleteCallback;)V",
+            (void*)android_view_ThreadedRenderer_setFrameCompleteCallback },
     { "nAddFrameMetricsObserver",
             "(JLandroid/view/FrameMetricsObserver;)J",
             (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
@@ -1143,6 +1208,11 @@
     gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
             "onFrameDraw", "(J)V");
 
+    jclass frameCompleteClass = FindClassOrDie(env,
+            "android/view/ThreadedRenderer$FrameCompleteCallback");
+    gFrameCompleteCallback.onFrameComplete = GetMethodIDOrDie(env, frameCompleteClass,
+            "onFrameComplete", "(J)V");
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }