blob: eac218548cfbf701f4be60b54aade82a3d1bacfb [file] [log] [blame]
// 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/lib/ui/ui_dart_state.h"
#include "flutter/fml/message_loop.h"
#include "flutter/lib/ui/window/platform_configuration.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_message_handler.h"
using tonic::ToDart;
namespace flutter {
UIDartState::UIDartState(
TaskRunners task_runners,
TaskObserverAdd add_callback,
TaskObserverRemove remove_callback,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
std::string logger_prefix,
UnhandledExceptionCallback unhandled_exception_callback,
std::shared_ptr<IsolateNameServer> isolate_name_server,
bool is_root_isolate)
: task_runners_(std::move(task_runners)),
add_callback_(std::move(add_callback)),
remove_callback_(std::move(remove_callback)),
snapshot_delegate_(std::move(snapshot_delegate)),
hint_freed_delegate_(std::move(hint_freed_delegate)),
io_manager_(std::move(io_manager)),
skia_unref_queue_(std::move(skia_unref_queue)),
image_decoder_(std::move(image_decoder)),
advisory_script_uri_(std::move(advisory_script_uri)),
advisory_script_entrypoint_(std::move(advisory_script_entrypoint)),
logger_prefix_(std::move(logger_prefix)),
is_root_isolate_(is_root_isolate),
unhandled_exception_callback_(unhandled_exception_callback),
isolate_name_server_(std::move(isolate_name_server)) {
AddOrRemoveTaskObserver(true /* add */);
}
UIDartState::~UIDartState() {
AddOrRemoveTaskObserver(false /* remove */);
}
const std::string& UIDartState::GetAdvisoryScriptURI() const {
return advisory_script_uri_;
}
const std::string& UIDartState::GetAdvisoryScriptEntrypoint() const {
return advisory_script_entrypoint_;
}
void UIDartState::DidSetIsolate() {
main_port_ = Dart_GetMainPortId();
std::ostringstream debug_name;
// main.dart$main-1234
debug_name << advisory_script_uri_ << "$" << advisory_script_entrypoint_
<< "-" << main_port_;
SetDebugName(debug_name.str());
}
void UIDartState::ThrowIfUIOperationsProhibited() {
if (!UIDartState::Current()->IsRootIsolate()) {
Dart_ThrowException(
tonic::ToDart("UI actions are only available on root isolate."));
}
}
void UIDartState::SetDebugName(const std::string debug_name) {
debug_name_ = debug_name;
if (platform_configuration_) {
platform_configuration_->client()->UpdateIsolateDescription(debug_name_,
main_port_);
}
}
UIDartState* UIDartState::Current() {
return static_cast<UIDartState*>(DartState::Current());
}
void UIDartState::SetPlatformConfiguration(
std::unique_ptr<PlatformConfiguration> platform_configuration) {
platform_configuration_ = std::move(platform_configuration);
if (platform_configuration_) {
platform_configuration_->client()->UpdateIsolateDescription(debug_name_,
main_port_);
}
}
const TaskRunners& UIDartState::GetTaskRunners() const {
return task_runners_;
}
fml::WeakPtr<IOManager> UIDartState::GetIOManager() const {
return io_manager_;
}
fml::RefPtr<flutter::SkiaUnrefQueue> UIDartState::GetSkiaUnrefQueue() const {
return skia_unref_queue_;
}
void UIDartState::ScheduleMicrotask(Dart_Handle closure) {
if (tonic::LogIfError(closure) || !Dart_IsClosure(closure)) {
return;
}
microtask_queue_.ScheduleMicrotask(closure);
}
void UIDartState::FlushMicrotasksNow() {
microtask_queue_.RunMicrotasks();
}
void UIDartState::AddOrRemoveTaskObserver(bool add) {
auto task_runner = task_runners_.GetUITaskRunner();
if (!task_runner) {
// This may happen in case the isolate has no thread affinity (for example,
// the service isolate).
return;
}
FML_DCHECK(add_callback_ && remove_callback_);
if (add) {
add_callback_(reinterpret_cast<intptr_t>(this),
[this]() { this->FlushMicrotasksNow(); });
} else {
remove_callback_(reinterpret_cast<intptr_t>(this));
}
}
fml::WeakPtr<SnapshotDelegate> UIDartState::GetSnapshotDelegate() const {
return snapshot_delegate_;
}
fml::WeakPtr<HintFreedDelegate> UIDartState::GetHintFreedDelegate() const {
return hint_freed_delegate_;
}
fml::WeakPtr<GrDirectContext> UIDartState::GetResourceContext() const {
if (!io_manager_) {
return {};
}
return io_manager_->GetResourceContext();
}
fml::WeakPtr<ImageDecoder> UIDartState::GetImageDecoder() const {
return image_decoder_;
}
std::shared_ptr<IsolateNameServer> UIDartState::GetIsolateNameServer() const {
return isolate_name_server_;
}
tonic::DartErrorHandleType UIDartState::GetLastError() {
tonic::DartErrorHandleType error = message_handler().isolate_last_error();
if (error == tonic::kNoError) {
error = microtask_queue_.GetLastError();
}
return error;
}
void UIDartState::ReportUnhandledException(const std::string& error,
const std::string& stack_trace) {
if (unhandled_exception_callback_ &&
unhandled_exception_callback_(error, stack_trace)) {
return;
}
// Either the exception handler was not set or it could not handle the error,
// just log the exception.
FML_LOG(ERROR) << "Unhandled Exception: " << error << std::endl
<< stack_trace;
}
} // namespace flutter