From 338194dbff1b44345e13a22be6da36426fa1995b Mon Sep 17 00:00:00 2001 From: bryanoltman Date: Mon, 27 Jan 2025 23:09:28 -0500 Subject: [PATCH 1/6] Add shorebird support to x64 Linux targets --- shell/common/BUILD.gn | 8 +++++ shell/platform/linux/BUILD.gn | 2 ++ shell/platform/linux/fl_engine.cc | 56 ++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index aee1fcc550f8f..2261b3b85d848 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -183,6 +183,14 @@ source_set("common") { ] } } + + if (host_os == "linux" && target_os == "linux") { + if (target_cpu == "x64") { + libs = [ + "//third_party/updater/target/x86_64-unknown-linux-gnu/release/libupdater.a", + ] + } + } } # These are in their own source_set to avoid a dependency cycle with //common/graphics diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 36045a9fd4708..a95f6a3f0bf78 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -163,11 +163,13 @@ source_set("flutter_linux_sources") { deps = [ "//flutter/fml", + "//flutter/shell/common/shorebird", "//flutter/shell/platform/common:common_cpp_enums", "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/common:common_cpp_switches", "//flutter/shell/platform/embedder:embedder_headers", "//flutter/third_party/rapidjson", + "//flutter/third_party/tonic", ] } diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 4a8bee3561046..5830de148f363 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -11,6 +11,9 @@ #include #include "flutter/common/constants.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/paths.h" +#include "flutter/shell/common/shorebird/shorebird.h" #include "flutter/shell/platform/common/engine_switches.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" @@ -25,6 +28,7 @@ #include "flutter/shell/platform/linux/fl_texture_gl_private.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" +#include "third_party/tonic/filesystem/filesystem/file.h" // Unique number associated with platform tasks. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; @@ -506,6 +510,42 @@ FlRenderer* fl_engine_get_renderer(FlEngine* self) { return self->renderer; } +gboolean fl_set_up_shorebird(std::string assets_path_string, + std::string& patch_path) { + auto shorebird_yaml_path = + fml::paths::JoinPaths({assets_path_string, "shorebird.yaml"}); + std::string shorebird_yaml_contents(""); + if (!filesystem::ReadFileToString(shorebird_yaml_path, + &shorebird_yaml_contents)) { + FML_LOG(ERROR) << "Failed to read shorebird.yaml."; + return false; + } + + std::string code_cache_path = "$HOME/shorebird/my_shorebird_app"; + // if (!GetLocalAppDataPath(code_cache_path)) { + // FML_LOG(ERROR) << "Failed to retrieve the local AppData directory."; + // return false; + // } + + auto executable_location = fml::paths::GetExecutableDirectoryPath().second; + auto app_path = + fml::paths::JoinPaths({executable_location, "lib", "libapp.so"}); + // Need to read this, I think from assets/version.json + flutter::ReleaseVersion release_version{"1.0.0", "1"}; + // auto release_version_result = + // GetReleaseVersionAndBuildNumber(&release_version); + // if (release_version_result != kSuccess) { + // FML_LOG(ERROR) + // << "Failed to retrieve the release version and build number."; + // return false; + // } + + flutter::ShorebirdConfigArgs shorebird_args(code_cache_path, code_cache_path, + app_path, shorebird_yaml_contents, + release_version); + return ConfigureShorebird(shorebird_args, patch_path); +} + gboolean fl_engine_start(FlEngine* self, GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); @@ -575,7 +615,21 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { if (self->embedder_api.RunsAOTCompiledDartCode()) { FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; - source.elf_path = fl_dart_project_get_aot_library_path(self->project); + std::string patch_path; + auto setup_shorebird_result = + fl_set_up_shorebird(std::string(args.assets_path), patch_path); + if (setup_shorebird_result) { + // If we have a patch installed, we replace the default AOT library path + // with the patch path here. + FML_LOG(INFO) << "Setting project patch path: " << patch_path; + source.elf_path = patch_path.c_str(); + } else { + FML_LOG(ERROR) << "Failed to configure Shorebird."; + source.elf_path = fl_dart_project_get_aot_library_path(self->project); + } + + FML_LOG(INFO) << "ELF PATH: " << source.elf_path; + if (self->embedder_api.CreateAOTData(&source, &self->aot_data) != kSuccess) { g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, From 95846a0c75960ec9048072168a0c46de863741ee Mon Sep 17 00:00:00 2001 From: bryanoltman Date: Mon, 27 Jan 2025 23:10:05 -0500 Subject: [PATCH 2/6] formatting --- shell/common/BUILD.gn | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 2261b3b85d848..d0494a9c51258 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -186,9 +186,7 @@ source_set("common") { if (host_os == "linux" && target_os == "linux") { if (target_cpu == "x64") { - libs = [ - "//third_party/updater/target/x86_64-unknown-linux-gnu/release/libupdater.a", - ] + libs = [ "//third_party/updater/target/x86_64-unknown-linux-gnu/release/libupdater.a" ] } } } From 0347ffab9587b7e29705a90b6fe300ff3191d8bc Mon Sep 17 00:00:00 2001 From: bryanoltman Date: Tue, 28 Jan 2025 15:51:02 -0500 Subject: [PATCH 3/6] read app id and version from files --- common/config.gni | 2 +- shell/platform/linux/fl_engine.cc | 55 +++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/common/config.gni b/common/config.gni index 351af4a41746d..8807af4fcc8ba 100644 --- a/common/config.gni +++ b/common/config.gni @@ -73,7 +73,7 @@ if (slimpeller) { feature_defines_list += [ "SLIMPELLER=1" ] } -if (is_ios || is_mac || is_android || is_win) { +if (is_android || is_ios || is_linux || is_mac || is_win) { feature_defines_list += [ "SHOREBIRD_PLATFORM_SUPPORTED=1" ] } diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 5830de148f363..bbc0a0d397b13 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include @@ -28,6 +30,7 @@ #include "flutter/shell/platform/linux/fl_texture_gl_private.h" #include "flutter/shell/platform/linux/fl_texture_registrar_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" +#include "rapidjson/document.h" #include "third_party/tonic/filesystem/filesystem/file.h" // Unique number associated with platform tasks. @@ -510,10 +513,9 @@ FlRenderer* fl_engine_get_renderer(FlEngine* self) { return self->renderer; } -gboolean fl_set_up_shorebird(std::string assets_path_string, - std::string& patch_path) { +gboolean fl_set_up_shorebird(const char* assets_path, std::string& patch_path) { auto shorebird_yaml_path = - fml::paths::JoinPaths({assets_path_string, "shorebird.yaml"}); + fml::paths::JoinPaths({assets_path, "shorebird.yaml"}); std::string shorebird_yaml_contents(""); if (!filesystem::ReadFileToString(shorebird_yaml_path, &shorebird_yaml_contents)) { @@ -521,24 +523,41 @@ gboolean fl_set_up_shorebird(std::string assets_path_string, return false; } - std::string code_cache_path = "$HOME/shorebird/my_shorebird_app"; - // if (!GetLocalAppDataPath(code_cache_path)) { - // FML_LOG(ERROR) << "Failed to retrieve the local AppData directory."; - // return false; - // } + // Read appid from shorebird.yaml + std::string appid = ""; + std::stringstream ss(shorebird_yaml_contents); + std::string line; + std::string appid_prefix = "appid:"; + while (std::getline(ss, line, '\n')) { + if (line.find(appid_prefix) != std::string::npos) { + appid = line.substr(line.find(appid_prefix) + appid_prefix.size()); + break; + } + } + std::string code_cache_path = "$HOME/.shorebird_cache/" + appid; auto executable_location = fml::paths::GetExecutableDirectoryPath().second; auto app_path = fml::paths::JoinPaths({executable_location, "lib", "libapp.so"}); - // Need to read this, I think from assets/version.json - flutter::ReleaseVersion release_version{"1.0.0", "1"}; - // auto release_version_result = - // GetReleaseVersionAndBuildNumber(&release_version); - // if (release_version_result != kSuccess) { - // FML_LOG(ERROR) - // << "Failed to retrieve the release version and build number."; - // return false; - // } + auto version_json_path = fml::paths::JoinPaths({assets_path, "version.json"}); + std::ifstream input(version_json_path); + if (!input) { + return false; + } + std::string json_contents{std::istreambuf_iterator(input), + std::istreambuf_iterator()}; + + rapidjson::Document json_doc; + json_doc.Parse(json_contents.c_str()); + if (json_doc.HasParseError()) { + // Could not parse version file, aborting.. + return false; + } + + const auto version_map = json_doc.GetObject(); + flutter::ReleaseVersion release_version{ + version_map["version"].GetString(), + version_map["build_number"].GetString()}; flutter::ShorebirdConfigArgs shorebird_args(code_cache_path, code_cache_path, app_path, shorebird_yaml_contents, @@ -617,7 +636,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { source.type = kFlutterEngineAOTDataSourceTypeElfPath; std::string patch_path; auto setup_shorebird_result = - fl_set_up_shorebird(std::string(args.assets_path), patch_path); + fl_set_up_shorebird(args.assets_path, patch_path); if (setup_shorebird_result) { // If we have a patch installed, we replace the default AOT library path // with the patch path here. From c614c85128e63d26bf83b94900529f02871f2d8d Mon Sep 17 00:00:00 2001 From: bryanoltman Date: Tue, 28 Jan 2025 16:07:05 -0500 Subject: [PATCH 4/6] Cleanup --- shell/platform/linux/fl_engine.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index bbc0a0d397b13..2c6ea4679b7d2 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -4,6 +4,7 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" +#include #include #include @@ -535,7 +536,8 @@ gboolean fl_set_up_shorebird(const char* assets_path, std::string& patch_path) { } } - std::string code_cache_path = "$HOME/.shorebird_cache/" + appid; + std::string code_cache_path = + fml::paths::JoinPaths({g_get_home_dir(), ".shorebird_cache", appid}); auto executable_location = fml::paths::GetExecutableDirectoryPath().second; auto app_path = fml::paths::JoinPaths({executable_location, "lib", "libapp.so"}); @@ -550,7 +552,7 @@ gboolean fl_set_up_shorebird(const char* assets_path, std::string& patch_path) { rapidjson::Document json_doc; json_doc.Parse(json_contents.c_str()); if (json_doc.HasParseError()) { - // Could not parse version file, aborting.. + // Could not parse version file, aborting. return false; } @@ -597,8 +599,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { g_autoptr(GPtrArray) command_line_args = fl_engine_get_switches(self); // FlutterProjectArgs expects 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 switches are used. + // the first item is treated as the executable and ignored. Add a dummy + // value so that all switches are used. g_ptr_array_insert(command_line_args, 0, g_strdup("flutter")); gchar** dart_entrypoint_args = @@ -640,7 +642,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { if (setup_shorebird_result) { // If we have a patch installed, we replace the default AOT library path // with the patch path here. - FML_LOG(INFO) << "Setting project patch path: " << patch_path; source.elf_path = patch_path.c_str(); } else { FML_LOG(ERROR) << "Failed to configure Shorebird."; From f10ba6560bdf387d8f41ec9f1a676fc91a81312a Mon Sep 17 00:00:00 2001 From: bryanoltman Date: Tue, 28 Jan 2025 16:07:46 -0500 Subject: [PATCH 5/6] Cleanup --- shell/platform/linux/fl_engine.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 2c6ea4679b7d2..f01299bf0dd96 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -648,8 +648,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { source.elf_path = fl_dart_project_get_aot_library_path(self->project); } - FML_LOG(INFO) << "ELF PATH: " << source.elf_path; - if (self->embedder_api.CreateAOTData(&source, &self->aot_data) != kSuccess) { g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, From 9882c84efa3386324d0c44cf0a2377f17b548cc6 Mon Sep 17 00:00:00 2001 From: bryanoltman Date: Tue, 28 Jan 2025 17:45:33 -0500 Subject: [PATCH 6/6] add comment --- shell/platform/linux/fl_engine.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index f01299bf0dd96..cfd61f6dce303 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -634,6 +634,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { args.compositor = &compositor; if (self->embedder_api.RunsAOTCompiledDartCode()) { + // This struct contains raw C strings and needs to have its lifetime scoped + // to this block. FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; std::string patch_path;