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/common/BUILD.gn b/shell/common/BUILD.gn index aee1fcc550f8f..d0494a9c51258 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -183,6 +183,12 @@ 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..cfd61f6dce303 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -4,13 +4,19 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" +#include #include #include +#include +#include #include #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 +31,8 @@ #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. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; @@ -506,6 +514,59 @@ FlRenderer* fl_engine_get_renderer(FlEngine* self) { return self->renderer; } +gboolean fl_set_up_shorebird(const char* assets_path, std::string& patch_path) { + auto shorebird_yaml_path = + fml::paths::JoinPaths({assets_path, "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; + } + + // 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 = + 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"}); + 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, + 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); @@ -538,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 = @@ -573,9 +634,22 @@ 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; - source.elf_path = fl_dart_project_get_aot_library_path(self->project); + std::string patch_path; + auto setup_shorebird_result = + 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. + 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); + } + if (self->embedder_api.CreateAOTData(&source, &self->aot_data) != kSuccess) { g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED,