mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
207 lines
6.6 KiB
C++
207 lines
6.6 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.
|
|
|
|
// This is why we can't yet export the UI thread to embedders.
|
|
#define FML_USED_ON_EMBEDDER
|
|
|
|
#include "flutter/shell/platform/embedder/embedder_thread_host.h"
|
|
|
|
#include "flutter/fml/message_loop.h"
|
|
#include "flutter/shell/platform/embedder/embedder_safe_access.h"
|
|
|
|
namespace flutter {
|
|
|
|
static fml::RefPtr<EmbedderTaskRunner> CreateEmbedderTaskRunner(
|
|
const FlutterTaskRunnerDescription* description) {
|
|
if (description == nullptr) {
|
|
return {};
|
|
}
|
|
|
|
if (SAFE_ACCESS(description, runs_task_on_current_thread_callback, nullptr) ==
|
|
nullptr) {
|
|
FML_LOG(ERROR) << "FlutterTaskRunnerDescription.runs_task_on_current_"
|
|
"thread_callback was nullptr.";
|
|
return {};
|
|
}
|
|
|
|
if (SAFE_ACCESS(description, post_task_callback, nullptr) == nullptr) {
|
|
FML_LOG(ERROR)
|
|
<< "FlutterTaskRunnerDescription.post_task_callback was nullptr.";
|
|
return {};
|
|
}
|
|
|
|
auto user_data = SAFE_ACCESS(description, user_data, nullptr);
|
|
|
|
// ABI safety checks have been completed.
|
|
auto post_task_callback_c = description->post_task_callback;
|
|
auto runs_task_on_current_thread_callback_c =
|
|
description->runs_task_on_current_thread_callback;
|
|
|
|
EmbedderTaskRunner::DispatchTable task_runner_dispatch_table = {
|
|
// .post_task_callback
|
|
[post_task_callback_c, user_data](EmbedderTaskRunner* task_runner,
|
|
uint64_t task_baton,
|
|
fml::TimePoint target_time) -> void {
|
|
FlutterTask task = {
|
|
// runner
|
|
reinterpret_cast<FlutterTaskRunner>(task_runner),
|
|
// task
|
|
task_baton,
|
|
};
|
|
post_task_callback_c(task, target_time.ToEpochDelta().ToNanoseconds(),
|
|
user_data);
|
|
},
|
|
// runs_task_on_current_thread_callback
|
|
[runs_task_on_current_thread_callback_c, user_data]() -> bool {
|
|
return runs_task_on_current_thread_callback_c(user_data);
|
|
}};
|
|
|
|
return fml::MakeRefCounted<EmbedderTaskRunner>(task_runner_dispatch_table);
|
|
}
|
|
|
|
std::unique_ptr<EmbedderThreadHost>
|
|
EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost(
|
|
const FlutterCustomTaskRunners* custom_task_runners) {
|
|
{
|
|
auto host = CreateEmbedderManagedThreadHost(custom_task_runners);
|
|
if (host && host->IsValid()) {
|
|
return host;
|
|
}
|
|
}
|
|
|
|
// Only attempt to create the engine managed host if the embedder did not
|
|
// specify a custom configuration. We don't want to fallback to the engine
|
|
// managed configuration if the embedder attempted to specify a configuration
|
|
// but messed up with an incorrect configuration.
|
|
if (custom_task_runners == nullptr) {
|
|
auto host = CreateEngineManagedThreadHost();
|
|
if (host && host->IsValid()) {
|
|
return host;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
constexpr const char* kFlutterThreadName = "io.flutter";
|
|
|
|
// static
|
|
std::unique_ptr<EmbedderThreadHost>
|
|
EmbedderThreadHost::CreateEmbedderManagedThreadHost(
|
|
const FlutterCustomTaskRunners* custom_task_runners) {
|
|
if (custom_task_runners == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
const auto platform_task_runner = CreateEmbedderTaskRunner(
|
|
SAFE_ACCESS(custom_task_runners, platform_task_runner, nullptr));
|
|
|
|
// TODO(chinmaygarde): Add more here as we allow more threads to be controlled
|
|
// by the embedder. Create fallbacks as necessary.
|
|
|
|
if (!platform_task_runner) {
|
|
return nullptr;
|
|
}
|
|
|
|
ThreadHost thread_host(kFlutterThreadName, ThreadHost::Type::GPU |
|
|
ThreadHost::Type::IO |
|
|
ThreadHost::Type::UI);
|
|
|
|
flutter::TaskRunners task_runners(
|
|
kFlutterThreadName,
|
|
platform_task_runner, // platform
|
|
thread_host.gpu_thread->GetTaskRunner(), // gpu
|
|
thread_host.ui_thread->GetTaskRunner(), // ui
|
|
thread_host.io_thread->GetTaskRunner() // io
|
|
);
|
|
|
|
if (!task_runners.IsValid()) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners;
|
|
embedder_task_runners.insert(platform_task_runner);
|
|
|
|
auto embedder_host = std::make_unique<EmbedderThreadHost>(
|
|
std::move(thread_host), std::move(task_runners),
|
|
std::move(embedder_task_runners));
|
|
|
|
if (embedder_host->IsValid()) {
|
|
return embedder_host;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// static
|
|
std::unique_ptr<EmbedderThreadHost>
|
|
EmbedderThreadHost::CreateEngineManagedThreadHost() {
|
|
// Create a thread host with the current thread as the platform thread and all
|
|
// other threads managed.
|
|
ThreadHost thread_host(kFlutterThreadName, ThreadHost::Type::GPU |
|
|
ThreadHost::Type::IO |
|
|
ThreadHost::Type::UI);
|
|
|
|
fml::MessageLoop::EnsureInitializedForCurrentThread();
|
|
|
|
// For embedder platforms that don't have native message loop interop, this
|
|
// will reference a task runner that points to a null message loop
|
|
// implementation.
|
|
auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
|
|
|
|
flutter::TaskRunners task_runners(
|
|
kFlutterThreadName,
|
|
platform_task_runner, // platform
|
|
thread_host.gpu_thread->GetTaskRunner(), // gpu
|
|
thread_host.ui_thread->GetTaskRunner(), // ui
|
|
thread_host.io_thread->GetTaskRunner() // io
|
|
);
|
|
|
|
if (!task_runners.IsValid()) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::set<fml::RefPtr<EmbedderTaskRunner>> empty_embedder_task_runners;
|
|
|
|
auto embedder_host = std::make_unique<EmbedderThreadHost>(
|
|
std::move(thread_host), std::move(task_runners),
|
|
empty_embedder_task_runners);
|
|
|
|
if (embedder_host->IsValid()) {
|
|
return embedder_host;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
EmbedderThreadHost::EmbedderThreadHost(
|
|
ThreadHost host,
|
|
flutter::TaskRunners runners,
|
|
std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners)
|
|
: host_(std::move(host)), runners_(std::move(runners)) {
|
|
for (const auto& runner : embedder_task_runners) {
|
|
runners_map_[reinterpret_cast<int64_t>(runner.get())] = runner;
|
|
}
|
|
}
|
|
|
|
EmbedderThreadHost::~EmbedderThreadHost() = default;
|
|
|
|
bool EmbedderThreadHost::IsValid() const {
|
|
return runners_.IsValid();
|
|
}
|
|
|
|
const flutter::TaskRunners& EmbedderThreadHost::GetTaskRunners() const {
|
|
return runners_;
|
|
}
|
|
|
|
bool EmbedderThreadHost::PostTask(int64_t runner, uint64_t task) const {
|
|
auto found = runners_map_.find(runner);
|
|
if (found == runners_map_.end()) {
|
|
return false;
|
|
}
|
|
return found->second->PostTask(task);
|
|
}
|
|
|
|
} // namespace flutter
|