diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 14b30b322c345..405d947cb8097 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -521,24 +521,28 @@ void Engine::ScheduleSecondaryVsyncCallback(uintptr_t id, } void Engine::HandleAssetPlatformMessage(fml::RefPtr message) { - fml::RefPtr response = message->response(); - if (!response) { - return; - } - const auto& data = message->data(); - std::string asset_name(reinterpret_cast(data.data()), - data.size()); - - if (asset_manager_) { - std::unique_ptr asset_mapping = - asset_manager_->GetAsMapping(asset_name); - if (asset_mapping) { - response->Complete(std::move(asset_mapping)); - return; - } - } - - response->CompleteEmpty(); + task_runners_.GetIOTaskRunner()->PostTask(fml::MakeCopyable( + [message = std::move(message), asset_manager = asset_manager_]() mutable { + fml::RefPtr response = message->response(); + if (!response) { + return; + } + + const auto& data = message->data(); + std::string asset_name(reinterpret_cast(data.data()), + data.size()); + + if (asset_manager) { + std::unique_ptr asset_mapping = + asset_manager->GetAsMapping(asset_name); + if (asset_mapping) { + response->Complete(std::move(asset_mapping)); + return; + } + } + + response->CompleteEmpty(); + })); } const std::string& Engine::GetLastEntrypoint() const { diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index b9bec86095648..8488d00d3223d 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -12,6 +12,7 @@ #include #include "assets/directory_asset_bundle.h" +#include "flutter/assets/asset_resolver.h" #include "flutter/common/graphics/persistent_cache.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/layers/picture_layer.h" @@ -148,6 +149,83 @@ class TestAssetResolver : public AssetResolver { AssetResolver::AssetResolverType type_; }; +class PlatformMessageResponseTest : public flutter::PlatformMessageResponse { + public: + void Complete(std::unique_ptr data) override; + + void CompleteEmpty() override; + + private: + explicit PlatformMessageResponseTest(); + + ~PlatformMessageResponseTest() override; + + FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseTest); +}; + +PlatformMessageResponseTest::PlatformMessageResponseTest() {} + +PlatformMessageResponseTest::~PlatformMessageResponseTest() = default; + +void PlatformMessageResponseTest::Complete(std::unique_ptr data) { +} + +void PlatformMessageResponseTest::CompleteEmpty() {} + +class AssetTestResolver : public AssetResolver { + public: + AssetTestResolver(Shell* shell); + + ~AssetTestResolver() override; + + private: + Shell* shell_; + bool IsValid() const override; + // |AssetResolver| + AssetResolver::AssetResolverType GetType() const override; + // |AssetResolver| + std::unique_ptr GetAsMapping( + const std::string& asset_name) const override; + void CheckQueue() const; + // |AssetResolver| + bool IsValidAfterAssetManagerChange() const override; + FML_DISALLOW_COPY_AND_ASSIGN(AssetTestResolver); +}; + +AssetTestResolver::AssetTestResolver(Shell* shell) : shell_(shell){}; + +AssetTestResolver::~AssetTestResolver() = default; + +AssetResolver::AssetResolverType AssetTestResolver::GetType() const { + return AssetResolverType::kAssetManager; +} + +void AssetTestResolver::CheckQueue() const { + const auto current_queue_id = fml::MessageLoop::GetCurrentTaskQueueId(); + const auto io_queue_id = + shell_->GetTaskRunners().GetIOTaskRunner()->GetTaskQueueId(); + ASSERT_TRUE(current_queue_id == io_queue_id); +} + +// |AssetResolver| +std::unique_ptr AssetTestResolver::GetAsMapping( + const std::string& asset_name) const { + if (asset_name.compare("TestFlutterLoadAssets.json") == 0) { + CheckQueue(); + } + return nullptr; +} + +// |AssetResolver| +bool AssetTestResolver::IsValid() const { + return true; +} + +// |AssetResolver| +bool AssetTestResolver::IsValidAfterAssetManagerChange() const { + return false; +} + static bool ValidateShell(Shell* shell) { if (!shell) { return false; @@ -222,6 +300,38 @@ static void TestDartVmFlags(std::vector& flags) { } } +TEST_F(ShellTest, TestFlutterLoadAssetsOnIOThread) { + Settings settings = CreateSettingsForFixture(); + auto task_runner = CreateNewThread(); + ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI); + + TaskRunners task_runners("test", thread_host.ui_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + + std::unique_ptr shell = + CreateShell(std::move(settings), std::move(task_runners)); + + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("emptyMain"); + configuration.AddAssetResolver( + std::make_unique(shell.get())); + + RunEngine(shell.get(), std::move(configuration)); + + std::string request_json = "TestFlutterLoadAssets.json"; + std::vector data(request_json.begin(), request_json.end()); + auto platform_message = fml::MakeRefCounted( + "flutter/assets", std::move(data), + fml::MakeRefCounted()); + SendEnginePlatformMessage(shell.get(), std::move(platform_message)); + + DestroyShell(std::move(shell), std::move(task_runners)); +} + static void PostSync(const fml::RefPtr& task_runner, const fml::closure& task) { fml::AutoResetWaitableEvent latch;