Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 5a84712

Browse files
committed
Ensure root isolate create callback is invoked before the isolate is in the running phase.
Embedders that have access to the Dart native API (only Fuchsia now) may perform library setup in the isolate create callback. The engine used to depend on the fact the root isolate entrypoint is invoked in the next iteration of message loop (via the `_startIsolate` trampoline in `isolate_patch.dart`) to ensure that library setup occur before the main entrypoint was invoked. However, due to differences in the way in which message loops are setup in Fuchsia, this entrypoint was run before the callback could be executed. Dart code on Fuchsia also has the ability to access the underlying event loops directly. This patch moves the invocation of the create callback to before user dart code has a chance to run. This difference in behavior on Fuchsia became an issue when the isolate initialization was reworked in #21820 for null-safety. Another issue was discovered in that the callback was being invoked twice, I fixed that too and added a test. Fixes flutter/flutter#68732
1 parent 2718474 commit 5a84712

File tree

5 files changed

+46
-26
lines changed

5 files changed

+46
-26
lines changed

common/settings.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ using MappingsCallback = std::function<Mappings(void)>;
5959

6060
using FrameRasterizedCallback = std::function<void(const FrameTiming&)>;
6161

62+
class DartIsolate;
63+
6264
struct Settings {
6365
Settings();
6466

@@ -169,7 +171,9 @@ struct Settings {
169171
TaskObserverRemove task_observer_remove;
170172
// The main isolate is current when this callback is made. This is a good spot
171173
// to perform native Dart bindings for libraries not built in.
172-
fml::closure root_isolate_create_callback;
174+
std::function<void(const DartIsolate&)> root_isolate_create_callback;
175+
// TODO(68738): Update isolate callbacks in settings to accept an additional
176+
// DartIsolate parameter.
173177
fml::closure isolate_create_callback;
174178
// The isolate is not current and may have already been destroyed when this
175179
// call is made.

runtime/dart_isolate.cc

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -148,21 +148,21 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRunningRootIsolate(
148148
return {};
149149
}
150150

151-
if (!isolate->RunFromLibrary(dart_entrypoint_library, //
152-
dart_entrypoint, //
153-
settings.dart_entrypoint_args, //
154-
settings.root_isolate_create_callback //
151+
if (settings.root_isolate_create_callback) {
152+
// Isolate callbacks always occur in isolate scope and before user code has
153+
// had a chance to run.
154+
tonic::DartState::Scope scope(isolate.get());
155+
settings.root_isolate_create_callback(*isolate.get());
156+
}
157+
158+
if (!isolate->RunFromLibrary(dart_entrypoint_library, //
159+
dart_entrypoint, //
160+
settings.dart_entrypoint_args //
155161
)) {
156162
FML_LOG(ERROR) << "Could not run the run main Dart entrypoint.";
157163
return {};
158164
}
159165

160-
if (settings.root_isolate_create_callback) {
161-
// Isolate callbacks always occur in isolate scope.
162-
tonic::DartState::Scope scope(isolate.get());
163-
settings.root_isolate_create_callback();
164-
}
165-
166166
if (settings.root_isolate_shutdown_callback) {
167167
isolate->AddIsolateShutdownCallback(
168168
settings.root_isolate_shutdown_callback);
@@ -617,8 +617,7 @@ bool DartIsolate::MarkIsolateRunnable() {
617617

618618
bool DartIsolate::RunFromLibrary(std::optional<std::string> library_name,
619619
std::optional<std::string> entrypoint,
620-
const std::vector<std::string>& args,
621-
const fml::closure& on_run) {
620+
const std::vector<std::string>& args) {
622621
TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary");
623622
if (phase_ != Phase::Ready) {
624623
return false;
@@ -644,9 +643,6 @@ bool DartIsolate::RunFromLibrary(std::optional<std::string> library_name,
644643

645644
phase_ = Phase::Running;
646645

647-
if (on_run) {
648-
on_run();
649-
}
650646
return true;
651647
}
652648

runtime/dart_isolate.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,20 +342,14 @@ class DartIsolate : public UIDartState {
342342
/// supplied entrypoint.
343343
/// @param[in] entrypoint The entrypoint in `library_name`
344344
/// @param[in] args A list of string arguments to the entrypoint.
345-
/// @param[in] on_run A callback to run in isolate scope after the
346-
/// main entrypoint has been invoked. There is no
347-
/// isolate scope current on the thread once this
348-
/// method returns.
349345
///
350346
/// @return If the isolate successfully transitioned to the running phase
351347
/// and the main entrypoint was invoked.
352348
///
353349
[[nodiscard]] bool RunFromLibrary(std::optional<std::string> library_name,
354350
std::optional<std::string> entrypoint,
355-
const std::vector<std::string>& args,
356-
const fml::closure& on_run = nullptr);
351+
const std::vector<std::string>& args);
357352

358-
public:
359353
//----------------------------------------------------------------------------
360354
/// @brief Transition the isolate to the `Phase::Shutdown` phase. The
361355
/// only thing left to do is to collect the isolate.

runtime/dart_isolate_unittests.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,5 +375,32 @@ TEST_F(DartIsolateTest, CanCreateServiceIsolate) {
375375
ASSERT_TRUE(root_isolate->Shutdown());
376376
}
377377

378+
TEST_F(DartIsolateTest,
379+
RootIsolateCreateCallbackIsMadeOnceAndBeforeIsolateRunning) {
380+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
381+
auto settings = CreateSettingsForFixture();
382+
size_t create_callback_count = 0u;
383+
settings.root_isolate_create_callback =
384+
[&create_callback_count](const auto& isolate) {
385+
ASSERT_EQ(isolate.GetPhase(), DartIsolate::Phase::Ready);
386+
create_callback_count++;
387+
ASSERT_NE(::Dart_CurrentIsolate(), nullptr);
388+
};
389+
auto vm_ref = DartVMRef::Create(settings);
390+
TaskRunners task_runners(GetCurrentTestName(), //
391+
GetCurrentTaskRunner(), //
392+
GetCurrentTaskRunner(), //
393+
GetCurrentTaskRunner(), //
394+
GetCurrentTaskRunner() //
395+
);
396+
{
397+
auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners, "main",
398+
{}, GetFixturesPath());
399+
ASSERT_TRUE(isolate);
400+
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
401+
}
402+
ASSERT_EQ(create_callback_count, 1u);
403+
}
404+
378405
} // namespace testing
379406
} // namespace flutter

shell/platform/embedder/embedder.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -841,9 +841,8 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
841841
if (SAFE_ACCESS(args, root_isolate_create_callback, nullptr) != nullptr) {
842842
VoidCallback callback =
843843
SAFE_ACCESS(args, root_isolate_create_callback, nullptr);
844-
settings.root_isolate_create_callback = [callback, user_data]() {
845-
callback(user_data);
846-
};
844+
settings.root_isolate_create_callback =
845+
[callback, user_data](const auto& isolate) { callback(user_data); };
847846
}
848847

849848
flutter::PlatformViewEmbedder::UpdateSemanticsNodesCallback

0 commit comments

Comments
 (0)