| // 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 <iostream> |
| #include <utility> |
| |
| #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" |
| |
| #if defined(FML_OS_ANDROID) |
| #include <android/log.h> |
| #elif defined(FML_OS_IOS) |
| extern "C" { |
| // Cannot import the syslog.h header directly because of macro collision. |
| extern void syslog(int, const char*, ...); |
| } |
| #endif |
| |
| using tonic::ToDart; |
| |
| namespace flutter { |
| |
| UIDartState::Context::Context(const TaskRunners& task_runners) |
| : task_runners(task_runners) {} |
| |
| UIDartState::Context::Context( |
| const TaskRunners& task_runners, |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, |
| fml::WeakPtr<IOManager> io_manager, |
| fml::RefPtr<SkiaUnrefQueue> unref_queue, |
| fml::WeakPtr<ImageDecoder> image_decoder, |
| fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry, |
| std::string advisory_script_uri, |
| std::string advisory_script_entrypoint, |
| std::shared_ptr<VolatilePathTracker> volatile_path_tracker, |
| std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner, |
| bool enable_impeller) |
| : task_runners(task_runners), |
| snapshot_delegate(std::move(snapshot_delegate)), |
| io_manager(std::move(io_manager)), |
| unref_queue(std::move(unref_queue)), |
| image_decoder(std::move(image_decoder)), |
| image_generator_registry(std::move(image_generator_registry)), |
| advisory_script_uri(std::move(advisory_script_uri)), |
| advisory_script_entrypoint(std::move(advisory_script_entrypoint)), |
| volatile_path_tracker(std::move(volatile_path_tracker)), |
| concurrent_task_runner(std::move(concurrent_task_runner)), |
| enable_impeller(enable_impeller) {} |
| |
| UIDartState::UIDartState( |
| TaskObserverAdd add_callback, |
| TaskObserverRemove remove_callback, |
| std::string logger_prefix, |
| UnhandledExceptionCallback unhandled_exception_callback, |
| LogMessageCallback log_message_callback, |
| std::shared_ptr<IsolateNameServer> isolate_name_server, |
| bool is_root_isolate, |
| bool enable_skparagraph, |
| const UIDartState::Context& context) |
| : add_callback_(std::move(add_callback)), |
| remove_callback_(std::move(remove_callback)), |
| logger_prefix_(std::move(logger_prefix)), |
| is_root_isolate_(is_root_isolate), |
| unhandled_exception_callback_(std::move(unhandled_exception_callback)), |
| log_message_callback_(std::move(log_message_callback)), |
| isolate_name_server_(std::move(isolate_name_server)), |
| enable_skparagraph_(enable_skparagraph), |
| context_(context) { |
| AddOrRemoveTaskObserver(true /* add */); |
| } |
| |
| UIDartState::~UIDartState() { |
| AddOrRemoveTaskObserver(false /* remove */); |
| } |
| |
| const std::string& UIDartState::GetAdvisoryScriptURI() const { |
| return context_.advisory_script_uri; |
| } |
| |
| bool UIDartState::IsImpellerEnabled() const { |
| return context_.enable_impeller; |
| } |
| |
| void UIDartState::DidSetIsolate() { |
| main_port_ = Dart_GetMainPortId(); |
| std::ostringstream debug_name; |
| // main.dart$main-1234 |
| debug_name << context_.advisory_script_uri << "$" |
| << context_.advisory_script_entrypoint << "-" << main_port_; |
| SetDebugName(debug_name.str()); |
| } |
| |
| void UIDartState::ThrowIfUIOperationsProhibited() { |
| if (!UIDartState::Current()->IsRootIsolate()) { |
| Dart_EnterScope(); |
| 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) { |
| FML_DCHECK(IsRootIsolate()); |
| platform_configuration_ = std::move(platform_configuration); |
| if (platform_configuration_) { |
| platform_configuration_->client()->UpdateIsolateDescription(debug_name_, |
| main_port_); |
| } |
| } |
| |
| void UIDartState::SetPlatformMessageHandler( |
| std::weak_ptr<PlatformMessageHandler> handler) { |
| FML_DCHECK(!IsRootIsolate()); |
| platform_message_handler_ = std::move(handler); |
| } |
| |
| const TaskRunners& UIDartState::GetTaskRunners() const { |
| return context_.task_runners; |
| } |
| |
| fml::WeakPtr<IOManager> UIDartState::GetIOManager() const { |
| return context_.io_manager; |
| } |
| |
| fml::RefPtr<flutter::SkiaUnrefQueue> UIDartState::GetSkiaUnrefQueue() const { |
| return context_.unref_queue; |
| } |
| |
| std::shared_ptr<VolatilePathTracker> UIDartState::GetVolatilePathTracker() |
| const { |
| return context_.volatile_path_tracker; |
| } |
| |
| std::shared_ptr<fml::ConcurrentTaskRunner> |
| UIDartState::GetConcurrentTaskRunner() const { |
| return context_.concurrent_task_runner; |
| } |
| |
| void UIDartState::ScheduleMicrotask(Dart_Handle closure) { |
| if (tonic::CheckAndHandleError(closure) || !Dart_IsClosure(closure)) { |
| return; |
| } |
| |
| microtask_queue_.ScheduleMicrotask(closure); |
| } |
| |
| void UIDartState::FlushMicrotasksNow() { |
| microtask_queue_.RunMicrotasks(); |
| } |
| |
| void UIDartState::AddOrRemoveTaskObserver(bool add) { |
| auto task_runner = context_.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::TaskRunnerAffineWeakPtr<SnapshotDelegate> |
| UIDartState::GetSnapshotDelegate() const { |
| return context_.snapshot_delegate; |
| } |
| |
| fml::WeakPtr<ImageDecoder> UIDartState::GetImageDecoder() const { |
| return context_.image_decoder; |
| } |
| |
| fml::WeakPtr<ImageGeneratorRegistry> UIDartState::GetImageGeneratorRegistry() |
| const { |
| return context_.image_generator_registry; |
| } |
| |
| 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::LogMessage(const std::string& tag, |
| const std::string& message) const { |
| if (log_message_callback_) { |
| log_message_callback_(tag, message); |
| } else { |
| // Fall back to previous behavior if unspecified. |
| #if defined(FML_OS_ANDROID) |
| __android_log_print(ANDROID_LOG_INFO, tag.c_str(), "%.*s", |
| static_cast<int>(message.size()), message.c_str()); |
| #elif defined(FML_OS_IOS) |
| std::stringstream stream; |
| if (!tag.empty()) { |
| stream << tag << ": "; |
| } |
| stream << message; |
| std::string log = stream.str(); |
| syslog(1 /* LOG_ALERT */, "%.*s", static_cast<int>(log.size()), |
| log.c_str()); |
| #else |
| if (!tag.empty()) { |
| std::cout << tag << ": "; |
| } |
| std::cout << message << std::endl; |
| #endif |
| } |
| } |
| |
| bool UIDartState::enable_skparagraph() const { |
| return enable_skparagraph_; |
| } |
| |
| Dart_Handle UIDartState::HandlePlatformMessage( |
| std::unique_ptr<PlatformMessage> message) { |
| if (platform_configuration_) { |
| platform_configuration_->client()->HandlePlatformMessage( |
| std::move(message)); |
| } else { |
| std::shared_ptr<PlatformMessageHandler> handler = |
| platform_message_handler_.lock(); |
| if (handler) { |
| handler->HandlePlatformMessage(std::move(message)); |
| } else { |
| return tonic::ToDart( |
| "No platform channel handler registered for background isolate."); |
| } |
| } |
| |
| return Dart_Null(); |
| } |
| |
| int64_t UIDartState::GetRootIsolateToken() const { |
| return IsRootIsolate() ? reinterpret_cast<int64_t>(this) : 0; |
| } |
| |
| } // namespace flutter |