-
Notifications
You must be signed in to change notification settings - Fork 6k
Create root isolate asynchronously #20142
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,10 @@ namespace flutter { | |
|
||
RuntimeController::RuntimeController(RuntimeDelegate& client, | ||
TaskRunners p_task_runners) | ||
: client_(client), vm_(nullptr), task_runners_(p_task_runners) {} | ||
: client_(client), | ||
vm_(nullptr), | ||
task_runners_(p_task_runners), | ||
weak_factory_(this) {} | ||
|
||
RuntimeController::RuntimeController( | ||
RuntimeDelegate& p_client, | ||
|
@@ -50,48 +53,80 @@ RuntimeController::RuntimeController( | |
platform_data_(std::move(p_platform_data)), | ||
isolate_create_callback_(p_isolate_create_callback), | ||
isolate_shutdown_callback_(p_isolate_shutdown_callback), | ||
persistent_isolate_data_(std::move(p_persistent_isolate_data)) { | ||
// Create the root isolate as soon as the runtime controller is initialized. | ||
persistent_isolate_data_(std::move(p_persistent_isolate_data)), | ||
weak_factory_(this) { | ||
// Create the root isolate as soon as the runtime controller is initialized, | ||
// but not using a synchronous way to avoid blocking the platform thread a | ||
// long time as it is waiting while creating `Shell` on that platform thread. | ||
// It will be run at a later point when the engine provides a run | ||
// configuration and then runs the isolate. | ||
auto strong_root_isolate = | ||
DartIsolate::CreateRootIsolate( | ||
vm_->GetVMData()->GetSettings(), // | ||
isolate_snapshot_, // | ||
task_runners_, // | ||
std::make_unique<PlatformConfiguration>(this), // | ||
snapshot_delegate_, // | ||
io_manager_, // | ||
unref_queue_, // | ||
image_decoder_, // | ||
p_advisory_script_uri, // | ||
p_advisory_script_entrypoint, // | ||
nullptr, // | ||
isolate_create_callback_, // | ||
isolate_shutdown_callback_ // | ||
) | ||
.lock(); | ||
|
||
FML_CHECK(strong_root_isolate) << "Could not create root isolate."; | ||
|
||
// The root isolate ivar is weak. | ||
root_isolate_ = strong_root_isolate; | ||
|
||
strong_root_isolate->SetReturnCodeCallback([this](uint32_t code) { | ||
root_isolate_return_code_ = {true, code}; | ||
}); | ||
|
||
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { | ||
tonic::DartState::Scope scope(strong_root_isolate); | ||
platform_configuration->DidCreateIsolate(); | ||
if (!FlushRuntimeStateToIsolate()) { | ||
FML_DLOG(ERROR) << "Could not setup initial isolate state."; | ||
} | ||
} else { | ||
FML_DCHECK(false) << "RuntimeController created without window binding."; | ||
} | ||
|
||
FML_DCHECK(Dart_CurrentIsolate() == nullptr); | ||
create_and_config_root_isolate_ = | ||
std::async(std::launch::deferred, [self = weak_factory_.GetWeakPtr()]() { | ||
if (!self) { | ||
return; | ||
} | ||
|
||
auto strong_root_isolate = | ||
DartIsolate::CreateRootIsolate( | ||
self->vm_->GetVMData()->GetSettings(), // | ||
self->isolate_snapshot_, // | ||
self->task_runners_, // | ||
std::make_unique<PlatformConfiguration>(self.get()), // | ||
self->snapshot_delegate_, // | ||
self->io_manager_, // | ||
self->unref_queue_, // | ||
self->image_decoder_, // | ||
self->advisory_script_uri_, // | ||
self->advisory_script_entrypoint_, // | ||
nullptr, // | ||
self->isolate_create_callback_, // | ||
self->isolate_shutdown_callback_ // | ||
) | ||
.lock(); | ||
|
||
FML_CHECK(strong_root_isolate) << "Could not create root isolate."; | ||
|
||
// The root isolate ivar is weak. | ||
self->root_isolate_ = strong_root_isolate; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The API as originally designed expects the root isolate to be ready when the runtime controller has been created (this assumption is prevalent throughout the engine). Now, a race has been introduced with no way of telling from the caller about when the root isolate is ready (or the other ivars). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it breaks the assumption but also makes sure the root isolate must be ready before running. |
||
|
||
strong_root_isolate->SetReturnCodeCallback([self](uint32_t code) { | ||
if (!self) { | ||
return; | ||
} | ||
|
||
self->root_isolate_return_code_ = {true, code}; | ||
}); | ||
|
||
if (auto* platform_configuration = | ||
self->GetPlatformConfigurationIfAvailable()) { | ||
tonic::DartState::Scope scope(strong_root_isolate); | ||
platform_configuration->DidCreateIsolate(); | ||
if (!self->FlushRuntimeStateToIsolate()) { | ||
FML_DLOG(ERROR) << "Could not setup initial isolate state."; | ||
} | ||
} else { | ||
FML_DCHECK(false) | ||
<< "RuntimeController created without window binding."; | ||
} | ||
|
||
FML_DCHECK(Dart_CurrentIsolate() == nullptr); | ||
|
||
self->client_.OnRootIsolateCreated(); | ||
return; | ||
}); | ||
|
||
// We're still trying to create the root isolate as soon as possible here on | ||
// the UI thread although it's deferred a little bit by | ||
// std::async(std::launch::deferred, ...). So the callers of `GetRootIsolate` | ||
// should get a quick return after this UI thread task. | ||
task_runners_.GetUITaskRunner()->PostTask( | ||
[self = weak_factory_.GetWeakPtr()]() { | ||
if (!self) { | ||
return; | ||
} | ||
|
||
self->GetRootIsolate(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: add a comment here that we're still trying to create the root isolate as soon as possible here on the UI thread although it's deferred a little bit by This comment might also be help for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
}); | ||
} | ||
|
||
RuntimeController::~RuntimeController() { | ||
|
@@ -107,8 +142,8 @@ RuntimeController::~RuntimeController() { | |
} | ||
} | ||
|
||
bool RuntimeController::IsRootIsolateRunning() const { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
bool RuntimeController::IsRootIsolateRunning() { | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Relying on Besides, even if (#18225 doesn't seem to have this problem.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Access to If someone calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Good catch, I guess we'll want to fix this regardless if we're going to adopt the bigger solution. We'll have more discussions about whether to accept the price of this pr. |
||
if (root_isolate) { | ||
return root_isolate->GetPhase() == DartIsolate::Phase::Running; | ||
} | ||
|
@@ -234,7 +269,7 @@ bool RuntimeController::ReportTimings(std::vector<int64_t> timings) { | |
} | ||
|
||
bool RuntimeController::NotifyIdle(int64_t deadline) { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
if (!root_isolate) { | ||
return false; | ||
} | ||
|
@@ -291,7 +326,7 @@ bool RuntimeController::DispatchSemanticsAction(int32_t id, | |
|
||
PlatformConfiguration* | ||
RuntimeController::GetPlatformConfigurationIfAvailable() { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
return root_isolate ? root_isolate->platform_configuration() : nullptr; | ||
} | ||
|
||
|
@@ -353,17 +388,17 @@ RuntimeController::ComputePlatformResolvedLocale( | |
} | ||
|
||
Dart_Port RuntimeController::GetMainPort() { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT; | ||
} | ||
|
||
std::string RuntimeController::GetIsolateName() { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
return root_isolate ? root_isolate->debug_name() : ""; | ||
} | ||
|
||
bool RuntimeController::HasLivePorts() { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
if (!root_isolate) { | ||
return false; | ||
} | ||
|
@@ -372,11 +407,20 @@ bool RuntimeController::HasLivePorts() { | |
} | ||
|
||
tonic::DartErrorHandleType RuntimeController::GetLastError() { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock(); | ||
return root_isolate ? root_isolate->GetLastError() : tonic::kNoError; | ||
} | ||
|
||
std::weak_ptr<DartIsolate> RuntimeController::GetRootIsolate() { | ||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I missed it as I originally that |
||
if (root_isolate) { | ||
return root_isolate_; | ||
} | ||
|
||
// Root isolate is not yet created, get it and do some configuration. | ||
FML_DCHECK(create_and_config_root_isolate_.valid()); | ||
create_and_config_root_isolate_.get(); | ||
liyuqian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return root_isolate_; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -563,8 +563,6 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view, | |
|
||
is_setup_ = true; | ||
|
||
vm_->GetServiceProtocol()->AddHandler(this, GetServiceProtocolDescription()); | ||
|
||
PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner( | ||
task_runners_.GetIOTaskRunner()); | ||
|
||
|
@@ -1134,6 +1132,19 @@ void Shell::OnPreEngineRestart() { | |
latch.Wait(); | ||
} | ||
|
||
// |Engine::Delegate| | ||
void Shell::OnRootIsolateCreated() { | ||
auto description = GetServiceProtocolDescription(); | ||
fml::TaskRunner::RunNowOrPostTask( | ||
task_runners_.GetPlatformTaskRunner(), | ||
[self = weak_factory_.GetWeakPtr(), | ||
description = std::move(description)]() { | ||
if (self) { | ||
self->vm_->GetServiceProtocol()->AddHandler(self.get(), description); | ||
} | ||
}); | ||
} | ||
|
||
// |Engine::Delegate| | ||
void Shell::UpdateIsolateDescription(const std::string isolate_name, | ||
int64_t isolate_port) { | ||
|
@@ -1278,9 +1289,15 @@ bool Shell::HandleServiceProtocolMessage( | |
// |ServiceProtocol::Handler| | ||
ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription() | ||
const { | ||
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per @jason-simmons 's suggestion
let's just add an Other things look good to me and I'm ready to approve it. @chinmaygarde : do you have any other requests to change? (You still flagged this PR as change requesteed.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
if (!weak_engine_) { | ||
return ServiceProtocol::Handler::Description(); | ||
} | ||
|
||
return { | ||
engine_->GetUIIsolateMainPort(), | ||
engine_->GetUIIsolateName(), | ||
weak_engine_->GetUIIsolateMainPort(), | ||
weak_engine_->GetUIIsolateName(), | ||
}; | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.