Filip Filmar 6c763bb551 [fuchsia] Temporarily disable intl provider (#13696)
The intention of the property provider is to try to connect, not
bail out if connection is not possible.

This code tried to connect unconditionally, which is not what we wanted.
Removing this initialization code to enable a roll, and will fix in a
followup.
2019-11-05 18:51:37 -08:00

474 lines
17 KiB
C++

// 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 "engine.h"
#include <lib/async/cpp/task.h>
#include <zircon/status.h>
#include <sstream>
#include "flutter/common/task_runners.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/task_runner.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/run_configuration.h"
#include "fuchsia_intl.h"
#include "platform_view.h"
#include "runtime/dart/utils/files.h"
#include "task_runner_adapter.h"
#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
#include "thread.h"
namespace flutter_runner {
static void UpdateNativeThreadLabelNames(const std::string& label,
const flutter::TaskRunners& runners) {
auto set_thread_name = [](fml::RefPtr<fml::TaskRunner> runner,
std::string prefix, std::string suffix) {
if (!runner) {
return;
}
fml::TaskRunner::RunNowOrPostTask(runner, [name = prefix + suffix]() {
zx::thread::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size());
});
};
set_thread_name(runners.GetPlatformTaskRunner(), label, ".platform");
set_thread_name(runners.GetUITaskRunner(), label, ".ui");
set_thread_name(runners.GetGPUTaskRunner(), label, ".gpu");
set_thread_name(runners.GetIOTaskRunner(), label, ".io");
}
Engine::Engine(Delegate& delegate,
std::string thread_label,
std::shared_ptr<sys::ServiceDirectory> svc,
std::shared_ptr<sys::ServiceDirectory> runner_services,
flutter::Settings settings,
fml::RefPtr<const flutter::DartSnapshot> isolate_snapshot,
fuchsia::ui::views::ViewToken view_token,
fuchsia::ui::views::ViewRefControl view_ref_control,
fuchsia::ui::views::ViewRef view_ref,
UniqueFDIONS fdio_ns,
fidl::InterfaceRequest<fuchsia::io::Directory> directory_request)
: delegate_(delegate),
thread_label_(std::move(thread_label)),
settings_(std::move(settings)),
weak_factory_(this) {
if (zx::event::create(0, &vsync_event_) != ZX_OK) {
FML_DLOG(ERROR) << "Could not create the vsync event.";
return;
}
// Launch the threads that will be used to run the shell. These threads will
// be joined in the destructor.
for (auto& thread : threads_) {
thread.reset(new Thread());
}
// Set up the session connection.
auto scenic = svc->Connect<fuchsia::ui::scenic::Scenic>();
fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session;
fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> session_listener;
auto session_listener_request = session_listener.NewRequest();
scenic->CreateSession(session.NewRequest(), session_listener.Bind());
// Grab the parent environment services. The platform view may want to access
// some of these services.
fuchsia::sys::EnvironmentPtr environment;
svc->Connect(environment.NewRequest());
fidl::InterfaceHandle<fuchsia::sys::ServiceProvider>
parent_environment_service_provider;
environment->GetServices(parent_environment_service_provider.NewRequest());
environment.Unbind();
// We need to manually schedule a frame when the session metrics change.
OnMetricsUpdate on_session_metrics_change_callback = std::bind(
&Engine::OnSessionMetricsDidChange, this, std::placeholders::_1);
OnSizeChangeHint on_session_size_change_hint_callback =
std::bind(&Engine::OnSessionSizeChangeHint, this, std::placeholders::_1,
std::placeholders::_2);
OnEnableWireframe on_enable_wireframe_callback = std::bind(
&Engine::OnDebugWireframeSettingsChanged, this, std::placeholders::_1);
// SessionListener has a OnScenicError method; invoke this callback on the
// platform thread when that happens. The Session itself should also be
// disconnected when this happens, and it will also attempt to terminate.
fit::closure on_session_listener_error_callback =
[dispatcher = async_get_default_dispatcher(),
weak = weak_factory_.GetWeakPtr()]() {
async::PostTask(dispatcher, [weak]() {
if (weak) {
weak->Terminate();
}
});
};
// Setup the callback that will instantiate the platform view.
flutter::Shell::CreateCallback<flutter::PlatformView>
on_create_platform_view = fml::MakeCopyable(
[debug_label = thread_label_,
view_ref_control = std::move(view_ref_control),
view_ref = std::move(view_ref), runner_services,
parent_environment_service_provider =
std::move(parent_environment_service_provider),
session_listener_request = std::move(session_listener_request),
on_session_listener_error_callback =
std::move(on_session_listener_error_callback),
on_session_metrics_change_callback =
std::move(on_session_metrics_change_callback),
on_session_size_change_hint_callback =
std::move(on_session_size_change_hint_callback),
on_enable_wireframe_callback =
std::move(on_enable_wireframe_callback),
vsync_handle = vsync_event_.get()](flutter::Shell& shell) mutable {
return std::make_unique<flutter_runner::PlatformView>(
shell, // delegate
debug_label, // debug label
std::move(view_ref_control), // view control ref
std::move(view_ref), // view ref
shell.GetTaskRunners(), // task runners
std::move(runner_services),
std::move(parent_environment_service_provider), // services
std::move(session_listener_request), // session listener
std::move(on_session_listener_error_callback),
std::move(on_session_metrics_change_callback),
std::move(on_session_size_change_hint_callback),
std::move(on_enable_wireframe_callback),
vsync_handle // vsync handle
);
});
// Session can be terminated on the GPU thread, but we must terminate
// ourselves on the platform thread.
//
// This handles the fidl error callback when the Session connection is
// broken. The SessionListener interface also has an OnError method, which is
// invoked on the platform thread (in PlatformView).
fml::closure on_session_error_callback =
[dispatcher = async_get_default_dispatcher(),
weak = weak_factory_.GetWeakPtr()]() {
async::PostTask(dispatcher, [weak]() {
if (weak) {
weak->Terminate();
}
});
};
// Get the task runners from the managed threads. The current thread will be
// used as the "platform" thread.
const flutter::TaskRunners task_runners(
thread_label_, // Dart thread labels
CreateFMLTaskRunner(async_get_default_dispatcher()), // platform
CreateFMLTaskRunner(threads_[0]->dispatcher()), // gpu
CreateFMLTaskRunner(threads_[1]->dispatcher()), // ui
CreateFMLTaskRunner(threads_[2]->dispatcher()) // io
);
// Setup the callback that will instantiate the rasterizer.
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
fml::MakeCopyable([thread_label = thread_label_, //
view_token = std::move(view_token), //
session = std::move(session), //
on_session_error_callback, //
vsync_event = vsync_event_.get() //
](flutter::Shell& shell) mutable {
std::unique_ptr<flutter_runner::CompositorContext> compositor_context;
{
TRACE_DURATION("flutter", "CreateCompositorContext");
compositor_context =
std::make_unique<flutter_runner::CompositorContext>(
thread_label, // debug label
std::move(view_token), // scenic view we attach our tree to
std::move(session), // scenic session
on_session_error_callback, // session did encounter error
vsync_event // vsync event handle
);
}
return std::make_unique<flutter::Rasterizer>(
shell.GetTaskRunners(), // task runners
std::move(compositor_context) // compositor context
);
});
UpdateNativeThreadLabelNames(thread_label_, task_runners);
settings_.verbose_logging = true;
settings_.advisory_script_uri = thread_label_;
settings_.advisory_script_entrypoint = thread_label_;
settings_.root_isolate_create_callback =
std::bind(&Engine::OnMainIsolateStart, this);
settings_.root_isolate_shutdown_callback =
std::bind([weak = weak_factory_.GetWeakPtr(),
runner = task_runners.GetPlatformTaskRunner()]() {
runner->PostTask([weak = std::move(weak)] {
if (weak) {
weak->OnMainIsolateShutdown();
}
});
});
auto vm = flutter::DartVMRef::Create(settings_);
if (!isolate_snapshot) {
isolate_snapshot = vm->GetVMData()->GetIsolateSnapshot();
}
{
TRACE_EVENT0("flutter", "CreateShell");
shell_ = flutter::Shell::Create(
task_runners, // host task runners
settings_, // shell launch settings
std::move(isolate_snapshot), // isolate snapshot
on_create_platform_view, // platform view create callback
on_create_rasterizer, // rasterizer create callback
std::move(vm) // vm reference
);
}
if (!shell_) {
FML_LOG(ERROR) << "Could not launch the shell.";
return;
}
// Shell has been created. Before we run the engine, setup the isolate
// configurator.
{
fuchsia::sys::EnvironmentPtr environment;
svc->Connect(environment.NewRequest());
isolate_configurator_ = std::make_unique<IsolateConfigurator>(
std::move(fdio_ns), //
std::move(environment), //
directory_request.TakeChannel() //
);
}
// This platform does not get a separate surface platform view creation
// notification. Fire one eagerly.
shell_->GetPlatformView()->NotifyCreated();
// Launch the engine in the appropriate configuration.
auto run_configuration = flutter::RunConfiguration::InferFromSettings(
settings_, task_runners.GetIOTaskRunner());
auto on_run_failure = [weak = weak_factory_.GetWeakPtr()]() {
// The engine could have been killed by the caller right after the
// constructor was called but before it could run on the UI thread.
if (weak) {
weak->Terminate();
}
};
// Connect to the system font provider.
fuchsia::fonts::ProviderSyncPtr sync_font_provider;
svc->Connect(sync_font_provider.NewRequest());
shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
fml::MakeCopyable([engine = shell_->GetEngine(), //
run_configuration = std::move(run_configuration), //
sync_font_provider = std::move(sync_font_provider), //
on_run_failure //
]() mutable {
if (!engine) {
return;
}
// Set default font manager.
engine->GetFontCollection().GetFontCollection()->SetDefaultFontManager(
SkFontMgr_New_Fuchsia(std::move(sync_font_provider)));
if (engine->Run(std::move(run_configuration)) ==
flutter::Engine::RunStatus::Failure) {
on_run_failure();
}
}));
}
Engine::~Engine() {
shell_.reset();
for (const auto& thread : threads_) {
thread->Quit();
}
for (const auto& thread : threads_) {
thread->Join();
}
}
std::pair<bool, uint32_t> Engine::GetEngineReturnCode() const {
std::pair<bool, uint32_t> code(false, 0);
if (!shell_) {
return code;
}
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell_->GetTaskRunners().GetUITaskRunner(),
[&latch, &code, engine = shell_->GetEngine()]() {
if (engine) {
code = engine->GetUIIsolateReturnCode();
}
latch.Signal();
});
latch.Wait();
return code;
}
static void CreateCompilationTrace(Dart_Isolate isolate) {
Dart_EnterIsolate(isolate);
{
Dart_EnterScope();
uint8_t* trace = nullptr;
intptr_t trace_length = 0;
Dart_Handle result = Dart_SaveCompilationTrace(&trace, &trace_length);
tonic::LogIfError(result);
for (intptr_t start = 0; start < trace_length;) {
intptr_t end = start;
while ((end < trace_length) && trace[end] != '\n')
end++;
std::string line(reinterpret_cast<char*>(&trace[start]), end - start);
FML_LOG(INFO) << "compilation-trace: " << line;
start = end + 1;
}
Dart_ExitScope();
}
// Re-enter Dart scope to release the compilation trace's memory.
{
Dart_EnterScope();
uint8_t* feedback = nullptr;
intptr_t feedback_length = 0;
Dart_Handle result = Dart_SaveTypeFeedback(&feedback, &feedback_length);
tonic::LogIfError(result);
const std::string kTypeFeedbackFile = "/data/dart_type_feedback.bin";
if (dart_utils::WriteFile(kTypeFeedbackFile,
reinterpret_cast<const char*>(feedback),
feedback_length)) {
FML_LOG(INFO) << "Dart type feedback written to " << kTypeFeedbackFile;
} else {
FML_LOG(ERROR) << "Could not write Dart type feedback to "
<< kTypeFeedbackFile;
}
Dart_ExitScope();
}
Dart_ExitIsolate();
}
void Engine::OnMainIsolateStart() {
if (!isolate_configurator_ ||
!isolate_configurator_->ConfigureCurrentIsolate()) {
FML_LOG(ERROR) << "Could not configure some native embedder bindings for a "
"new root isolate.";
}
FML_DLOG(INFO) << "Main isolate for engine '" << thread_label_
<< "' was started.";
const intptr_t kCompilationTraceDelayInSeconds = 0;
if (kCompilationTraceDelayInSeconds != 0) {
Dart_Isolate isolate = Dart_CurrentIsolate();
FML_CHECK(isolate);
shell_->GetTaskRunners().GetUITaskRunner()->PostDelayedTask(
[engine = shell_->GetEngine(), isolate]() {
if (!engine) {
return;
}
CreateCompilationTrace(isolate);
},
fml::TimeDelta::FromSeconds(kCompilationTraceDelayInSeconds));
}
}
void Engine::OnMainIsolateShutdown() {
FML_DLOG(INFO) << "Main isolate for engine '" << thread_label_
<< "' shutting down.";
Terminate();
}
void Engine::Terminate() {
delegate_.OnEngineTerminate(this);
// Warning. Do not do anything after this point as the delegate may have
// collected this object.
}
void Engine::OnSessionMetricsDidChange(
const fuchsia::ui::gfx::Metrics& metrics) {
if (!shell_) {
return;
}
shell_->GetTaskRunners().GetGPUTaskRunner()->PostTask(
[rasterizer = shell_->GetRasterizer(), metrics]() {
if (rasterizer) {
auto compositor_context =
reinterpret_cast<flutter_runner::CompositorContext*>(
rasterizer->compositor_context());
compositor_context->OnSessionMetricsDidChange(metrics);
}
});
}
void Engine::OnDebugWireframeSettingsChanged(bool enabled) {
if (!shell_) {
return;
}
shell_->GetTaskRunners().GetGPUTaskRunner()->PostTask(
[rasterizer = shell_->GetRasterizer(), enabled]() {
if (rasterizer) {
auto compositor_context =
reinterpret_cast<flutter_runner::CompositorContext*>(
rasterizer->compositor_context());
compositor_context->OnWireframeEnabled(enabled);
}
});
}
void Engine::OnSessionSizeChangeHint(float width_change_factor,
float height_change_factor) {
if (!shell_) {
return;
}
shell_->GetTaskRunners().GetGPUTaskRunner()->PostTask(
[rasterizer = shell_->GetRasterizer(), width_change_factor,
height_change_factor]() {
if (rasterizer) {
auto compositor_context = reinterpret_cast<CompositorContext*>(
rasterizer->compositor_context());
compositor_context->OnSessionSizeChangeHint(width_change_factor,
height_change_factor);
}
});
}
#if !defined(DART_PRODUCT)
void Engine::WriteProfileToTrace() const {
Dart_Port main_port = shell_->GetEngine()->GetUIIsolateMainPort();
char* error = NULL;
bool success = Dart_WriteProfileToTimeline(main_port, &error);
if (!success) {
FML_LOG(ERROR) << "Failed to write Dart profile to trace: " << error;
free(error);
}
}
#endif // !defined(DART_PRODUCT)
} // namespace flutter_runner