diff --git a/fml/concurrent_message_loop.cc b/fml/concurrent_message_loop.cc index b58431b7df3d2..f352467c44f50 100644 --- a/fml/concurrent_message_loop.cc +++ b/fml/concurrent_message_loop.cc @@ -21,8 +21,8 @@ ConcurrentMessageLoop::ConcurrentMessageLoop(size_t worker_count) : worker_count_(std::max(worker_count, 1ul)) { for (size_t i = 0; i < worker_count_; ++i) { workers_.emplace_back([i, this]() { - fml::Thread::SetCurrentThreadName( - std::string{"io.worker." + std::to_string(i + 1)}); + fml::Thread::SetCurrentThreadName(fml::Thread::ThreadConfig( + std::string{"io.worker." + std::to_string(i + 1)})); WorkerMain(); }); } diff --git a/fml/thread.cc b/fml/thread.cc index 220d66dd07191..a905fd071eaa9 100644 --- a/fml/thread.cc +++ b/fml/thread.cc @@ -8,6 +8,7 @@ #include #include +#include #include "flutter/fml/build_config.h" #include "flutter/fml/message_loop.h" @@ -23,38 +24,6 @@ namespace fml { -Thread::Thread(const std::string& name) : joined_(false) { - fml::AutoResetWaitableEvent latch; - fml::RefPtr runner; - thread_ = std::make_unique([&latch, &runner, name]() -> void { - SetCurrentThreadName(name); - fml::MessageLoop::EnsureInitializedForCurrentThread(); - auto& loop = MessageLoop::GetCurrent(); - runner = loop.GetTaskRunner(); - latch.Signal(); - loop.Run(); - }); - latch.Wait(); - task_runner_ = runner; -} - -Thread::~Thread() { - Join(); -} - -fml::RefPtr Thread::GetTaskRunner() const { - return task_runner_; -} - -void Thread::Join() { - if (joined_) { - return; - } - joined_ = true; - task_runner_->PostTask([]() { MessageLoop::GetCurrent().Terminate(); }); - thread_->join(); -} - #if defined(FML_OS_WIN) // The information on how to set the thread name comes from // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx @@ -67,7 +36,7 @@ typedef struct tagTHREADNAME_INFO { } THREADNAME_INFO; #endif -void Thread::SetCurrentThreadName(const std::string& name) { +void SetThreadName(const std::string& name) { if (name == "") { return; } @@ -94,4 +63,46 @@ void Thread::SetCurrentThreadName(const std::string& name) { #endif } +void Thread::SetCurrentThreadName(const Thread::ThreadConfig& config) { + SetThreadName(config.name); +} + +Thread::Thread(const std::string& name) + : Thread(Thread::SetCurrentThreadName, ThreadConfig(name)) {} + +Thread::Thread(const ThreadConfigSetter& setter, const ThreadConfig& config) + : joined_(false) { + fml::AutoResetWaitableEvent latch; + fml::RefPtr runner; + + thread_ = std::make_unique( + [&latch, &runner, setter, config]() -> void { + setter(config); + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto& loop = MessageLoop::GetCurrent(); + runner = loop.GetTaskRunner(); + latch.Signal(); + loop.Run(); + }); + latch.Wait(); + task_runner_ = runner; +} + +Thread::~Thread() { + Join(); +} + +fml::RefPtr Thread::GetTaskRunner() const { + return task_runner_; +} + +void Thread::Join() { + if (joined_) { + return; + } + joined_ = true; + task_runner_->PostTask([]() { MessageLoop::GetCurrent().Terminate(); }); + thread_->join(); +} + } // namespace fml diff --git a/fml/thread.h b/fml/thread.h index 9d297c2a5502d..0b176c2ff5d6f 100644 --- a/fml/thread.h +++ b/fml/thread.h @@ -6,7 +6,9 @@ #define FLUTTER_FML_THREAD_H_ #include +#include #include +#include #include #include "flutter/fml/macros.h" @@ -16,19 +18,52 @@ namespace fml { class Thread { public: + /// Valid values for priority of Thread. + enum class ThreadPriority : int { + /// Suitable for threads that shouldn't disrupt high priority work. + BACKGROUND, + /// Default priority level. + NORMAL, + /// Suitable for threads which generate data for the display. + DISPLAY, + /// Suitable for thread which raster data. + RASTER, + }; + + /// The ThreadConfig is the thread info include thread name, thread priority. + struct ThreadConfig { + ThreadConfig(const std::string& name, ThreadPriority priority) + : name(name), priority(priority) {} + + explicit ThreadConfig(const std::string& name) + : ThreadConfig(name, ThreadPriority::NORMAL) {} + + ThreadConfig() : ThreadConfig("", ThreadPriority::NORMAL) {} + + std::string name; + ThreadPriority priority; + }; + + using ThreadConfigSetter = std::function; + explicit Thread(const std::string& name = ""); + explicit Thread(const ThreadConfigSetter& setter, + const ThreadConfig& config = ThreadConfig()); + ~Thread(); fml::RefPtr GetTaskRunner() const; void Join(); - static void SetCurrentThreadName(const std::string& name); + static void SetCurrentThreadName(const ThreadConfig& config); private: std::unique_ptr thread_; + fml::RefPtr task_runner_; + std::atomic_bool joined_; FML_DISALLOW_COPY_AND_ASSIGN(Thread); diff --git a/fml/thread_unittests.cc b/fml/thread_unittests.cc index 5f8502753ce2d..6e8001ac8b0bd 100644 --- a/fml/thread_unittests.cc +++ b/fml/thread_unittests.cc @@ -4,6 +4,18 @@ #include "flutter/fml/thread.h" +#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_ANDROID) +#define FLUTTER_PTHREAD_SUPPORTED 1 +#else +#define FLUTTER_PTHREAD_SUPPORTED 0 +#endif + +#if FLUTTER_PTHREAD_SUPPORTED +#include +#else +#endif + +#include #include "gtest/gtest.h" TEST(Thread, CanStartAndEnd) { @@ -24,3 +36,77 @@ TEST(Thread, HasARunningMessageLoop) { thread.Join(); ASSERT_TRUE(done); } + +#if FLUTTER_PTHREAD_SUPPORTED +TEST(Thread, ThreadNameCreatedWithConfig) { + const std::string name = "Thread1"; + fml::Thread thread(name); + + bool done = false; + thread.GetTaskRunner()->PostTask([&done, &name]() { + done = true; + char thread_name[8]; + pthread_t current_thread = pthread_self(); + pthread_getname_np(current_thread, thread_name, 8); + ASSERT_EQ(thread_name, name); + }); + thread.Join(); + ASSERT_TRUE(done); +} + +static void MockThreadConfigSetter(const fml::Thread::ThreadConfig& config) { + // set thread name + fml::Thread::SetCurrentThreadName(config); + + pthread_t tid = pthread_self(); + struct sched_param param; + int policy = SCHED_OTHER; + switch (config.priority) { + case fml::Thread::ThreadPriority::DISPLAY: + param.sched_priority = 10; + break; + default: + param.sched_priority = 1; + } + pthread_setschedparam(tid, policy, ¶m); +} + +TEST(Thread, ThreadPriorityCreatedWithConfig) { + const std::string thread1_name = "Thread1"; + const std::string thread2_name = "Thread2"; + + fml::Thread thread(MockThreadConfigSetter, + fml::Thread::ThreadConfig( + thread1_name, fml::Thread::ThreadPriority::NORMAL)); + bool done = false; + + struct sched_param param; + int policy; + thread.GetTaskRunner()->PostTask([&]() { + done = true; + char thread_name[8]; + pthread_t current_thread = pthread_self(); + pthread_getname_np(current_thread, thread_name, 8); + pthread_getschedparam(current_thread, &policy, ¶m); + ASSERT_EQ(thread_name, thread1_name); + ASSERT_EQ(policy, SCHED_OTHER); + ASSERT_EQ(param.sched_priority, 1); + }); + + fml::Thread thread2(MockThreadConfigSetter, + fml::Thread::ThreadConfig( + thread2_name, fml::Thread::ThreadPriority::DISPLAY)); + thread2.GetTaskRunner()->PostTask([&]() { + done = true; + char thread_name[8]; + pthread_t current_thread = pthread_self(); + pthread_getname_np(current_thread, thread_name, 8); + pthread_getschedparam(current_thread, &policy, ¶m); + ASSERT_EQ(thread_name, thread2_name); + ASSERT_EQ(policy, SCHED_OTHER); + ASSERT_EQ(param.sched_priority, 10); + }); + thread.Join(); + ASSERT_TRUE(done); +} +#endif diff --git a/lib/ui/ui_benchmarks.cc b/lib/ui/ui_benchmarks.cc index a88877dac798d..4c8239b0f5dfe 100644 --- a/lib/ui/ui_benchmarks.cc +++ b/lib/ui/ui_benchmarks.cc @@ -20,9 +20,9 @@ class Fixture : public testing::FixtureTest { }; static void BM_PlatformMessageResponseDartComplete(benchmark::State& state) { - ThreadHost thread_host("test", - ThreadHost::Type::Platform | ThreadHost::Type::RASTER | - ThreadHost::Type::IO | ThreadHost::Type::UI); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "test", ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI)); TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), @@ -68,9 +68,9 @@ static void BM_PlatformMessageResponseDartComplete(benchmark::State& state) { } static void BM_PathVolatilityTracker(benchmark::State& state) { - ThreadHost thread_host("test", - ThreadHost::Type::Platform | ThreadHost::Type::RASTER | - ThreadHost::Type::IO | ThreadHost::Type::UI); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "test", ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI)); TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), diff --git a/shell/common/shell_benchmarks.cc b/shell/common/shell_benchmarks.cc index cf73ab352fcf7..09a696c8af026 100644 --- a/shell/common/shell_benchmarks.cc +++ b/shell/common/shell_benchmarks.cc @@ -43,10 +43,10 @@ static void StartupAndShutdownShell(benchmark::State& state, }; } - thread_host = std::make_unique( + thread_host = std::make_unique(ThreadHost::ThreadHostConfig( "io.flutter.bench.", ThreadHost::Type::Platform | ThreadHost::Type::RASTER | - ThreadHost::Type::IO | ThreadHost::Type::UI); + ThreadHost::Type::IO | ThreadHost::Type::UI)); TaskRunners task_runners("test", thread_host->platform_thread->GetTaskRunner(), diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 8de99aeb0ca9c..4070a79abd0b8 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -267,9 +267,10 @@ TEST_F(ShellTest, InitializeWithInvalidThreads) { TEST_F(ShellTest, InitializeWithDifferentThreads) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); - ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", - ThreadHost::Type::Platform | ThreadHost::Type::RASTER | - ThreadHost::Type::IO | ThreadHost::Type::UI); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI)); TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), thread_host.raster_thread->GetTaskRunner(), thread_host.ui_thread->GetTaskRunner(), @@ -3116,8 +3117,9 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeAppends) { TEST_F(ShellTest, UpdateAssetResolverByTypeNull) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); - ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", - ThreadHost::Type::Platform); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::Platform)); auto task_runner = thread_host.platform_thread->GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); @@ -3153,8 +3155,9 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeNull) { TEST_F(ShellTest, UpdateAssetResolverByTypeDoesNotReplaceMismatchType) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); - ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", - ThreadHost::Type::Platform); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::Platform)); auto task_runner = thread_host.platform_thread->GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); diff --git a/shell/common/thread_host.cc b/shell/common/thread_host.cc index 2e0d539fa82f0..b79ed6c99a0da 100644 --- a/shell/common/thread_host.cc +++ b/shell/common/thread_host.cc @@ -4,32 +4,73 @@ #include "flutter/shell/common/thread_host.h" +#include +#include +#include +#include +#include + namespace flutter { +std::string ThreadHost::ThreadHostConfig::MakeThreadName( + Type type, + const std::string& prefix) { + switch (type) { + case Type::Platform: + return prefix + ".platform"; + case Type::UI: + return prefix + ".ui"; + case Type::IO: + return prefix + ".io"; + case Type::RASTER: + return prefix + ".raster"; + case Type::Profiler: + return prefix + ".profiler"; + } +} + +std::unique_ptr ThreadHost::CreateThread( + Type type, + std::optional thread_config, + const ThreadHostConfig& host_config) const { + /// if not specified ThreadConfig, create a ThreadConfig. + if (!thread_config.has_value()) { + thread_config = ThreadConfig( + ThreadHostConfig::MakeThreadName(type, host_config.name_prefix)); + } + return std::make_unique(host_config.config_setter, + thread_config.value()); +} + ThreadHost::ThreadHost() = default; ThreadHost::ThreadHost(ThreadHost&&) = default; -ThreadHost::ThreadHost(std::string name_prefix_arg, uint64_t mask) - : name_prefix(name_prefix_arg) { - if (mask & ThreadHost::Type::Platform) { - platform_thread = std::make_unique(name_prefix + ".platform"); +ThreadHost::ThreadHost(const std::string name_prefix, uint64_t mask) + : ThreadHost(ThreadHostConfig(name_prefix, mask)) {} + +ThreadHost::ThreadHost(const ThreadHostConfig& host_config) { + if (host_config.isThreadNeeded(ThreadHost::Type::Platform)) { + platform_thread = + CreateThread(Type::Platform, host_config.platform_config, host_config); } - if (mask & ThreadHost::Type::UI) { - ui_thread = std::make_unique(name_prefix + ".ui"); + if (host_config.isThreadNeeded(ThreadHost::Type::UI)) { + ui_thread = CreateThread(Type::UI, host_config.ui_config, host_config); } - if (mask & ThreadHost::Type::RASTER) { - raster_thread = std::make_unique(name_prefix + ".raster"); + if (host_config.isThreadNeeded(ThreadHost::Type::RASTER)) { + raster_thread = + CreateThread(Type::RASTER, host_config.raster_config, host_config); } - if (mask & ThreadHost::Type::IO) { - io_thread = std::make_unique(name_prefix + ".io"); + if (host_config.isThreadNeeded(ThreadHost::Type::IO)) { + io_thread = CreateThread(Type::IO, host_config.io_config, host_config); } - if (mask & ThreadHost::Type::Profiler) { - profiler_thread = std::make_unique(name_prefix + ".profiler"); + if (host_config.isThreadNeeded(ThreadHost::Type::Profiler)) { + profiler_thread = + CreateThread(Type::Profiler, host_config.profiler_config, host_config); } } diff --git a/shell/common/thread_host.h b/shell/common/thread_host.h index d944963282cb9..598b67e4babe3 100644 --- a/shell/common/thread_host.h +++ b/shell/common/thread_host.h @@ -6,12 +6,17 @@ #define FLUTTER_SHELL_COMMON_THREAD_HOST_H_ #include +#include +#include #include "flutter/fml/macros.h" #include "flutter/fml/thread.h" namespace flutter { +using ThreadConfig = fml::Thread::ThreadConfig; +using ThreadConfigSetter = fml::Thread::ThreadConfigSetter; + /// The collection of all the threads used by the engine. struct ThreadHost { enum Type { @@ -22,6 +27,41 @@ struct ThreadHost { Profiler = 1 << 4, }; + /// The collection of all the thread configures, and we create custom thread + /// configure in engine to info the thread. + struct ThreadHostConfig { + ThreadHostConfig() : type_mask(0) {} + + ThreadHostConfig( + const std::string& name_prefix, + uint64_t mask, + const ThreadConfigSetter& setter = fml::Thread::SetCurrentThreadName) + : type_mask(mask), name_prefix(name_prefix), config_setter(setter) {} + + explicit ThreadHostConfig( + uint64_t mask, + const ThreadConfigSetter& setter = fml::Thread::SetCurrentThreadName) + : ThreadHostConfig("", mask, setter) {} + + /// Check if need to create thread. + bool isThreadNeeded(Type type) const { return type_mask & type; } + + /// Use the prefix and thread type to generator a thread name. + static std::string MakeThreadName(Type type, const std::string& prefix); + + uint64_t type_mask; + + std::string name_prefix = ""; + + const ThreadConfigSetter config_setter; + + std::optional platform_config; + std::optional ui_config; + std::optional raster_config; + std::optional io_config; + std::optional profiler_config; + }; + std::string name_prefix; std::unique_ptr platform_thread; std::unique_ptr ui_thread; @@ -35,9 +75,17 @@ struct ThreadHost { ThreadHost& operator=(ThreadHost&&) = default; - ThreadHost(std::string name_prefix, uint64_t type_mask); + ThreadHost(const std::string name_prefix, uint64_t mask); + + explicit ThreadHost(const ThreadHostConfig& host_config); ~ThreadHost(); + + private: + std::unique_ptr CreateThread( + Type type, + std::optional thread_config, + const ThreadHostConfig& host_config) const; }; } // namespace flutter diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc index 4205864189a0b..9b376bc848233 100644 --- a/shell/platform/android/android_context_gl_unittests.cc +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -80,9 +80,10 @@ TEST(AndroidContextGl, Create) { auto environment = fml::MakeRefCounted(); std::string thread_label = ::testing::UnitTest::GetInstance()->current_test_info()->name(); - ThreadHost thread_host(thread_label, ThreadHost::Type::UI | - ThreadHost::Type::RASTER | - ThreadHost::Type::IO); + + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + thread_label, + ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO)); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); auto context = std::make_unique( AndroidRenderingAPI::kOpenGLES, environment, task_runners); @@ -120,9 +121,9 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNotNull) { auto environment = fml::MakeRefCounted(); std::string thread_label = ::testing::UnitTest::GetInstance()->current_test_info()->name(); - ThreadHost thread_host(thread_label, ThreadHost::Type::UI | - ThreadHost::Type::RASTER | - ThreadHost::Type::IO); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + thread_label, + ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO)); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); auto android_context = std::make_shared( AndroidRenderingAPI::kOpenGLES, environment, task_runners); @@ -145,9 +146,12 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNull) { auto environment = fml::MakeRefCounted(); std::string thread_label = ::testing::UnitTest::GetInstance()->current_test_info()->name(); - ThreadHost thread_host(thread_label, ThreadHost::Type::UI | - ThreadHost::Type::RASTER | - ThreadHost::Type::IO); + + auto mask = + ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO; + flutter::ThreadHost::ThreadHostConfig host_config(mask); + + ThreadHost thread_host(host_config); TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host); auto android_context = std::make_shared( AndroidRenderingAPI::kOpenGLES, environment, task_runners); diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index f425e2041cc1c..14e8555c40c16 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -32,6 +32,45 @@ namespace flutter { +/// Inheriting ThreadConfigurer and use Android platform thread API to configure +/// the thread priorities +static void AndroidPlatformThreadConfigSetter( + const fml::Thread::ThreadConfig& config) { + // set thread name + fml::Thread::SetCurrentThreadName(config); + // set thread priority + switch (config.priority) { + case fml::Thread::ThreadPriority::BACKGROUND: { + if (::setpriority(PRIO_PROCESS, 0, 10) != 0) { + FML_LOG(ERROR) << "Failed to set IO task runner priority"; + } + break; + } + case fml::Thread::ThreadPriority::DISPLAY: { + if (::setpriority(PRIO_PROCESS, 0, -1) != 0) { + FML_LOG(ERROR) << "Failed to set UI task runner priority"; + } + break; + } + case fml::Thread::ThreadPriority::RASTER: { + // Android describes -8 as "most important display threads, for + // compositing the screen and retrieving input events". Conservatively + // set the raster thread to slightly lower priority than it. + if (::setpriority(PRIO_PROCESS, 0, -5) != 0) { + // Defensive fallback. Depending on the OEM, it may not be possible + // to set priority to -5. + if (::setpriority(PRIO_PROCESS, 0, -2) != 0) { + FML_LOG(ERROR) << "Failed to set raster task runner priority"; + } + } + break; + } + default: + if (::setpriority(PRIO_PROCESS, 0, 0) != 0) { + FML_LOG(ERROR) << "Failed to set priority"; + } + } +} static PlatformData GetDefaultPlatformData() { PlatformData platform_data; platform_data.lifecycle_state = "AppLifecycleState.detached"; @@ -45,10 +84,25 @@ AndroidShellHolder::AndroidShellHolder( static size_t thread_host_count = 1; auto thread_label = std::to_string(thread_host_count++); - thread_host_ = std::make_shared(); - *thread_host_ = {thread_label, ThreadHost::Type::UI | - ThreadHost::Type::RASTER | - ThreadHost::Type::IO}; + auto mask = + ThreadHost::Type::UI | ThreadHost::Type::RASTER | ThreadHost::Type::IO; + + flutter::ThreadHost::ThreadHostConfig host_config( + mask, AndroidPlatformThreadConfigSetter); + host_config.ui_config = fml::Thread::ThreadConfig( + flutter::ThreadHost::ThreadHostConfig::MakeThreadName( + flutter::ThreadHost::Type::UI, thread_label), + fml::Thread::ThreadPriority::DISPLAY); + host_config.raster_config = fml::Thread::ThreadConfig( + flutter::ThreadHost::ThreadHostConfig::MakeThreadName( + flutter::ThreadHost::Type::RASTER, thread_label), + fml::Thread::ThreadPriority::RASTER); + host_config.io_config = fml::Thread::ThreadConfig( + flutter::ThreadHost::ThreadHostConfig::MakeThreadName( + flutter::ThreadHost::Type::IO, thread_label), + fml::Thread::ThreadPriority::BACKGROUND); + + thread_host_ = std::make_shared(host_config); fml::WeakPtr weak_platform_view; Shell::CreateCallback on_create_platform_view = @@ -91,28 +145,6 @@ AndroidShellHolder::AndroidShellHolder( ui_runner, // ui io_runner // io ); - task_runners.GetRasterTaskRunner()->PostTask([]() { - // Android describes -8 as "most important display threads, for - // compositing the screen and retrieving input events". Conservatively - // set the raster thread to slightly lower priority than it. - if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) { - // Defensive fallback. Depending on the OEM, it may not be possible - // to set priority to -5. - if (::setpriority(PRIO_PROCESS, gettid(), -2) != 0) { - FML_LOG(ERROR) << "Failed to set raster task runner priority"; - } - } - }); - task_runners.GetUITaskRunner()->PostTask([]() { - if (::setpriority(PRIO_PROCESS, gettid(), -1) != 0) { - FML_LOG(ERROR) << "Failed to set UI task runner priority"; - } - }); - task_runners.GetIOTaskRunner()->PostTask([]() { - if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) { - FML_LOG(ERROR) << "Failed to set IO task runner priority"; - } - }); shell_ = Shell::Create(GetDefaultPlatformData(), // window data diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 30d1d1d8004c4..9c867eaaa9d84 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -34,6 +34,37 @@ #import "flutter/shell/platform/darwin/ios/rendering_api_selection.h" #include "flutter/shell/profiling/sampling_profiler.h" +/// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities +/// Using iOS platform thread API to configure thread priority +static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig& config) { + // set thread name + fml::Thread::SetCurrentThreadName(config); + + // set thread priority + switch (config.priority) { + case fml::Thread::ThreadPriority::BACKGROUND: { + [[NSThread currentThread] setThreadPriority:0]; + break; + } + case fml::Thread::ThreadPriority::NORMAL: { + [[NSThread currentThread] setThreadPriority:0.5]; + break; + } + case fml::Thread::ThreadPriority::RASTER: + case fml::Thread::ThreadPriority::DISPLAY: { + [[NSThread currentThread] setThreadPriority:1.0]; + sched_param param; + int policy; + pthread_t thread = pthread_self(); + if (!pthread_getschedparam(thread, &policy, ¶m)) { + param.sched_priority = 50; + pthread_setschedparam(thread, policy, ¶m); + } + break; + } + } +} + NSString* const FlutterDefaultDartEntrypoint = nil; NSString* const FlutterDefaultInitialRoute = nil; NSString* const FlutterEngineWillDealloc = @"FlutterEngineWillDealloc"; @@ -613,11 +644,29 @@ + (NSString*)generateThreadLabel:(NSString*)labelPrefix { uint32_t threadHostType = flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::RASTER | flutter::ThreadHost::Type::IO; + if ([FlutterEngine isProfilerEnabled]) { threadHostType = threadHostType | flutter::ThreadHost::Type::Profiler; } - return {threadLabel.UTF8String, // label - threadHostType}; + + flutter::ThreadHost::ThreadHostConfig host_config(threadHostType, IOSPlatformThreadConfigSetter); + + host_config.ui_config = + fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName( + flutter::ThreadHost::Type::UI, threadLabel.UTF8String), + fml::Thread::ThreadPriority::DISPLAY); + + host_config.raster_config = + fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName( + flutter::ThreadHost::Type::RASTER, threadLabel.UTF8String), + fml::Thread::ThreadPriority::RASTER); + + host_config.io_config = + fml::Thread::ThreadConfig(flutter::ThreadHost::ThreadHostConfig::MakeThreadName( + flutter::ThreadHost::Type::IO, threadLabel.UTF8String), + fml::Thread::ThreadPriority::BACKGROUND); + + return (flutter::ThreadHost){host_config}; } static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) { diff --git a/shell/platform/embedder/embedder_thread_host.cc b/shell/platform/embedder/embedder_thread_host.cc index 1f02eead41118..30955caa6622c 100644 --- a/shell/platform/embedder/embedder_thread_host.cc +++ b/shell/platform/embedder/embedder_thread_host.cc @@ -154,7 +154,8 @@ EmbedderThreadHost::CreateEmbedderManagedThreadHost( // Create a thread host with just the threads that need to be managed by the // engine. The embedder has provided the rest. - ThreadHost thread_host(kFlutterThreadName, engine_thread_host_mask); + ThreadHost thread_host(ThreadHost::ThreadHostConfig(kFlutterThreadName, + engine_thread_host_mask)); // If the embedder has supplied a platform task runner, use that. If not, use // the current thread task runner. @@ -208,9 +209,9 @@ std::unique_ptr 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::RASTER | - ThreadHost::Type::IO | - ThreadHost::Type::UI); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + kFlutterThreadName, + ThreadHost::Type::RASTER | ThreadHost::Type::IO | ThreadHost::Type::UI)); // For embedder platforms that don't have native message loop interop, this // will reference a task runner that points to a null message loop diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc index ccad16a902d50..f74973aef64db 100644 --- a/shell/platform/fuchsia/flutter/engine.cc +++ b/shell/platform/fuchsia/flutter/engine.cc @@ -57,7 +57,8 @@ std::unique_ptr MakeLocalizationPlatformMessage( } // namespace flutter::ThreadHost Engine::CreateThreadHost(const std::string& name_prefix) { - fml::Thread::SetCurrentThreadName(name_prefix + ".platform"); + fml::Thread::SetCurrentThreadName( + fml::Thread::ThreadConfig(name_prefix + ".platform")); return flutter::ThreadHost(name_prefix, flutter::ThreadHost::Type::RASTER | flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::IO);