1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/lib/ui/ui_dart_state.h"
6
7#include "flutter/fml/message_loop.h"
8#include "flutter/lib/ui/window/platform_configuration.h"
9#include "third_party/tonic/converter/dart_converter.h"
10#include "third_party/tonic/dart_message_handler.h"
11
12using tonic::ToDart;
13
14namespace flutter {
15
16UIDartState::UIDartState(
17 TaskRunners task_runners,
18 TaskObserverAdd add_callback,
19 TaskObserverRemove remove_callback,
20 fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
21 fml::WeakPtr<IOManager> io_manager,
22 fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
23 fml::WeakPtr<ImageDecoder> image_decoder,
24 std::string advisory_script_uri,
25 std::string advisory_script_entrypoint,
26 std::string logger_prefix,
27 UnhandledExceptionCallback unhandled_exception_callback,
28 std::shared_ptr<IsolateNameServer> isolate_name_server,
29 bool is_root_isolate)
30 : task_runners_(std::move(task_runners)),
31 add_callback_(std::move(add_callback)),
32 remove_callback_(std::move(remove_callback)),
33 snapshot_delegate_(std::move(snapshot_delegate)),
34 io_manager_(std::move(io_manager)),
35 skia_unref_queue_(std::move(skia_unref_queue)),
36 image_decoder_(std::move(image_decoder)),
37 advisory_script_uri_(std::move(advisory_script_uri)),
38 advisory_script_entrypoint_(std::move(advisory_script_entrypoint)),
39 logger_prefix_(std::move(logger_prefix)),
40 is_root_isolate_(is_root_isolate),
41 unhandled_exception_callback_(unhandled_exception_callback),
42 isolate_name_server_(std::move(isolate_name_server)) {
43 AddOrRemoveTaskObserver(true /* add */);
44}
45
46UIDartState::~UIDartState() {
47 AddOrRemoveTaskObserver(false /* remove */);
48}
49
50const std::string& UIDartState::GetAdvisoryScriptURI() const {
51 return advisory_script_uri_;
52}
53
54const std::string& UIDartState::GetAdvisoryScriptEntrypoint() const {
55 return advisory_script_entrypoint_;
56}
57
58void UIDartState::DidSetIsolate() {
59 main_port_ = Dart_GetMainPortId();
60 std::ostringstream debug_name;
61 // main.dart$main-1234
62 debug_name << advisory_script_uri_ << "$" << advisory_script_entrypoint_
63 << "-" << main_port_;
64 SetDebugName(debug_name.str());
65}
66
67void UIDartState::ThrowIfUIOperationsProhibited() {
68 if (!UIDartState::Current()->IsRootIsolate()) {
69 Dart_ThrowException(
70 tonic::ToDart("UI actions are only available on root isolate."));
71 }
72}
73
74void UIDartState::SetDebugName(const std::string debug_name) {
75 debug_name_ = debug_name;
76 if (platform_configuration_) {
77 platform_configuration_->client()->UpdateIsolateDescription(debug_name_,
78 main_port_);
79 }
80}
81
82UIDartState* UIDartState::Current() {
83 return static_cast<UIDartState*>(DartState::Current());
84}
85
86void UIDartState::SetPlatformConfiguration(
87 std::unique_ptr<PlatformConfiguration> platform_configuration) {
88 platform_configuration_ = std::move(platform_configuration);
89 if (platform_configuration_) {
90 platform_configuration_->client()->UpdateIsolateDescription(debug_name_,
91 main_port_);
92 }
93}
94
95const TaskRunners& UIDartState::GetTaskRunners() const {
96 return task_runners_;
97}
98
99fml::WeakPtr<IOManager> UIDartState::GetIOManager() const {
100 return io_manager_;
101}
102
103fml::RefPtr<flutter::SkiaUnrefQueue> UIDartState::GetSkiaUnrefQueue() const {
104 return skia_unref_queue_;
105}
106
107void UIDartState::ScheduleMicrotask(Dart_Handle closure) {
108 if (tonic::LogIfError(closure) || !Dart_IsClosure(closure)) {
109 return;
110 }
111
112 microtask_queue_.ScheduleMicrotask(closure);
113}
114
115void UIDartState::FlushMicrotasksNow() {
116 microtask_queue_.RunMicrotasks();
117}
118
119void UIDartState::AddOrRemoveTaskObserver(bool add) {
120 auto task_runner = task_runners_.GetUITaskRunner();
121 if (!task_runner) {
122 // This may happen in case the isolate has no thread affinity (for example,
123 // the service isolate).
124 return;
125 }
126 FML_DCHECK(add_callback_ && remove_callback_);
127 if (add) {
128 add_callback_(reinterpret_cast<intptr_t>(this),
129 [this]() { this->FlushMicrotasksNow(); });
130 } else {
131 remove_callback_(reinterpret_cast<intptr_t>(this));
132 }
133}
134
135fml::WeakPtr<SnapshotDelegate> UIDartState::GetSnapshotDelegate() const {
136 return snapshot_delegate_;
137}
138
139fml::WeakPtr<GrDirectContext> UIDartState::GetResourceContext() const {
140 if (!io_manager_) {
141 return {};
142 }
143 return io_manager_->GetResourceContext();
144}
145
146fml::WeakPtr<ImageDecoder> UIDartState::GetImageDecoder() const {
147 return image_decoder_;
148}
149
150std::shared_ptr<IsolateNameServer> UIDartState::GetIsolateNameServer() const {
151 return isolate_name_server_;
152}
153
154tonic::DartErrorHandleType UIDartState::GetLastError() {
155 tonic::DartErrorHandleType error = message_handler().isolate_last_error();
156 if (error == tonic::kNoError) {
157 error = microtask_queue_.GetLastError();
158 }
159 return error;
160}
161
162void UIDartState::ReportUnhandledException(const std::string& error,
163 const std::string& stack_trace) {
164 if (unhandled_exception_callback_ &&
165 unhandled_exception_callback_(error, stack_trace)) {
166 return;
167 }
168
169 // Either the exception handler was not set or it could not handle the error,
170 // just log the exception.
171 FML_LOG(ERROR) << "Unhandled Exception: " << error << std::endl
172 << stack_trace;
173}
174
175} // namespace flutter
176