flutter_flutter/shell/platform/embedder/embedder_engine.cc
Chinmay Garde c5329ef5c4
Allow embedders to schedule a callback on all engine managed threads. (#15980)
`FlutterEnginePostCallbackOnAllNativeThreads` schedule a callback to be run on
all engine managed threads. The engine will attempt to service this callback the
next time the message loops for each managed thread is idle. Since the engine
manages the entire lifecycle of multiple threads, there is no opportunity for
the embedders to finely tune the priorities of threads directly, or, perform
other thread specific configuration (for example, setting thread names for
tracing). This callback gives embedders a chance to affect such tuning.

Fixes flutter/flutter#49551
Fixes b/143774406
Fixes b/148278215
Fixes b/148278931
2020-01-27 13:49:39 -08:00

283 lines
7.8 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/embedder/embedder_engine.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/shell/platform/embedder/vsync_waiter_embedder.h"
namespace flutter {
struct ShellArgs {
Settings settings;
Shell::CreateCallback<PlatformView> on_create_platform_view;
Shell::CreateCallback<Rasterizer> on_create_rasterizer;
ShellArgs(Settings p_settings,
Shell::CreateCallback<PlatformView> p_on_create_platform_view,
Shell::CreateCallback<Rasterizer> p_on_create_rasterizer)
: settings(std::move(p_settings)),
on_create_platform_view(std::move(p_on_create_platform_view)),
on_create_rasterizer(std::move(p_on_create_rasterizer)) {}
};
EmbedderEngine::EmbedderEngine(
std::unique_ptr<EmbedderThreadHost> thread_host,
flutter::TaskRunners task_runners,
flutter::Settings settings,
RunConfiguration run_configuration,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback)
: thread_host_(std::move(thread_host)),
task_runners_(task_runners),
run_configuration_(std::move(run_configuration)),
shell_args_(std::make_unique<ShellArgs>(std::move(settings),
on_create_platform_view,
on_create_rasterizer)),
external_texture_callback_(external_texture_callback) {}
EmbedderEngine::~EmbedderEngine() = default;
bool EmbedderEngine::LaunchShell() {
if (!shell_args_) {
FML_DLOG(ERROR) << "Invalid shell arguments.";
return false;
}
if (shell_) {
FML_DLOG(ERROR) << "Shell already initialized";
}
shell_ = Shell::Create(task_runners_, shell_args_->settings,
shell_args_->on_create_platform_view,
shell_args_->on_create_rasterizer);
// Reset the args no matter what. They will never be used to initialize a
// shell again.
shell_args_.reset();
return IsValid();
}
bool EmbedderEngine::CollectShell() {
shell_.reset();
return IsValid();
}
bool EmbedderEngine::RunRootIsolate() {
if (!IsValid() || !run_configuration_.IsValid()) {
return false;
}
shell_->RunEngine(std::move(run_configuration_));
return true;
}
bool EmbedderEngine::IsValid() const {
return static_cast<bool>(shell_);
}
const TaskRunners& EmbedderEngine::GetTaskRunners() const {
return task_runners_;
}
bool EmbedderEngine::NotifyCreated() {
if (!IsValid()) {
return false;
}
shell_->GetPlatformView()->NotifyCreated();
return true;
}
bool EmbedderEngine::NotifyDestroyed() {
if (!IsValid()) {
return false;
}
shell_->GetPlatformView()->NotifyDestroyed();
return true;
}
bool EmbedderEngine::SetViewportMetrics(flutter::ViewportMetrics metrics) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetViewportMetrics(std::move(metrics));
return true;
}
bool EmbedderEngine::DispatchPointerDataPacket(
std::unique_ptr<flutter::PointerDataPacket> packet) {
if (!IsValid() || !packet) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchPointerDataPacket(std::move(packet));
return true;
}
bool EmbedderEngine::SendPlatformMessage(
fml::RefPtr<flutter::PlatformMessage> message) {
if (!IsValid() || !message) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchPlatformMessage(message);
return true;
}
bool EmbedderEngine::RegisterTexture(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->RegisterTexture(
std::make_unique<EmbedderExternalTextureGL>(texture,
external_texture_callback_));
return true;
}
bool EmbedderEngine::UnregisterTexture(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->UnregisterTexture(texture);
return true;
}
bool EmbedderEngine::MarkTextureFrameAvailable(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->MarkTextureFrameAvailable(texture);
return true;
}
bool EmbedderEngine::SetSemanticsEnabled(bool enabled) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetSemanticsEnabled(enabled);
return true;
}
bool EmbedderEngine::SetAccessibilityFeatures(int32_t flags) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetAccessibilityFeatures(flags);
return true;
}
bool EmbedderEngine::DispatchSemanticsAction(int id,
flutter::SemanticsAction action,
std::vector<uint8_t> args) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchSemanticsAction(id, action, std::move(args));
return true;
}
bool EmbedderEngine::OnVsyncEvent(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
if (!IsValid()) {
return false;
}
return VsyncWaiterEmbedder::OnEmbedderVsync(baton, frame_start_time,
frame_target_time);
}
bool EmbedderEngine::ReloadSystemFonts() {
if (!IsValid()) {
return false;
}
return shell_->ReloadSystemFonts();
}
bool EmbedderEngine::PostRenderThreadTask(const fml::closure& task) {
if (!IsValid()) {
return false;
}
shell_->GetTaskRunners().GetGPUTaskRunner()->PostTask(task);
return true;
}
bool EmbedderEngine::RunTask(const FlutterTask* task) {
// The shell doesn't need to be running or valid for access to the thread
// host. This is why there is no `IsValid` check here. This allows embedders
// to perform custom task runner interop before the shell is running.
if (task == nullptr) {
return false;
}
return thread_host_->PostTask(reinterpret_cast<int64_t>(task->runner),
task->task);
}
bool EmbedderEngine::PostTaskOnEngineManagedNativeThreads(
std::function<void(FlutterNativeThreadType)> closure) const {
if (!IsValid() || closure == nullptr) {
return false;
}
const auto trampoline = [closure](FlutterNativeThreadType type,
fml::RefPtr<fml::TaskRunner> runner) {
runner->PostTask([closure, type] { closure(type); });
};
// Post the task to all thread host threads.
const auto& task_runners = shell_->GetTaskRunners();
trampoline(kFlutterNativeThreadTypeRender, task_runners.GetGPUTaskRunner());
trampoline(kFlutterNativeThreadTypeWorker, task_runners.GetIOTaskRunner());
trampoline(kFlutterNativeThreadTypeUI, task_runners.GetUITaskRunner());
trampoline(kFlutterNativeThreadTypePlatform,
task_runners.GetPlatformTaskRunner());
// Post the task to all worker threads.
auto vm = shell_->GetDartVM();
vm->GetConcurrentMessageLoop()->PostTaskToAllWorkers(
[closure]() { closure(kFlutterNativeThreadTypeWorker); });
return true;
}
Shell& EmbedderEngine::GetShell() {
FML_DCHECK(shell_);
return *shell_.get();
}
} // namespace flutter