blob: 65cef346ec1735483f9b92e79b8b02214ae16e6a [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 <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