From 18f2c9c9aef049d429c115ed4757e90b0a318a04 Mon Sep 17 00:00:00 2001 From: Swift Kim Date: Tue, 29 Jun 2021 20:58:54 +0900 Subject: [PATCH] Refactor using FlutterProjectBundle --- shell/platform/tizen/BUILD.gn | 1 + .../platform/tizen/flutter_project_bundle.cc | 78 ++++++++++++++++++ shell/platform/tizen/flutter_project_bundle.h | 62 +++++++++++++++ shell/platform/tizen/flutter_tizen.cc | 6 +- shell/platform/tizen/flutter_tizen_engine.cc | 79 ++++++++----------- shell/platform/tizen/flutter_tizen_engine.h | 41 +++++----- 6 files changed, 199 insertions(+), 68 deletions(-) create mode 100644 shell/platform/tizen/flutter_project_bundle.cc create mode 100644 shell/platform/tizen/flutter_project_bundle.h diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index 98981a99aadff..7094a89c32349 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -96,6 +96,7 @@ template("embedder_for_profile") { "channels/text_input_channel.cc", "external_texture_pixel_gl.cc", "external_texture_surface_gl.cc", + "flutter_project_bundle.cc", "flutter_tizen.cc", "flutter_tizen_engine.cc", "flutter_tizen_texture_registrar.cc", diff --git a/shell/platform/tizen/flutter_project_bundle.cc b/shell/platform/tizen/flutter_project_bundle.cc new file mode 100644 index 0000000000000..eff1953350591 --- /dev/null +++ b/shell/platform/tizen/flutter_project_bundle.cc @@ -0,0 +1,78 @@ +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// 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_project_bundle.h" + +#include + +#include "flutter/shell/platform/common/path_utils.h" +#include "flutter/shell/platform/tizen/tizen_log.h" + +namespace flutter { + +FlutterProjectBundle::FlutterProjectBundle( + const FlutterDesktopEngineProperties& properties) + : assets_path_(properties.assets_path), + icu_path_(properties.icu_data_path) { + if (properties.aot_library_path != nullptr) { + aot_library_path_ = std::filesystem::path(properties.aot_library_path); + } + + // Resolve any relative paths. + if (assets_path_.is_relative() || icu_path_.is_relative() || + (!aot_library_path_.empty() && aot_library_path_.is_relative())) { + std::filesystem::path executable_location = GetExecutableDirectory(); + if (executable_location.empty()) { + FT_LOGE("Unable to find executable location to resolve resource paths."); + assets_path_ = std::filesystem::path(); + icu_path_ = std::filesystem::path(); + } else { + assets_path_ = std::filesystem::path(executable_location) / assets_path_; + icu_path_ = std::filesystem::path(executable_location) / icu_path_; + if (!aot_library_path_.empty()) { + aot_library_path_ = + std::filesystem::path(executable_location) / aot_library_path_; + } + } + } + + switches_.insert(switches_.end(), properties.switches, + properties.switches + properties.switches_count); +} + +bool FlutterProjectBundle::HasValidPaths() { + return !assets_path_.empty() && !icu_path_.empty(); +} + +// Attempts to load AOT data from the given path, which must be absolute and +// non-empty. Logs and returns nullptr on failure. +UniqueAotDataPtr FlutterProjectBundle::LoadAotData( + const FlutterEngineProcTable& engine_procs) { + if (aot_library_path_.empty()) { + FT_LOGE( + "Attempted to load AOT data, but no aot_library_path was provided."); + return UniqueAotDataPtr(nullptr, nullptr); + } + if (!std::filesystem::exists(aot_library_path_)) { + FT_LOGE("Can't load AOT data from %s; no such file.", + aot_library_path_.u8string().c_str()); + return UniqueAotDataPtr(nullptr, nullptr); + } + std::string path_string = aot_library_path_.u8string(); + FlutterEngineAOTDataSource source = {}; + source.type = kFlutterEngineAOTDataSourceTypeElfPath; + source.elf_path = path_string.c_str(); + FlutterEngineAOTData data = nullptr; + auto result = engine_procs.CreateAOTData(&source, &data); + if (result != kSuccess) { + FT_LOGE("Failed to load AOT data from: %s", path_string.c_str()); + return UniqueAotDataPtr(nullptr, nullptr); + } + return UniqueAotDataPtr(data, engine_procs.CollectAOTData); +} + +FlutterProjectBundle::~FlutterProjectBundle() {} + +} // namespace flutter diff --git a/shell/platform/tizen/flutter_project_bundle.h b/shell/platform/tizen/flutter_project_bundle.h new file mode 100644 index 0000000000000..f6734af7314b9 --- /dev/null +++ b/shell/platform/tizen/flutter_project_bundle.h @@ -0,0 +1,62 @@ +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. +// 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. + +#ifndef EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_ +#define EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_ + +#include +#include +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/tizen/public/flutter_tizen.h" + +namespace flutter { + +using UniqueAotDataPtr = + std::unique_ptr<_FlutterEngineAOTData, FlutterEngineCollectAOTDataFnPtr>; + +// The data associated with a Flutter project needed to run it in an engine. +class FlutterProjectBundle { + public: + // Creates a new project bundle from the given properties. + // + // Treats any relative paths as relative to the directory of this executable. + explicit FlutterProjectBundle( + const FlutterDesktopEngineProperties& properties); + + ~FlutterProjectBundle(); + + // Whether or not the bundle is valid. This does not check that the paths + // exist, or contain valid data, just that paths were able to be constructed. + bool HasValidPaths(); + + // Returns the path to the assets directory. + const std::filesystem::path& assets_path() { return assets_path_; } + + // Returns the path to the ICU data file. + const std::filesystem::path& icu_path() { return icu_path_; } + + // Returns any switches that should be passed to the engine. + const std::vector switches() { return switches_; } + + // Attempts to load AOT data for this bundle. The returned data must be + // retained until any engine instance it is passed to has been shut down. + // + // Logs and returns nullptr on failure. + UniqueAotDataPtr LoadAotData(const FlutterEngineProcTable& engine_procs); + + private: + std::filesystem::path assets_path_; + std::filesystem::path icu_path_; + std::vector switches_; + + // Path to the AOT library file, if any. + std::filesystem::path aot_library_path_; +}; + +} // namespace flutter + +#endif // EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_ diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index b588eef534d33..4606742de02b3 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -8,6 +8,7 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h" #include "flutter/shell/platform/common/incoming_message_dispatcher.h" +#include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/public/flutter_platform_view.h" #include "flutter/shell/platform/tizen/tizen_log.h" @@ -29,8 +30,9 @@ FlutterDesktopEngineRef FlutterDesktopRunEngine( bool headed) { flutter::StartLogging(); - auto engine = std::make_unique(headed); - if (!engine->RunEngine(engine_properties)) { + flutter::FlutterProjectBundle project(engine_properties); + auto engine = std::make_unique(project, headed); + if (!engine->RunEngine()) { FT_LOGE("Failed to run the Flutter engine."); return nullptr; } diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index 067ec0edf4c05..aa842f9bf9265 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -5,7 +5,7 @@ #include "flutter_tizen_engine.h" -#include +#include #include #include @@ -33,7 +33,10 @@ constexpr double kProfileFactor = 1.0; } // namespace -FlutterTizenEngine::FlutterTizenEngine(bool headed) { +FlutterTizenEngine::FlutterTizenEngine(const FlutterProjectBundle& project, + bool headed) + : project_(std::make_unique(project)), + aot_data_(nullptr, nullptr) { embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); @@ -88,52 +91,38 @@ void FlutterTizenEngine::NotifyLowMemoryWarning() { embedder_api_.NotifyLowMemoryWarning(engine_); } -// Attempts to load AOT data from the given path, which must be absolute and -// non-empty. Logs and returns nullptr on failure. -UniqueAotDataPtr FlutterTizenEngine::LoadAotData(std::string aot_data_path) { - if (aot_data_path.empty()) { - FT_LOGE( - "Attempted to load AOT data, but no aot_library_path was provided."); - return nullptr; - } - if (!std::filesystem::exists(aot_data_path)) { - FT_LOGE("Can't load AOT data from %s; no such file.", - aot_data_path.c_str()); - return nullptr; - } - FlutterEngineAOTDataSource source = {}; - source.type = kFlutterEngineAOTDataSourceTypeElfPath; - source.elf_path = aot_data_path.c_str(); - FlutterEngineAOTData data = nullptr; - auto result = embedder_api_.CreateAOTData(&source, &data); - if (result != kSuccess) { - FT_LOGE("Failed to load AOT data from: %s", aot_data_path.c_str()); - return nullptr; - } - return UniqueAotDataPtr(data); -} - -bool FlutterTizenEngine::RunEngine( - const FlutterDesktopEngineProperties& engine_properties) { +bool FlutterTizenEngine::RunEngine() { if (IsHeaded() && !renderer->IsValid()) { FT_LOGE("The display was not valid."); return false; } + if (!project_->HasValidPaths()) { + FT_LOGE("Missing or unresolvable paths to assets."); + return false; + } + std::string assets_path_string = project_->assets_path().u8string(); + std::string icu_path_string = project_->icu_path().u8string(); + if (embedder_api_.RunsAOTCompiledDartCode()) { + aot_data_ = project_->LoadAotData(embedder_api_); + if (!aot_data_) { + FT_LOGE("Unable to start engine without AOT data."); + return false; + } + } + // FlutterProjectArgs is expecting a full argv, so when processing it for // flags the first item is treated as the executable and ignored. Add a dummy // value so that all provided arguments are used. + std::vector switches = project_->switches(); std::vector argv = {"placeholder"}; - if (engine_properties.switches_count > 0) { - argv.insert(argv.end(), &engine_properties.switches[0], - &engine_properties.switches[engine_properties.switches_count]); - } + std::transform( + switches.begin(), switches.end(), std::back_inserter(argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); - for (size_t i = 0; i < engine_properties.switches_count; ++i) { - auto str = std::string{engine_properties.switches[i]}; - if (str.find("verbose-logging") != std::string::npos) { - SetMinLoggingLevel(DLOG_INFO); - } + if (std::find(switches.begin(), switches.end(), "verbose-logging") != + switches.end()) { + SetMinLoggingLevel(DLOG_INFO); } // Configure task runners. @@ -173,10 +162,10 @@ bool FlutterTizenEngine::RunEngine( FlutterProjectArgs args = {}; args.struct_size = sizeof(FlutterProjectArgs); - args.assets_path = engine_properties.assets_path; - args.icu_data_path = engine_properties.icu_data_path; + args.assets_path = assets_path_string.c_str(); + args.icu_data_path = icu_path_string.c_str(); args.command_line_argc = static_cast(argv.size()); - args.command_line_argv = &argv[0]; + args.command_line_argv = argv.size() > 0 ? argv.data() : nullptr; args.platform_message_callback = [](const FlutterPlatformMessage* engine_message, void* user_data) { if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { @@ -198,13 +187,7 @@ bool FlutterTizenEngine::RunEngine( }; } #endif - - if (embedder_api_.RunsAOTCompiledDartCode()) { - aot_data_ = LoadAotData(engine_properties.aot_library_path); - if (!aot_data_) { - FT_LOGE("Unable to start engine without AOT data."); - return false; - } + if (aot_data_) { args.aot_data = aot_data_.get(); } diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 882cf931c0355..bae5418fe43bb 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -6,7 +6,6 @@ #ifndef EMBEDDER_FLUTTER_TIZEN_ENGINE_H_ #define EMBEDDER_FLUTTER_TIZEN_ENGINE_H_ -#include #include #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" @@ -20,6 +19,7 @@ #include "flutter/shell/platform/tizen/channels/platform_view_channel.h" #include "flutter/shell/platform/tizen/channels/settings_channel.h" #include "flutter/shell/platform/tizen/channels/text_input_channel.h" +#include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_texture_registrar.h" #include "flutter/shell/platform/tizen/key_event_handler.h" #include "flutter/shell/platform/tizen/public/flutter_tizen.h" @@ -47,27 +47,25 @@ struct FlutterDesktopMessenger { namespace flutter { -// Custom deleter for FlutterEngineAOTData. -struct AOTDataDeleter { - void operator()(FlutterEngineAOTData aot_data) { - FlutterEngineCollectAOTData(aot_data); - } -}; - -using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>; - // Manages state associated with the underlying FlutterEngine. class FlutterTizenEngine : public TizenRenderer::Delegate { public: - explicit FlutterTizenEngine(bool headed); + // Creates a new Flutter engine object configured to run |project|. + explicit FlutterTizenEngine(const FlutterProjectBundle& project, bool headed); + virtual ~FlutterTizenEngine(); // Prevent copying. FlutterTizenEngine(FlutterTizenEngine const&) = delete; FlutterTizenEngine& operator=(FlutterTizenEngine const&) = delete; + // Sets up an instance of TizenRenderer. void InitializeRenderer(); - bool RunEngine(const FlutterDesktopEngineProperties& engine_properties); + + // Starts running the engine. + bool RunEngine(); + + // Stops the engine. bool StopEngine(); // Returns the currently configured Plugin Registrar. @@ -140,15 +138,25 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { private: bool IsHeaded() { return renderer != nullptr; } - UniqueAotDataPtr LoadAotData(std::string aot_data_path); + FlutterDesktopMessage ConvertToDesktopMessage( const FlutterPlatformMessage& engine_message); + + // Creates and returns a FlutterRendererConfig depending on the current + // display mode (headed or headless). + // The user_data received by the render callbacks refers to the + // FlutterTizenEngine. FlutterRendererConfig GetRendererConfig(); + // The handle to the embedder.h engine instance. + FLUTTER_API_SYMBOL(FlutterEngine) engine_ = nullptr; + FlutterEngineProcTable embedder_api_ = {}; - // The Flutter engine instance. - FLUTTER_API_SYMBOL(FlutterEngine) engine_; + std::unique_ptr project_; + + // AOT data for this engine instance, if applicable. + UniqueAotDataPtr aot_data_; // The handlers listening to platform events. std::unique_ptr key_event_handler_; @@ -180,9 +188,6 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { std::unique_ptr tizen_vsync_waiter_; #endif - // AOT data for this engine instance, if applicable. - UniqueAotDataPtr aot_data_; - // The current renderer transformation. FlutterTransformation transformation_; };