1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/android/vsync_waiter_android.h"
6
7 #include <cmath>
8 #include <utility>
9
10 #include "flutter/common/task_runners.h"
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/platform/android/jni_util.h"
13 #include "flutter/fml/platform/android/scoped_java_ref.h"
14 #include "flutter/fml/size.h"
15 #include "flutter/fml/trace_event.h"
16
17 namespace flutter {
18
19 static fml::jni::ScopedJavaGlobalRef<jclass>* g_vsync_waiter_class = nullptr;
20 static jmethodID g_async_wait_for_vsync_method_ = nullptr;
21
VsyncWaiterAndroid(flutter::TaskRunners task_runners)22 VsyncWaiterAndroid::VsyncWaiterAndroid(flutter::TaskRunners task_runners)
23 : VsyncWaiter(std::move(task_runners)) {}
24
25 VsyncWaiterAndroid::~VsyncWaiterAndroid() = default;
26
27 // |VsyncWaiter|
AwaitVSync()28 void VsyncWaiterAndroid::AwaitVSync() {
29 auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());
30 jlong java_baton = reinterpret_cast<jlong>(weak_this);
31
32 task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {
33 JNIEnv* env = fml::jni::AttachCurrentThread();
34 env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), //
35 g_async_wait_for_vsync_method_, //
36 java_baton //
37 );
38 });
39 }
40
GetDisplayRefreshRate() const41 float VsyncWaiterAndroid::GetDisplayRefreshRate() const {
42 JNIEnv* env = fml::jni::AttachCurrentThread();
43 if (g_vsync_waiter_class == nullptr) {
44 return kUnknownRefreshRateFPS;
45 }
46 jclass clazz = g_vsync_waiter_class->obj();
47 if (clazz == nullptr) {
48 return kUnknownRefreshRateFPS;
49 }
50 jfieldID fid = env->GetStaticFieldID(clazz, "refreshRateFPS", "F");
51 return env->GetStaticFloatField(clazz, fid);
52 }
53
54 // static
OnNativeVsync(JNIEnv * env,jclass jcaller,jlong frameTimeNanos,jlong frameTargetTimeNanos,jlong java_baton)55 void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env,
56 jclass jcaller,
57 jlong frameTimeNanos,
58 jlong frameTargetTimeNanos,
59 jlong java_baton) {
60 auto frame_time = fml::TimePoint::FromEpochDelta(
61 fml::TimeDelta::FromNanoseconds(frameTimeNanos));
62 auto target_time = fml::TimePoint::FromEpochDelta(
63 fml::TimeDelta::FromNanoseconds(frameTargetTimeNanos));
64
65 ConsumePendingCallback(java_baton, frame_time, target_time);
66 }
67
68 // static
ConsumePendingCallback(jlong java_baton,fml::TimePoint frame_start_time,fml::TimePoint frame_target_time)69 void VsyncWaiterAndroid::ConsumePendingCallback(
70 jlong java_baton,
71 fml::TimePoint frame_start_time,
72 fml::TimePoint frame_target_time) {
73 auto* weak_this = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(java_baton);
74 auto shared_this = weak_this->lock();
75 delete weak_this;
76
77 if (shared_this) {
78 shared_this->FireCallback(frame_start_time, frame_target_time);
79 }
80 }
81
82 // static
Register(JNIEnv * env)83 bool VsyncWaiterAndroid::Register(JNIEnv* env) {
84 static const JNINativeMethod methods[] = {{
85 .name = "nativeOnVsync",
86 .signature = "(JJJ)V",
87 .fnPtr = reinterpret_cast<void*>(&OnNativeVsync),
88 }};
89
90 jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI");
91
92 if (clazz == nullptr) {
93 return false;
94 }
95
96 g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);
97
98 FML_CHECK(!g_vsync_waiter_class->is_null());
99
100 g_async_wait_for_vsync_method_ = env->GetStaticMethodID(
101 g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V");
102
103 FML_CHECK(g_async_wait_for_vsync_method_ != nullptr);
104
105 return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
106 }
107
108 } // namespace flutter
109