Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/ui/hooks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,14 @@ typedef _ListStringArgFunction(List<String> args);
@pragma('vm:entry-point')
// ignore: unused_element
void _runMainZoned(Function startMainIsolateFunction,
Function? dartPluginRegistrant,
Function userMainFunction,
List<String> args) {
startMainIsolateFunction(() {
runZonedGuarded<void>(() {
if (dartPluginRegistrant != null) {
dartPluginRegistrant();
}
if (userMainFunction is _ListStringArgFunction) {
(userMainFunction as dynamic)(args);
} else {
Expand Down
32 changes: 28 additions & 4 deletions runtime/dart_isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ bool DartIsolate::MarkIsolateRunnable() {

[[nodiscard]] static bool InvokeMainEntrypoint(
Dart_Handle user_entrypoint_function,
Dart_Handle plugin_registrant_function,
Dart_Handle args) {
if (tonic::LogIfError(user_entrypoint_function)) {
FML_LOG(ERROR) << "Could not resolve main entrypoint function.";
Expand All @@ -691,7 +692,8 @@ bool DartIsolate::MarkIsolateRunnable() {

if (tonic::LogIfError(tonic::DartInvokeField(
Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
{start_main_isolate_function, user_entrypoint_function, args}))) {
{start_main_isolate_function, plugin_registrant_function,
user_entrypoint_function, args}))) {
FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
return false;
}
Expand All @@ -716,12 +718,34 @@ bool DartIsolate::RunFromLibrary(std::optional<std::string> library_name,
auto entrypoint_handle = entrypoint.has_value() && !entrypoint.value().empty()
? tonic::ToDart(entrypoint.value().c_str())
: tonic::ToDart("main");
auto entrypoint_args = tonic::ToDart(args);
auto user_entrypoint_function =
::Dart_GetField(library_handle, entrypoint_handle);

auto entrypoint_args = tonic::ToDart(args);

if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
// The Dart plugin registrant is a function named `_registerPlugins`
// generated by the Flutter tool.
//
// This function binds a plugin implementation to their platform
// interface based on the configuration of the app's pubpec.yaml, and the
// plugin's pubspec.yaml.
//
// Since this function may or may not be defined. Check that it is a top
// level function, and call it in hooks.dart before the main entrypoint
// function.
//
// If it's not defined, then just call the main entrypoint function
// as usual.
//
// This allows embeddings to change the name of the entrypoint function.
auto plugin_registrant_function =
::Dart_GetField(library_handle, tonic::ToDart("_registerPlugins"));

if (Dart_IsError(plugin_registrant_function)) {
plugin_registrant_function = Dart_Null();
}

if (!InvokeMainEntrypoint(user_entrypoint_function,
plugin_registrant_function, entrypoint_args)) {
return false;
}

Expand Down
34 changes: 34 additions & 0 deletions runtime/dart_isolate_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -597,5 +597,39 @@ TEST_F(DartIsolateTest, DISABLED_ValidLoadingUnitSucceeds) {
Wait();
}

TEST_F(DartIsolateTest, DartPluginRegistrantIsCalled) {
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();
})));

const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto thread = CreateNewThread();
TaskRunners task_runners(GetCurrentTestName(), //
thread, //
thread, //
thread, //
thread //
);
auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners,
"mainForPluginRegistrantTest", {},
GetFixturesPath());
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
latch.Wait();
ASSERT_EQ(messages.size(), 1u);
ASSERT_EQ(messages[0], "_registerPlugins was called");
}

} // namespace testing
} // namespace flutter
24 changes: 22 additions & 2 deletions runtime/fixtures/runtime_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import 'dart:ui';

import 'split_lib_test.dart' deferred as splitlib;

void main() {
}
void main() {}

@pragma('vm:entry-point')
void sayHi() {
Expand Down Expand Up @@ -115,3 +114,24 @@ void testCanConvertListOfInts(List<int> args){
args[2] == 3 &&
args[3] == 4);
}

bool didCallRegistrantBeforeEntrypoint = false;

// Test the Dart plugin registrant.
// _registerPlugins requires the entrypoint annotation, so the compiler doesn't tree shake it.
@pragma('vm:entry-point')
void _registerPlugins() { // ignore: unused_element
if (didCallRegistrantBeforeEntrypoint) {
throw '_registerPlugins is being called twice';
}
didCallRegistrantBeforeEntrypoint = true;
}

@pragma('vm:entry-point')
void mainForPluginRegistrantTest() { // ignore: unused_element
if (didCallRegistrantBeforeEntrypoint) {
passMessage('_registerPlugins was called');
} else {
passMessage('_registerPlugins was not called');
}
}