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

Commit 190fd8e

Browse files
authored
Reland "Create root isolate asynchronously (#20142)" (#21747)
This reverts commit 5585ed9. Additionally, the following _flutter.runInView deadlock is fixed. Previously, a deadlock would occur when service protocol _flutter.runInView is used to restart the engine wihtout tearing down the shell: the shared mutex of the service protocol will be locked during the restart as it's in the middle of handling a service protocol message; if ServiceProtocol::AddHandler is also called during the restart, the deadlock happens as AddHandler also requires such lock. test/integration.shard/background_isolate_test.dart would fail without this fix.
1 parent 1068429 commit 190fd8e

File tree

8 files changed

+155
-57
lines changed

8 files changed

+155
-57
lines changed

runtime/runtime_controller.cc

Lines changed: 94 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ namespace flutter {
1818

1919
RuntimeController::RuntimeController(RuntimeDelegate& client,
2020
TaskRunners p_task_runners)
21-
: client_(client), vm_(nullptr), task_runners_(p_task_runners) {}
21+
: client_(client),
22+
vm_(nullptr),
23+
task_runners_(p_task_runners),
24+
weak_factory_(this) {}
2225

2326
RuntimeController::RuntimeController(
2427
RuntimeDelegate& p_client,
@@ -52,49 +55,81 @@ RuntimeController::RuntimeController(
5255
platform_data_(std::move(p_platform_data)),
5356
isolate_create_callback_(p_isolate_create_callback),
5457
isolate_shutdown_callback_(p_isolate_shutdown_callback),
55-
persistent_isolate_data_(std::move(p_persistent_isolate_data)) {
56-
// Create the root isolate as soon as the runtime controller is initialized.
58+
persistent_isolate_data_(std::move(p_persistent_isolate_data)),
59+
weak_factory_(this) {
60+
// Create the root isolate as soon as the runtime controller is initialized,
61+
// but not using a synchronous way to avoid blocking the platform thread a
62+
// long time as it is waiting while creating `Shell` on that platform thread.
5763
// It will be run at a later point when the engine provides a run
5864
// configuration and then runs the isolate.
59-
auto strong_root_isolate =
60-
DartIsolate::CreateRootIsolate(
61-
vm_->GetVMData()->GetSettings(), //
62-
isolate_snapshot_, //
63-
task_runners_, //
64-
std::make_unique<PlatformConfiguration>(this), //
65-
snapshot_delegate_, //
66-
hint_freed_delegate_, //
67-
io_manager_, //
68-
unref_queue_, //
69-
image_decoder_, //
70-
p_advisory_script_uri, //
71-
p_advisory_script_entrypoint, //
72-
nullptr, //
73-
isolate_create_callback_, //
74-
isolate_shutdown_callback_ //
75-
)
76-
.lock();
77-
78-
FML_CHECK(strong_root_isolate) << "Could not create root isolate.";
79-
80-
// The root isolate ivar is weak.
81-
root_isolate_ = strong_root_isolate;
82-
83-
strong_root_isolate->SetReturnCodeCallback([this](uint32_t code) {
84-
root_isolate_return_code_ = {true, code};
85-
});
86-
87-
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
88-
tonic::DartState::Scope scope(strong_root_isolate);
89-
platform_configuration->DidCreateIsolate();
90-
if (!FlushRuntimeStateToIsolate()) {
91-
FML_DLOG(ERROR) << "Could not setup initial isolate state.";
92-
}
93-
} else {
94-
FML_DCHECK(false) << "RuntimeController created without window binding.";
95-
}
96-
97-
FML_DCHECK(Dart_CurrentIsolate() == nullptr);
65+
create_and_config_root_isolate_ =
66+
std::async(std::launch::deferred, [self = weak_factory_.GetWeakPtr()]() {
67+
if (!self) {
68+
return;
69+
}
70+
71+
auto strong_root_isolate =
72+
DartIsolate::CreateRootIsolate(
73+
self->vm_->GetVMData()->GetSettings(), //
74+
self->isolate_snapshot_, //
75+
self->task_runners_, //
76+
std::make_unique<PlatformConfiguration>(self.get()), //
77+
self->snapshot_delegate_, //
78+
self->hint_freed_delegate_, //
79+
self->io_manager_, //
80+
self->unref_queue_, //
81+
self->image_decoder_, //
82+
self->advisory_script_uri_, //
83+
self->advisory_script_entrypoint_, //
84+
nullptr, //
85+
self->isolate_create_callback_, //
86+
self->isolate_shutdown_callback_ //
87+
)
88+
.lock();
89+
90+
FML_CHECK(strong_root_isolate) << "Could not create root isolate.";
91+
92+
// The root isolate ivar is weak.
93+
self->root_isolate_ = strong_root_isolate;
94+
95+
strong_root_isolate->SetReturnCodeCallback([self](uint32_t code) {
96+
if (!self) {
97+
return;
98+
}
99+
100+
self->root_isolate_return_code_ = {true, code};
101+
});
102+
103+
if (auto* platform_configuration =
104+
self->GetPlatformConfigurationIfAvailable()) {
105+
tonic::DartState::Scope scope(strong_root_isolate);
106+
platform_configuration->DidCreateIsolate();
107+
if (!self->FlushRuntimeStateToIsolate()) {
108+
FML_DLOG(ERROR) << "Could not setup initial isolate state.";
109+
}
110+
} else {
111+
FML_DCHECK(false)
112+
<< "RuntimeController created without window binding.";
113+
}
114+
115+
FML_DCHECK(Dart_CurrentIsolate() == nullptr);
116+
117+
self->client_.OnRootIsolateCreated();
118+
return;
119+
});
120+
121+
// We're still trying to create the root isolate as soon as possible here on
122+
// the UI thread although it's deferred a little bit by
123+
// std::async(std::launch::deferred, ...). So the callers of `GetRootIsolate`
124+
// should get a quick return after this UI thread task.
125+
task_runners_.GetUITaskRunner()->PostTask(
126+
[self = weak_factory_.GetWeakPtr()]() {
127+
if (!self) {
128+
return;
129+
}
130+
131+
self->GetRootIsolate();
132+
});
98133
}
99134

100135
RuntimeController::~RuntimeController() {
@@ -110,8 +145,8 @@ RuntimeController::~RuntimeController() {
110145
}
111146
}
112147

113-
bool RuntimeController::IsRootIsolateRunning() const {
114-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
148+
bool RuntimeController::IsRootIsolateRunning() {
149+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
115150
if (root_isolate) {
116151
return root_isolate->GetPhase() == DartIsolate::Phase::Running;
117152
}
@@ -238,7 +273,7 @@ bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
238273
}
239274

240275
bool RuntimeController::NotifyIdle(int64_t deadline, size_t freed_hint) {
241-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
276+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
242277
if (!root_isolate) {
243278
return false;
244279
}
@@ -298,7 +333,7 @@ bool RuntimeController::DispatchSemanticsAction(int32_t id,
298333

299334
PlatformConfiguration*
300335
RuntimeController::GetPlatformConfigurationIfAvailable() {
301-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
336+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
302337
return root_isolate ? root_isolate->platform_configuration() : nullptr;
303338
}
304339

@@ -360,17 +395,17 @@ RuntimeController::ComputePlatformResolvedLocale(
360395
}
361396

362397
Dart_Port RuntimeController::GetMainPort() {
363-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
398+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
364399
return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT;
365400
}
366401

367402
std::string RuntimeController::GetIsolateName() {
368-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
403+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
369404
return root_isolate ? root_isolate->debug_name() : "";
370405
}
371406

372407
bool RuntimeController::HasLivePorts() {
373-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
408+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
374409
if (!root_isolate) {
375410
return false;
376411
}
@@ -379,11 +414,20 @@ bool RuntimeController::HasLivePorts() {
379414
}
380415

381416
tonic::DartErrorHandleType RuntimeController::GetLastError() {
382-
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
417+
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
383418
return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
384419
}
385420

386421
std::weak_ptr<DartIsolate> RuntimeController::GetRootIsolate() {
422+
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
423+
if (root_isolate) {
424+
return root_isolate_;
425+
}
426+
427+
// Root isolate is not yet created, get it and do some configuration.
428+
FML_DCHECK(create_and_config_root_isolate_.valid());
429+
create_and_config_root_isolate_.get();
430+
387431
return root_isolate_;
388432
}
389433

runtime/runtime_controller.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
66
#define FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
77

8+
#include <future>
89
#include <memory>
910
#include <vector>
1011

@@ -348,7 +349,7 @@ class RuntimeController : public PlatformConfigurationClient {
348349
///
349350
/// @return True if root isolate running, False otherwise.
350351
///
351-
virtual bool IsRootIsolateRunning() const;
352+
virtual bool IsRootIsolateRunning();
352353

353354
//----------------------------------------------------------------------------
354355
/// @brief Dispatch the specified platform message to running root
@@ -430,7 +431,10 @@ class RuntimeController : public PlatformConfigurationClient {
430431
/// @brief Get a weak pointer to the root Dart isolate. This isolate may
431432
/// only be locked on the UI task runner. Callers use this
432433
/// accessor to transition to the root isolate to the running
433-
/// phase.
434+
/// phase. Note that it might take times if the isolate is not yet
435+
/// created, which should be done in a subsequence task after
436+
/// constructing `RuntimeController`, or it should get a quick
437+
/// return otherwise.
434438
///
435439
/// @return The root isolate reference.
436440
///
@@ -480,11 +484,16 @@ class RuntimeController : public PlatformConfigurationClient {
480484
std::string advisory_script_entrypoint_;
481485
std::function<void(int64_t)> idle_notification_callback_;
482486
PlatformData platform_data_;
487+
std::future<void> create_and_config_root_isolate_;
488+
// Note that `root_isolate_` is created asynchronously from the constructor of
489+
// `RuntimeController`, be careful to use it directly while it might have not
490+
// been created yet. Call `GetRootIsolate()` instead which guarantees that.
483491
std::weak_ptr<DartIsolate> root_isolate_;
484492
std::pair<bool, uint32_t> root_isolate_return_code_ = {false, 0};
485493
const fml::closure isolate_create_callback_;
486494
const fml::closure isolate_shutdown_callback_;
487495
std::shared_ptr<const fml::Mapping> persistent_isolate_data_;
496+
fml::WeakPtrFactory<RuntimeController> weak_factory_;
488497

489498
PlatformConfiguration* GetPlatformConfigurationIfAvailable();
490499

runtime/runtime_delegate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class RuntimeDelegate {
3232

3333
virtual FontCollection& GetFontCollection() = 0;
3434

35+
virtual void OnRootIsolateCreated() = 0;
36+
3537
virtual void UpdateIsolateDescription(const std::string isolate_name,
3638
int64_t isolate_port) = 0;
3739

shell/common/engine.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,10 @@ void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
501501
}
502502
}
503503

504+
void Engine::OnRootIsolateCreated() {
505+
delegate_.OnRootIsolateCreated();
506+
}
507+
504508
void Engine::UpdateIsolateDescription(const std::string isolate_name,
505509
int64_t isolate_port) {
506510
delegate_.UpdateIsolateDescription(isolate_name, isolate_port);

shell/common/engine.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ class Engine final : public RuntimeDelegate,
189189
///
190190
virtual void OnPreEngineRestart() = 0;
191191

192+
//--------------------------------------------------------------------------
193+
/// @brief Notifies the shell that the root isolate is created.
194+
/// Currently, this information is to add to the service
195+
/// protocol list of available root isolates running in the VM
196+
/// and their names so that the appropriate isolate can be
197+
/// selected in the tools for debugging and instrumentation.
198+
///
199+
virtual void OnRootIsolateCreated() = 0;
200+
192201
//--------------------------------------------------------------------------
193202
/// @brief Notifies the shell of the name of the root isolate and its
194203
/// port when that isolate is launched, restarted (in the
@@ -800,6 +809,9 @@ class Engine final : public RuntimeDelegate,
800809
// |RuntimeDelegate|
801810
void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
802811

812+
// |RuntimeDelegate|
813+
void OnRootIsolateCreated() override;
814+
803815
// |RuntimeDelegate|
804816
void UpdateIsolateDescription(const std::string isolate_name,
805817
int64_t isolate_port) override;

shell/common/engine_unittests.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class MockDelegate : public Engine::Delegate {
2727
MOCK_METHOD1(OnEngineHandlePlatformMessage,
2828
void(fml::RefPtr<PlatformMessage>));
2929
MOCK_METHOD0(OnPreEngineRestart, void());
30+
MOCK_METHOD0(OnRootIsolateCreated, void());
3031
MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
3132
MOCK_METHOD1(SetNeedsReportTimings, void(bool));
3233
MOCK_METHOD1(ComputePlatformResolvedLocale,
@@ -49,6 +50,7 @@ class MockRuntimeDelegate : public RuntimeDelegate {
4950
void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates));
5051
MOCK_METHOD1(HandlePlatformMessage, void(fml::RefPtr<PlatformMessage>));
5152
MOCK_METHOD0(GetFontCollection, FontCollection&());
53+
MOCK_METHOD0(OnRootIsolateCreated, void());
5254
MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
5355
MOCK_METHOD1(SetNeedsReportTimings, void(bool));
5456
MOCK_METHOD1(ComputePlatformResolvedLocale,
@@ -60,7 +62,7 @@ class MockRuntimeController : public RuntimeController {
6062
public:
6163
MockRuntimeController(RuntimeDelegate& client, TaskRunners p_task_runners)
6264
: RuntimeController(client, p_task_runners) {}
63-
MOCK_CONST_METHOD0(IsRootIsolateRunning, bool());
65+
MOCK_METHOD0(IsRootIsolateRunning, bool());
6466
MOCK_METHOD1(DispatchPlatformMessage, bool(fml::RefPtr<PlatformMessage>));
6567
};
6668

shell/common/shell.cc

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,6 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
564564

565565
is_setup_ = true;
566566

567-
vm_->GetServiceProtocol()->AddHandler(this, GetServiceProtocolDescription());
568-
569567
PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(
570568
task_runners_.GetIOTaskRunner());
571569

@@ -1150,6 +1148,23 @@ void Shell::OnPreEngineRestart() {
11501148
latch.Wait();
11511149
}
11521150

1151+
// |Engine::Delegate|
1152+
void Shell::OnRootIsolateCreated() {
1153+
if (is_added_to_service_protocol_) {
1154+
return;
1155+
}
1156+
auto description = GetServiceProtocolDescription();
1157+
fml::TaskRunner::RunNowOrPostTask(
1158+
task_runners_.GetPlatformTaskRunner(),
1159+
[self = weak_factory_.GetWeakPtr(),
1160+
description = std::move(description)]() {
1161+
if (self) {
1162+
self->vm_->GetServiceProtocol()->AddHandler(self.get(), description);
1163+
}
1164+
});
1165+
is_added_to_service_protocol_ = true;
1166+
}
1167+
11531168
// |Engine::Delegate|
11541169
void Shell::UpdateIsolateDescription(const std::string isolate_name,
11551170
int64_t isolate_port) {
@@ -1295,9 +1310,15 @@ bool Shell::HandleServiceProtocolMessage(
12951310
// |ServiceProtocol::Handler|
12961311
ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
12971312
const {
1313+
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
1314+
1315+
if (!weak_engine_) {
1316+
return ServiceProtocol::Handler::Description();
1317+
}
1318+
12981319
return {
1299-
engine_->GetUIIsolateMainPort(),
1300-
engine_->GetUIIsolateName(),
1320+
weak_engine_->GetUIIsolateMainPort(),
1321+
weak_engine_->GetUIIsolateName(),
13011322
};
13021323
}
13031324

shell/common/shell.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ class Shell final : public PlatformView::Delegate,
411411
>
412412
service_protocol_handlers_;
413413
bool is_setup_ = false;
414+
bool is_added_to_service_protocol_ = false;
414415
uint64_t next_pointer_flow_id_ = 0;
415416

416417
bool first_frame_rasterized_ = false;
@@ -537,6 +538,9 @@ class Shell final : public PlatformView::Delegate,
537538
// |Engine::Delegate|
538539
void OnPreEngineRestart() override;
539540

541+
// |Engine::Delegate|
542+
void OnRootIsolateCreated() override;
543+
540544
// |Engine::Delegate|
541545
void UpdateIsolateDescription(const std::string isolate_name,
542546
int64_t isolate_port) override;

0 commit comments

Comments
 (0)