Thanks to visit codestin.com
Credit goes to github.com

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
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.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you plan to work on this issue?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. I have no data to suggest it's worthwhile.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you envision passing this from the tool?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't thought about it. Maybe we could make it so the library has a unique name so we can look directly for it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I'd suggest filing an issue, and including the general idea about how this should be solved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dart_Handle libraries = Dart_GetLoadedLibraries();
intptr_t length = 0;
Dart_ListLength(libraries, &length);
for (intptr_t i = 0; i < length; ++i) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this grows with the number of packages, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right. I suspect the order of magnitude will never make this an issue. It depends on Dart's implementation of their API but linearly searching through a couple thousand strings shouldn't be significant. Most of the string comparisons will fail on the first char check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an internal customer, this resulted in a >300ms regression on startup time on low end Android devices.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it more like ~275ms? I might be looking at the wrong thing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it was just under 300ms - a mean change of about 291ms on low end Android. This represented a 17% regression from before this patch. I think we should revert this.

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')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any difference between this file (or test) and

@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');
}
}
?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the path of the file. The other one can be removed once we land the Framework PR.

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() {}