diff --git a/common/settings.h b/common/settings.h index 9e61e729d978d..b857b4aade6a2 100644 --- a/common/settings.h +++ b/common/settings.h @@ -74,6 +74,12 @@ struct Settings { // The isolate is not current and may have already been destroyed when this // call is made. fml::closure root_isolate_shutdown_callback; + // The callback made on the UI thread in an isolate scope when the engine + // detects that the framework is idle. The VM also uses this time to perform + // tasks suitable when idling. Due to this, embedders are still advised to be + // as fast as possible in returning from this callback. Long running + // operations in this callback do have the capability of introducing jank. + fml::closure idle_notification_callback; bool enable_software_rendering = false; bool skia_deterministic_rendering_on_cpu = false; bool verbose_logging = false; diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index ac99aa5f99ac5..e4c3c3289e006 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -24,7 +24,8 @@ RuntimeController::RuntimeController( fml::WeakPtr p_resource_context, fml::RefPtr p_unref_queue, std::string p_advisory_script_uri, - std::string p_advisory_script_entrypoint) + std::string p_advisory_script_entrypoint, + fml::closure p_idle_notification_callback) : RuntimeController(p_client, p_vm, std::move(p_isolate_snapshot), @@ -35,6 +36,7 @@ RuntimeController::RuntimeController( std::move(p_unref_queue), std::move(p_advisory_script_uri), std::move(p_advisory_script_entrypoint), + p_idle_notification_callback, WindowData{/* default window data */}) {} RuntimeController::RuntimeController( @@ -48,6 +50,7 @@ RuntimeController::RuntimeController( fml::RefPtr p_unref_queue, std::string p_advisory_script_uri, std::string p_advisory_script_entrypoint, + fml::closure idle_notification_callback, WindowData p_window_data) : client_(p_client), vm_(p_vm), @@ -59,6 +62,7 @@ RuntimeController::RuntimeController( unref_queue_(p_unref_queue), advisory_script_uri_(p_advisory_script_uri), advisory_script_entrypoint_(p_advisory_script_entrypoint), + idle_notification_callback_(idle_notification_callback), window_data_(std::move(p_window_data)), root_isolate_( DartIsolate::CreateRootIsolate(vm_, @@ -120,6 +124,7 @@ std::unique_ptr RuntimeController::Clone() const { unref_queue_, // advisory_script_uri_, // advisory_script_entrypoint_, // + idle_notification_callback_, // window_data_ // )); } @@ -201,7 +206,14 @@ bool RuntimeController::NotifyIdle(int64_t deadline) { } tonic::DartState::Scope scope(root_isolate); + Dart_NotifyIdle(deadline); + + // Idle notifications being in isolate scope are part of the contract. + if (idle_notification_callback_) { + TRACE_EVENT0("flutter", "EmbedderIdleNotification"); + idle_notification_callback_(); + } return true; } diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 05278740735de..5bbb47e221e77 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -36,7 +36,8 @@ class RuntimeController final : public WindowClient { fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, - std::string advisory_script_entrypoint); + std::string advisory_script_entrypoint, + fml::closure idle_notification_callback); ~RuntimeController() override; @@ -125,6 +126,7 @@ class RuntimeController final : public WindowClient { fml::RefPtr unref_queue_; std::string advisory_script_uri_; std::string advisory_script_entrypoint_; + fml::closure idle_notification_callback_; WindowData window_data_; std::weak_ptr root_isolate_; std::pair root_isolate_return_code_ = {false, 0}; @@ -139,6 +141,7 @@ class RuntimeController final : public WindowClient { fml::RefPtr unref_queue, std::string advisory_script_uri, std::string advisory_script_entrypoint, + fml::closure idle_notification_callback, WindowData data); Window* GetWindowIfAvailable(); diff --git a/shell/common/engine.cc b/shell/common/engine.cc index ef3369347e055..aa88479baa755 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -54,16 +54,17 @@ Engine::Engine(Delegate& delegate, // object as its delegate. The delegate may be called in the constructor and // we want to be fully initilazed by that point. runtime_controller_ = std::make_unique( - *this, // runtime delegate - &vm, // VM - std::move(isolate_snapshot), // isolate snapshot - std::move(shared_snapshot), // shared snapshot - std::move(task_runners), // task runners - std::move(snapshot_delegate), // snapshot delegate - std::move(resource_context), // resource context - std::move(unref_queue), // skia unref queue - settings_.advisory_script_uri, // advisory script uri - settings_.advisory_script_entrypoint // advisory script entrypoint + *this, // runtime delegate + &vm, // VM + std::move(isolate_snapshot), // isolate snapshot + std::move(shared_snapshot), // shared snapshot + std::move(task_runners), // task runners + std::move(snapshot_delegate), // snapshot delegate + std::move(resource_context), // resource context + std::move(unref_queue), // skia unref queue + settings_.advisory_script_uri, // advisory script uri + settings_.advisory_script_entrypoint, // advisory script entrypoint + settings_.idle_notification_callback // idle notification callback ); }