lib/ui
/// Requests that, at the next appropriate opportunity, the [onBeginFrame]
/// and [onDrawFrame] callbacks be invoked.
///
/// See also:
///
/// * [SchedulerBinding], the Flutter framework class which manages the
/// scheduling of frames.
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';
lib/ui/window/platform_configuration.cc
void PlatformConfiguration::RegisterNatives(
tonic::DartLibraryNatives* natives) {
natives->Register({
{"PlatformConfiguration_defaultRouteName", DefaultRouteName, 1, true},
{"PlatformConfiguration_scheduleFrame", ScheduleFrame, 1, true},
{"PlatformConfiguration_sendPlatformMessage", _SendPlatformMessage, 4,
true},
{"PlatformConfiguration_respondToPlatformMessage",
_RespondToPlatformMessage, 3, true},
{"PlatformConfiguration_render", Render, 2, true},
{"PlatformConfiguration_updateSemantics", UpdateSemantics, 2, true},
{"PlatformConfiguration_setIsolateDebugName", SetIsolateDebugName, 2,
true},
{"PlatformConfiguration_reportUnhandledException",
ReportUnhandledException, 2, true},
{"PlatformConfiguration_setNeedsReportTimings", SetNeedsReportTimings, 2,
true},
{"PlatformConfiguration_getPersistentIsolateData",
GetPersistentIsolateData, 1, true},
{"PlatformConfiguration_computePlatformResolvedLocale",
_ComputePlatformResolvedLocale, 2, true},
});
}
void ScheduleFrame(Dart_NativeArguments args) {
UIDartState::ThrowIfUIOperationsProhibited();
UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
}
runtime/runtime_controller.cc
//------------------------------------------------------------------------------
/// Represents an instance of a running root isolate with window bindings. In
/// normal operation, a single instance of this object is owned by the engine
/// per shell. This object may only be created, used, and collected on the UI
/// task runner. Window state queried by the root isolate is stored by this
/// object. In cold-restart scenarios, the engine may collect this before
/// installing a new runtime controller in its place. The Clone method may be
/// used by the engine to copy the currently accumulated window state so it can
/// be referenced by the new runtime controller.
///
class RuntimeController : public PlatformConfigurationClient {
// |PlatformConfigurationClient|
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
}
shell/common/engine.cc
class Engine final : public RuntimeDelegate,
public HintFreedDelegate,
PointerDataDispatcher::Delegate {
private:
Delegate& delegate_;
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
animator_->RequestFrame(regenerate_layer_tree);
}
}
class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler {
shell/common/animator.cc
void Animator::RequestFrame(bool regenerate_layer_tree) {
// The AwaitVSync is going to call us back at the next VSync. However, we want
// to be reasonably certain that the UI thread is not in the middle of a
// particularly expensive callout. We post the AwaitVSync to run right after
// an idle. This does NOT provide a guarantee that the UI thread has not
// started an expensive operation right after posting this message however.
// To support that, we need edge triggered wakes on VSync.
task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(),
frame_number = frame_number_]() {
if (!self) {
return;
}
TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number);
self->AwaitVSync();
});
frame_scheduled_ = true;
}
void Animator::AwaitVSync() {
waiter_->AsyncWaitForVsync(
[self = weak_factory_.GetWeakPtr()](fml::TimePoint vsync_start_time,
fml::TimePoint frame_target_time) {
if (self) {
if (self->CanReuseLastLayerTree()) {
self->DrawLastLayerTree();
} else {
self->BeginFrame(vsync_start_time, frame_target_time);
}
}
});
delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
}
shell/common/vsync_waiter.cc
// Public method invoked by the animator.
void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) {
if (!callback) {
return;
}
TRACE_EVENT0("flutter", "AsyncWaitForVsync");
{
std::scoped_lock lock(callback_mutex_);
if (callback_) {
// The animator may request a frame more than once within a frame
// interval. Multiple calls to request frame must result in a single
// callback per frame interval.
TRACE_EVENT_INSTANT0("flutter", "MultipleCallsToVsyncInFrameInterval");
return;
}
callback_ = std::move(callback);
if (secondary_callback_) {
// Return directly as `AwaitVSync` is already called by
// `ScheduleSecondaryCallback`.
return;
}
}
AwaitVSync();
}
shell/platform/android/vsync_waiter_android.cc
// |VsyncWaiter|
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(), //调用FlutterJNI.asyncWaitForVsync
g_async_wait_for_vsync_method_, //
java_baton //
);
});
}
// TODO(mattcarroll): add javadocs
// Called by native.
private static void asyncWaitForVsync(final long cookie) {
if (asyncWaitForVsyncDelegate != null) {
asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie);
} else {
throw new IllegalStateException(
"An AsyncWaitForVsyncDelegate must be registered with FlutterJNI before asyncWaitForVsync() is invoked.");
}
}
public class VsyncWaiter {
private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate =
new FlutterJNI.AsyncWaitForVsyncDelegate() {
@Override
public void asyncWaitForVsync(long cookie) {
Choreographer.getInstance()
.postFrameCallback(
new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
float fps = windowManager.getDefaultDisplay().getRefreshRate();
long refreshPeriodNanos = (long) (1000000000.0 / fps);
FlutterJNI.nativeOnVsync(
frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie);
}
});
}
};
shell/platform/android/vsync_waiter_android.cc
// static
void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env,
jclass jcaller,
jlong frameTimeNanos,
jlong frameTargetTimeNanos,
jlong java_baton) {
TRACE_EVENT0("flutter", "VSYNC");
auto frame_time = fml::TimePoint::FromEpochDelta(
fml::TimeDelta::FromNanoseconds(frameTimeNanos));
auto target_time = fml::TimePoint::FromEpochDelta(
fml::TimeDelta::FromNanoseconds(frameTargetTimeNanos));
ConsumePendingCallback(java_baton, frame_time, target_time);
}
void VsyncWaiterAndroid::ConsumePendingCallback(
jlong java_baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
auto* weak_this = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(java_baton);
auto shared_this = weak_this->lock();
delete weak_this;
if (shared_this) {
shared_this->FireCallback(frame_start_time, frame_target_time);
}
}
https://api.flutter.dev/javadoc/io/flutter/embedding/engine/FlutterEngine.html
https://engine.chinmaygarde.com/classtonic_1_1_dart_persistent_value.html