diff --git a/engine/src/flutter/runtime/BUILD.gn b/engine/src/flutter/runtime/BUILD.gn index a6f4ceb196..2db3f12dbd 100644 --- a/engine/src/flutter/runtime/BUILD.gn +++ b/engine/src/flutter/runtime/BUILD.gn @@ -187,6 +187,7 @@ if (enable_unittests) { public_deps = [ ":plugin_registrant", "//flutter/fml", + "//flutter/runtime:dart_plugin_registrant", "//flutter/testing", "//flutter/testing:fixture_test", ] diff --git a/engine/src/flutter/runtime/dart_isolate.cc b/engine/src/flutter/runtime/dart_isolate.cc index b6c5e41e3f..e0ee729335 100644 --- a/engine/src/flutter/runtime/dart_isolate.cc +++ b/engine/src/flutter/runtime/dart_isolate.cc @@ -706,7 +706,12 @@ bool DartIsolate::RunFromLibrary(std::optional library_name, ? tonic::ToDart(entrypoint.value().c_str()) : tonic::ToDart("main"); - InvokeDartPluginRegistrantIfAvailable(library_handle); + if (!FindAndInvokeDartPluginRegistrant()) { + // TODO(gaaclarke): Remove once the framework PR lands that uses `--source` + // to compile the Dart Plugin Registrant + // (https://github.com/flutter/flutter/pull/100572). + InvokeDartPluginRegistrantIfAvailable(library_handle); + } auto user_entrypoint_function = ::Dart_GetField(library_handle, entrypoint_handle); diff --git a/engine/src/flutter/runtime/dart_plugin_registrant.cc b/engine/src/flutter/runtime/dart_plugin_registrant.cc index 08916ed477..e7e88f0922 100644 --- a/engine/src/flutter/runtime/dart_plugin_registrant.cc +++ b/engine/src/flutter/runtime/dart_plugin_registrant.cc @@ -6,40 +6,14 @@ #include +#include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/logging/dart_invoke.h" namespace flutter { -namespace { -bool EndsWith(const std::string& str, const std::string& ending) { - if (str.size() >= ending.size()) { - return (0 == - str.compare(str.size() - ending.size(), ending.size(), ending)); - } else { - return false; - } -} - -Dart_Handle FindDartPluginRegistrantLibrary() { - // TODO(99308): Instead of finding this, it could be passed down from the - // tool. - Dart_Handle libraries = Dart_GetLoadedLibraries(); - intptr_t length = 0; - Dart_ListLength(libraries, &length); - for (intptr_t i = 0; i < length; ++i) { - Dart_Handle library = Dart_ListGetAt(libraries, i); - std::string library_name = - tonic::DartConverter::FromDart(Dart_ToString(library)); - if (EndsWith(library_name, - "dart_tool/flutter_build/dart_plugin_registrant.dart'")) { - return library; - } - } - return Dart_Null(); -} -} // namespace +const char* dart_plugin_registrant_library_override = nullptr; bool InvokeDartPluginRegistrantIfAvailable(Dart_Handle library_handle) { TRACE_EVENT0("flutter", "InvokeDartPluginRegistrantIfAvailable"); @@ -65,12 +39,30 @@ bool InvokeDartPluginRegistrantIfAvailable(Dart_Handle library_handle) { } bool FindAndInvokeDartPluginRegistrant() { - auto dart_plugin_registrant_library = FindDartPluginRegistrantLibrary(); - if (!Dart_IsNull(dart_plugin_registrant_library)) { - return InvokeDartPluginRegistrantIfAvailable( - dart_plugin_registrant_library); - } else { + std::string library_name = + dart_plugin_registrant_library_override == nullptr + ? "package:flutter/src/dart_plugin_registrant.dart" + : dart_plugin_registrant_library_override; + Dart_Handle library = Dart_LookupLibrary(tonic::ToDart(library_name)); + if (Dart_IsError(library)) { return false; } + Dart_Handle registrant_file_uri = + Dart_GetField(library, tonic::ToDart("dartPluginRegistrantLibrary")); + if (Dart_IsError(registrant_file_uri)) { + // TODO(gaaclarke): Find a way to remove this branch so the field is + // required. I couldn't get it working with unit tests. + return InvokeDartPluginRegistrantIfAvailable(library); + } + + std::string registrant_file_uri_string = + tonic::DartConverter::FromDart(registrant_file_uri); + if (registrant_file_uri_string.empty()) { + FML_LOG(ERROR) << "Unexpected empty dartPluginRegistrantLibrary."; + return false; + } + + Dart_Handle registrant_library = Dart_LookupLibrary(registrant_file_uri); + return InvokeDartPluginRegistrantIfAvailable(registrant_library); } } // namespace flutter diff --git a/engine/src/flutter/runtime/dart_plugin_registrant.h b/engine/src/flutter/runtime/dart_plugin_registrant.h index b6a9856d66..f78dfccca8 100644 --- a/engine/src/flutter/runtime/dart_plugin_registrant.h +++ b/engine/src/flutter/runtime/dart_plugin_registrant.h @@ -9,6 +9,10 @@ namespace flutter { +/// The name of the library where the Dart Plugin Registrant will be looked for. +/// This is available for testing. +extern const char* dart_plugin_registrant_library_override; + /// Looks for the Dart Plugin Registrant in `library_handle` and invokes it if /// it is found. /// @return `true` when the registrant has been invoked. diff --git a/engine/src/flutter/runtime/dart_plugin_registrant_unittests.cc b/engine/src/flutter/runtime/dart_plugin_registrant_unittests.cc index c7cb6e4e84..380fa23629 100644 --- a/engine/src/flutter/runtime/dart_plugin_registrant_unittests.cc +++ b/engine/src/flutter/runtime/dart_plugin_registrant_unittests.cc @@ -4,7 +4,9 @@ #include "flutter/runtime/dart_isolate.h" +#include #include "flutter/fml/paths.h" +#include "flutter/runtime/dart_plugin_registrant.h" #include "flutter/runtime/dart_vm.h" #include "flutter/runtime/dart_vm_lifecycle.h" #include "flutter/testing/dart_isolate_runner.h" @@ -23,6 +25,30 @@ const std::string elf_file_name = "plugin_registrant_app_elf_snapshot.so"; class DartIsolateTest : public FixtureTest { public: DartIsolateTest() : FixtureTest(kernel_file_name, elf_file_name, "") {} + + void OverrideDartPluginRegistrant(const std::string& override_value) { + dart_plugin_registrant_library_ = override_value; + dart_plugin_registrant_library_override = + dart_plugin_registrant_library_.c_str(); + } + + void SetUp() override { + std::string source_path = GetSourcePath(); + if (source_path[0] != '/') { + // On windows we need an extra '/' prefix. + source_path = "/" + source_path; + } + std::string registrant_uri = std::string("file://") + source_path + + "flutter/runtime/fixtures/dart_tool/" + "flutter_build/dart_plugin_registrant.dart"; + OverrideDartPluginRegistrant(registrant_uri); + } + + void TearDown() override { + dart_plugin_registrant_library_override = nullptr; + } + + std::string dart_plugin_registrant_library_; }; TEST_F(DartIsolateTest, DartPluginRegistrantIsPresent) { diff --git a/engine/src/flutter/runtime/fixtures/dart_tool/flutter_build/dart_plugin_registrant.dart b/engine/src/flutter/runtime/fixtures/dart_tool/flutter_build/dart_plugin_registrant.dart index a8550a04e1..907e831eb1 100644 --- a/engine/src/flutter/runtime/fixtures/dart_tool/flutter_build/dart_plugin_registrant.dart +++ b/engine/src/flutter/runtime/fixtures/dart_tool/flutter_build/dart_plugin_registrant.dart @@ -4,6 +4,7 @@ import 'dart:isolate'; import 'dart:ui'; +import 'dart:io' show Platform; void passMessage(String message) native 'PassMessage'; diff --git a/engine/src/flutter/testing/testing.gni b/engine/src/flutter/testing/testing.gni index e0184d3a30..4fd02403aa 100644 --- a/engine/src/flutter/testing/testing.gni +++ b/engine/src/flutter/testing/testing.gni @@ -27,11 +27,13 @@ template("fixtures_location") { location_path = rebase_path(invoker.assets_dir) testing_assets_path = rebase_path("$root_out_dir/gen/flutter/testing/assets") + source_path = rebase_path("//") # Array of source lines. We use a list to ensure a trailing newline is # emitted by write_file() to comply with -Wnewline-eof. location_source = [ "namespace flutter { namespace testing { ", + "const char* GetSourcePath() {return \"$source_path\";} ", "const char* GetFixturesPath() {return \"$location_path\";} ", "const char* GetTestingAssetsPath() {return \"$testing_assets_path\";} ", "}}", diff --git a/engine/src/flutter/testing/testing.h b/engine/src/flutter/testing/testing.h index 386763a0b2..3fd0cbd9a5 100644 --- a/engine/src/flutter/testing/testing.h +++ b/engine/src/flutter/testing/testing.h @@ -16,6 +16,8 @@ namespace flutter { namespace testing { +const char* GetSourcePath(); + //------------------------------------------------------------------------------ /// @brief Returns the directory containing the test fixture for the target /// if this target has fixtures configured. If there are no