Reland "Listen for Vsync callback on the UI thread directly" (flutter/engine#31494)

This commit is contained in:
ColdPaleLight 2022-02-25 01:51:05 +08:00 committed by GitHub
parent c101941c37
commit 1a179ecff2
5 changed files with 75 additions and 24 deletions

View File

@ -13,6 +13,31 @@ namespace fml {
static constexpr int kClockType = CLOCK_MONOTONIC;
static fml::jni::ScopedJavaGlobalRef<jclass>* g_looper_class = nullptr;
static jmethodID g_looper_prepare_method_ = nullptr;
static jmethodID g_looper_loop_method_ = nullptr;
static jmethodID g_looper_my_looper_method_ = nullptr;
static jmethodID g_looper_quit_method_ = nullptr;
static void LooperPrepare() {
JNIEnv* env = fml::jni::AttachCurrentThread();
env->CallStaticVoidMethod(g_looper_class->obj(), g_looper_prepare_method_);
}
static void LooperLoop() {
JNIEnv* env = fml::jni::AttachCurrentThread();
env->CallStaticVoidMethod(g_looper_class->obj(), g_looper_loop_method_);
}
static void LooperQuit() {
JNIEnv* env = fml::jni::AttachCurrentThread();
auto my_looper = env->CallStaticObjectMethod(g_looper_class->obj(),
g_looper_my_looper_method_);
if (my_looper != nullptr) {
env->CallVoidMethod(my_looper, g_looper_quit_method_);
}
}
static ALooper* AcquireLooperForThread() {
ALooper* looper = ALooper_forThread();
@ -63,23 +88,15 @@ void MessageLoopAndroid::Run() {
FML_DCHECK(looper_.get() == ALooper_forThread());
running_ = true;
while (running_) {
int result = ::ALooper_pollOnce(-1, // infinite timeout
nullptr, // out fd,
nullptr, // out events,
nullptr // out data
);
if (result == ALOOPER_POLL_TIMEOUT || result == ALOOPER_POLL_ERROR) {
// This handles the case where the loop is terminated using ALooper APIs.
running_ = false;
}
}
// Initialize the current thread as a looper.
LooperPrepare();
// Run the message queue in this thread.
LooperLoop();
}
void MessageLoopAndroid::Terminate() {
running_ = false;
ALooper_wake(looper_.get());
LooperQuit();
}
void MessageLoopAndroid::WakeUp(fml::TimePoint time_point) {
@ -93,4 +110,30 @@ void MessageLoopAndroid::OnEventFired() {
}
}
bool MessageLoopAndroid::Register(JNIEnv* env) {
jclass clazz = env->FindClass("android/os/Looper");
FML_CHECK(clazz != nullptr);
g_looper_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);
FML_CHECK(!g_looper_class->is_null());
g_looper_prepare_method_ =
env->GetStaticMethodID(g_looper_class->obj(), "prepare", "()V");
FML_CHECK(g_looper_prepare_method_ != nullptr);
g_looper_loop_method_ =
env->GetStaticMethodID(g_looper_class->obj(), "loop", "()V");
FML_CHECK(g_looper_loop_method_ != nullptr);
g_looper_my_looper_method_ = env->GetStaticMethodID(
g_looper_class->obj(), "myLooper", "()Landroid/os/Looper;");
FML_CHECK(g_looper_my_looper_method_ != nullptr);
g_looper_quit_method_ =
env->GetMethodID(g_looper_class->obj(), "quit", "()V");
FML_CHECK(g_looper_quit_method_ != nullptr);
return true;
}
} // namespace fml

View File

@ -11,6 +11,7 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/message_loop_impl.h"
#include "flutter/fml/platform/android/jni_util.h"
#include "flutter/fml/unique_fd.h"
namespace fml {
@ -26,6 +27,9 @@ struct UniqueLooperTraits {
/// This implemenation wraps usage of Android's \p looper.
/// \see https://developer.android.com/ndk/reference/group/looper
class MessageLoopAndroid : public MessageLoopImpl {
public:
static bool Register(JNIEnv* env);
private:
fml::UniqueObject<ALooper*, UniqueLooperTraits> looper_;
fml::UniqueFD timer_fd_;

View File

@ -261,9 +261,10 @@ public class FlutterJNI {
/**
* The Android vsync waiter implementation in C++ needs to know when a vsync signal arrives, which
* is obtained via Java API. The delegate set here is called on the C++ side when the engine is
* ready to wait for the next vsync signal. The delegate is expected to add a postFrameCallback to
* the {@link android.view.Choreographer}, and call {@link onVsync} to notify the engine.
* is obtained via Java API. The delegate set here is called on the C++ side on the ui thread when
* the engine is ready to wait for the next vsync signal. The delegate is expected to add a
* postFrameCallback to the {@link android.view.Choreographer}, and call {@link onVsync} to notify
* the engine.
*
* @param delegate The delegate that will call the engine back on the next vsync signal.
*/
@ -272,7 +273,7 @@ public class FlutterJNI {
}
// TODO(mattcarroll): add javadocs
// Called by native.
// Called by native on the ui thread.
private static void asyncWaitForVsync(final long cookie) {
if (asyncWaitForVsyncDelegate != null) {
asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie);

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "flutter/fml/platform/android/jni_util.h"
#include "flutter/fml/platform/android/message_loop_android.h"
#include "flutter/shell/platform/android/android_image_generator.h"
#include "flutter/shell/platform/android/flutter_main.h"
#include "flutter/shell/platform/android/platform_view_android.h"
@ -32,5 +33,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
result = flutter::AndroidImageGenerator::Register(env);
FML_CHECK(result);
// Register MessageLoopAndroid.
result = fml::MessageLoopAndroid::Register(env);
FML_CHECK(result);
return JNI_VERSION_1_4;
}

View File

@ -29,13 +29,11 @@ void VsyncWaiterAndroid::AwaitVSync() {
auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());
jlong java_baton = reinterpret_cast<jlong>(weak_this);
task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {
JNIEnv* env = fml::jni::AttachCurrentThread();
env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), //
g_async_wait_for_vsync_method_, //
java_baton //
);
});
JNIEnv* env = fml::jni::AttachCurrentThread();
env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), //
g_async_wait_for_vsync_method_, //
java_baton //
);
}
// static