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 <iostream>
8#include <utility>
9
10#include "flutter/fml/message_loop.h"
11#include "flutter/lib/ui/window/platform_configuration.h"
12#include "third_party/tonic/converter/dart_converter.h"
13#include "third_party/tonic/dart_message_handler.h"
14
15#if defined(FML_OS_ANDROID)
16#include <android/log.h>
17#elif defined(FML_OS_IOS)
18extern "C" {
19// Cannot import the syslog.h header directly because of macro collision.
20extern void syslog(int, const char*, ...);
21}
22#endif
23
24using tonic::ToDart;
25
26namespace flutter {
27
28UIDartState::Context::Context(const TaskRunners& task_runners)
29 : task_runners(task_runners) {}
30
31UIDartState::Context::Context(
32 const TaskRunners& task_runners,
33 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
34 fml::WeakPtr<IOManager> io_manager,
35 fml::RefPtr<SkiaUnrefQueue> unref_queue,
36 fml::WeakPtr<ImageDecoder> image_decoder,
37 fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
38 std::string advisory_script_uri,
39 std::string advisory_script_entrypoint,
40 std::shared_ptr<VolatilePathTracker> volatile_path_tracker,
41 std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
42 bool enable_impeller)
43 : task_runners(task_runners),
44 snapshot_delegate(std::move(snapshot_delegate)),
45 io_manager(std::move(io_manager)),
46 unref_queue(std::move(unref_queue)),
47 image_decoder(std::move(image_decoder)),
48 image_generator_registry(std::move(image_generator_registry)),
49 advisory_script_uri(std::move(advisory_script_uri)),
50 advisory_script_entrypoint(std::move(advisory_script_entrypoint)),
51 volatile_path_tracker(std::move(volatile_path_tracker)),
52 concurrent_task_runner(std::move(concurrent_task_runner)),
53 enable_impeller(enable_impeller) {}
54
55UIDartState::UIDartState(
56 TaskObserverAdd add_callback,
57 TaskObserverRemove remove_callback,
58 std::string logger_prefix,
59 UnhandledExceptionCallback unhandled_exception_callback,
60 LogMessageCallback log_message_callback,
61 std::shared_ptr<IsolateNameServer> isolate_name_server,
62 bool is_root_isolate,
63 const UIDartState::Context& context)
64 : add_callback_(std::move(add_callback)),
65 remove_callback_(std::move(remove_callback)),
66 logger_prefix_(std::move(logger_prefix)),
67 is_root_isolate_(is_root_isolate),
68 unhandled_exception_callback_(std::move(unhandled_exception_callback)),
69 log_message_callback_(std::move(log_message_callback)),
70 isolate_name_server_(std::move(isolate_name_server)),
71 context_(context) {
72 AddOrRemoveTaskObserver(add: true /* add */);
73}
74
75UIDartState::~UIDartState() {
76 AddOrRemoveTaskObserver(add: false /* remove */);
77}
78
79const std::string& UIDartState::GetAdvisoryScriptURI() const {
80 return context_.advisory_script_uri;
81}
82
83bool UIDartState::IsImpellerEnabled() const {
84 return context_.enable_impeller;
85}
86
87void UIDartState::DidSetIsolate() {
88 main_port_ = Dart_GetMainPortId();
89 std::ostringstream debug_name;
90 // main.dart$main-1234
91 debug_name << context_.advisory_script_uri << "$"
92 << context_.advisory_script_entrypoint << "-" << main_port_;
93 SetDebugName(debug_name.str());
94}
95
96void UIDartState::ThrowIfUIOperationsProhibited() {
97 if (!UIDartState::Current()->IsRootIsolate()) {
98 Dart_EnterScope();
99 Dart_ThrowException(
100 exception: tonic::ToDart(val: "UI actions are only available on root isolate."));
101 }
102}
103
104void UIDartState::SetDebugName(const std::string& debug_name) {
105 debug_name_ = debug_name;
106 if (platform_configuration_) {
107 platform_configuration_->client()->UpdateIsolateDescription(isolate_name: debug_name_,
108 isolate_port: main_port_);
109 }
110}
111
112UIDartState* UIDartState::Current() {
113 return static_cast<UIDartState*>(DartState::Current());
114}
115
116void UIDartState::SetPlatformConfiguration(
117 std::unique_ptr<PlatformConfiguration> platform_configuration) {
118 FML_DCHECK(IsRootIsolate());
119 platform_configuration_ = std::move(platform_configuration);
120 if (platform_configuration_) {
121 platform_configuration_->client()->UpdateIsolateDescription(isolate_name: debug_name_,
122 isolate_port: main_port_);
123 }
124}
125
126void UIDartState::SetPlatformMessageHandler(
127 std::weak_ptr<PlatformMessageHandler> handler) {
128 FML_DCHECK(!IsRootIsolate());
129 platform_message_handler_ = std::move(handler);
130}
131
132const TaskRunners& UIDartState::GetTaskRunners() const {
133 return context_.task_runners;
134}
135
136fml::WeakPtr<IOManager> UIDartState::GetIOManager() const {
137 return context_.io_manager;
138}
139
140fml::RefPtr<flutter::SkiaUnrefQueue> UIDartState::GetSkiaUnrefQueue() const {
141 return context_.unref_queue;
142}
143
144std::shared_ptr<VolatilePathTracker> UIDartState::GetVolatilePathTracker()
145 const {
146 return context_.volatile_path_tracker;
147}
148
149std::shared_ptr<fml::ConcurrentTaskRunner>
150UIDartState::GetConcurrentTaskRunner() const {
151 return context_.concurrent_task_runner;
152}
153
154void UIDartState::ScheduleMicrotask(Dart_Handle closure) {
155 if (tonic::CheckAndHandleError(handle: closure) || !Dart_IsClosure(object: closure)) {
156 return;
157 }
158
159 microtask_queue_.ScheduleMicrotask(callback: closure);
160}
161
162void UIDartState::FlushMicrotasksNow() {
163 microtask_queue_.RunMicrotasks();
164}
165
166void UIDartState::AddOrRemoveTaskObserver(bool add) {
167 auto task_runner = context_.task_runners.GetUITaskRunner();
168 if (!task_runner) {
169 // This may happen in case the isolate has no thread affinity (for example,
170 // the service isolate).
171 return;
172 }
173 FML_DCHECK(add_callback_ && remove_callback_);
174 if (add) {
175 add_callback_(reinterpret_cast<intptr_t>(this),
176 [this]() { this->FlushMicrotasksNow(); });
177 } else {
178 remove_callback_(reinterpret_cast<intptr_t>(this));
179 }
180}
181
182fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>
183UIDartState::GetSnapshotDelegate() const {
184 return context_.snapshot_delegate;
185}
186
187fml::WeakPtr<ImageDecoder> UIDartState::GetImageDecoder() const {
188 return context_.image_decoder;
189}
190
191fml::WeakPtr<ImageGeneratorRegistry> UIDartState::GetImageGeneratorRegistry()
192 const {
193 return context_.image_generator_registry;
194}
195
196std::shared_ptr<IsolateNameServer> UIDartState::GetIsolateNameServer() const {
197 return isolate_name_server_;
198}
199
200tonic::DartErrorHandleType UIDartState::GetLastError() {
201 tonic::DartErrorHandleType error = message_handler().isolate_last_error();
202 if (error == tonic::kNoError) {
203 error = microtask_queue_.GetLastError();
204 }
205 return error;
206}
207
208void UIDartState::LogMessage(const std::string& tag,
209 const std::string& message) const {
210 if (log_message_callback_) {
211 log_message_callback_(tag, message);
212 } else {
213 // Fall back to previous behavior if unspecified.
214#if defined(FML_OS_ANDROID)
215 __android_log_print(ANDROID_LOG_INFO, tag.c_str(), "%.*s",
216 static_cast<int>(message.size()), message.c_str());
217#elif defined(FML_OS_IOS)
218 std::stringstream stream;
219 if (!tag.empty()) {
220 stream << tag << ": ";
221 }
222 stream << message;
223 std::string log = stream.str();
224 syslog(1 /* LOG_ALERT */, "%.*s", static_cast<int>(log.size()),
225 log.c_str());
226#else
227 if (!tag.empty()) {
228 std::cout << tag << ": ";
229 }
230 std::cout << message << std::endl;
231#endif
232 }
233}
234
235Dart_Handle UIDartState::HandlePlatformMessage(
236 std::unique_ptr<PlatformMessage> message) {
237 if (platform_configuration_) {
238 platform_configuration_->client()->HandlePlatformMessage(
239 message: std::move(message));
240 } else {
241 std::shared_ptr<PlatformMessageHandler> handler =
242 platform_message_handler_.lock();
243 if (handler) {
244 handler->HandlePlatformMessage(message: std::move(message));
245 } else {
246 return tonic::ToDart(
247 val: "No platform channel handler registered for background isolate.");
248 }
249 }
250
251 return Dart_Null();
252}
253
254int64_t UIDartState::GetRootIsolateToken() const {
255 return IsRootIsolate() ? reinterpret_cast<int64_t>(this) : 0;
256}
257
258} // namespace flutter
259

source code of flutter_engine/flutter/lib/ui/ui_dart_state.cc