Skip to content

Commit

Permalink
Started looking for the dart plugin registrant at runtime (flutter#31418
Browse files Browse the repository at this point in the history
)
  • Loading branch information
gaaclarke authored Feb 28, 2022
1 parent dc1dba5 commit e97c801
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 1 deletion.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ group("flutter") {
"//flutter/lib/spirv/test/supported_glsl_op_shaders:spirv_compile_supported_glsl_shaders",
"//flutter/lib/spirv/test/supported_op_shaders:spirv_compile_supported_op_shaders",
"//flutter/lib/ui:ui_unittests",
"//flutter/runtime:dart_plugin_registrant_unittests",
"//flutter/runtime:no_dart_plugin_registrant_unittests",
"//flutter/runtime:runtime_unittests",
"//flutter/shell/common:shell_unittests",
Expand Down
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,7 @@ FILE: ../../../flutter/runtime/dart_isolate_group_data.cc
FILE: ../../../flutter/runtime/dart_isolate_group_data.h
FILE: ../../../flutter/runtime/dart_isolate_unittests.cc
FILE: ../../../flutter/runtime/dart_lifecycle_unittests.cc
FILE: ../../../flutter/runtime/dart_plugin_registrant_unittests.cc
FILE: ../../../flutter/runtime/dart_service_isolate.cc
FILE: ../../../flutter/runtime/dart_service_isolate.h
FILE: ../../../flutter/runtime/dart_service_isolate_unittests.cc
Expand All @@ -978,6 +979,7 @@ FILE: ../../../flutter/runtime/dart_vm_lifecycle.h
FILE: ../../../flutter/runtime/dart_vm_unittests.cc
FILE: ../../../flutter/runtime/embedder_resources.cc
FILE: ../../../flutter/runtime/embedder_resources.h
FILE: ../../../flutter/runtime/fixtures/dart_tool/flutter_build/dart_plugin_registrant.dart
FILE: ../../../flutter/runtime/fixtures/no_dart_plugin_registrant_test.dart
FILE: ../../../flutter/runtime/fixtures/runtime_test.dart
FILE: ../../../flutter/runtime/fixtures/split_lib_test.dart
Expand Down
20 changes: 20 additions & 0 deletions runtime/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,24 @@ if (enable_unittests) {
"//flutter/testing:fixture_test",
]
}

test_fixtures("plugin_registrant") {
dart_main = "fixtures/dart_tool/flutter_build/dart_plugin_registrant.dart"
use_target_as_artifact_prefix = true
}

executable("dart_plugin_registrant_unittests") {
testonly = true

sources = [ "dart_plugin_registrant_unittests.cc" ]

public_configs = [ "//flutter:export_dynamic_symbols" ]

public_deps = [
":plugin_registrant",
"//flutter/fml",
"//flutter/testing",
"//flutter/testing:fixture_test",
]
}
}
35 changes: 34 additions & 1 deletion runtime/dart_isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,34 @@ static void InvokeDartPluginRegistrantIfAvailable(Dart_Handle library_handle) {
tonic::LogIfError(tonic::DartInvokeField(plugin_registrant, "register", {}));
}

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(): 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<std::string>::FromDart(Dart_ToString(library));
if (EndsWith(library_name,
"dart_tool/flutter_build/dart_plugin_registrant.dart'")) {
return library;
}
}
return Dart_Null();
}
} // namespace

bool DartIsolate::RunFromLibrary(std::optional<std::string> library_name,
std::optional<std::string> entrypoint,
const std::vector<std::string>& args) {
Expand All @@ -727,7 +755,12 @@ bool DartIsolate::RunFromLibrary(std::optional<std::string> library_name,
? tonic::ToDart(entrypoint.value().c_str())
: tonic::ToDart("main");

InvokeDartPluginRegistrantIfAvailable(library_handle);
auto dart_plugin_registrant_library = FindDartPluginRegistrantLibrary();
if (!Dart_IsNull(dart_plugin_registrant_library)) {
InvokeDartPluginRegistrantIfAvailable(dart_plugin_registrant_library);
} else {
InvokeDartPluginRegistrantIfAvailable(library_handle);
}

auto user_entrypoint_function =
::Dart_GetField(library_handle, entrypoint_handle);
Expand Down
78 changes: 78 additions & 0 deletions runtime/dart_plugin_registrant_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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/runtime/dart_isolate.h"

#include "flutter/fml/paths.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/testing/dart_isolate_runner.h"
#include "flutter/testing/fixture_test.h"
#include "flutter/testing/testing.h"

// CREATE_NATIVE_ENTRY is leaky by design
// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)

namespace flutter {
namespace testing {

const std::string kernel_file_name = "plugin_registrant_kernel_blob.bin";
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, "") {}
};

TEST_F(DartIsolateTest, DartPluginRegistrantIsNotPresent) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());

std::vector<std::string> messages;
fml::AutoResetWaitableEvent latch;

AddNativeCallback(
"PassMessage",
CREATE_NATIVE_ENTRY(([&latch, &messages](Dart_NativeArguments args) {
auto message = tonic::DartConverter<std::string>::FromDart(
Dart_GetNativeArgument(args, 0));
messages.push_back(message);
latch.Signal();
})));

auto settings = CreateSettingsForFixture();
auto did_throw_exception = false;
settings.unhandled_exception_callback = [&](const std::string& error,
const std::string& stack_trace) {
did_throw_exception = true;
return true;
};

auto vm_ref = DartVMRef::Create(settings);
auto thread = CreateNewThread();
TaskRunners task_runners(GetCurrentTestName(), //
thread, //
thread, //
thread, //
thread //
);

auto kernel_path =
fml::paths::JoinPaths({GetFixturesPath(), kernel_file_name});
auto isolate =
RunDartCodeInIsolate(vm_ref, settings, task_runners,
"mainForPluginRegistrantTest", {}, kernel_path);

ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);

latch.Wait();

ASSERT_EQ(messages.size(), 1u);
ASSERT_EQ(messages[0], "_PluginRegistrant.register() was called");
}

} // namespace testing
} // namespace flutter

// NOLINTEND(clang-analyzer-core.StackAddressEscape)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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.

void passMessage(String message) native 'PassMessage';

bool didCallRegistrantBeforeEntrypoint = false;

// Test the Dart plugin registrant.
@pragma('vm:entry-point')
class _PluginRegistrant {

@pragma('vm:entry-point')
static void register() {
if (didCallRegistrantBeforeEntrypoint) {
throw '_registerPlugins is being called twice';
}
didCallRegistrantBeforeEntrypoint = true;
}

}


@pragma('vm:entry-point')
void mainForPluginRegistrantTest() {
if (didCallRegistrantBeforeEntrypoint) {
passMessage('_PluginRegistrant.register() was called');
} else {
passMessage('_PluginRegistrant.register() was not called');
}
}

void main() {}

0 comments on commit e97c801

Please sign in to comment.