提交 cee7fef7 编写于 作者: A Adam Barth 提交者: GitHub

Simplify Dart application startup (#2910)

There are now three ways to start Dart applications:

1) From a precompiled snapshot
2) From a snapshot
3) From source

When loading from source, we no longer use the complex data pipe /
dependency catcher mechanism. Instead, we just load the source
synchronously from the file system. This is appropriate because running
from source is used only during development and not during production.

The previous design was built assuming we would want to run from source
over the network, which meant we needed to be able to load source
asynchronously over a high latency channel.
上级 607d379c
......@@ -55,7 +55,7 @@ deps = {
Var('fuchsia_git') + '/ftl' + '@' + '0bb3a02301c8a88b494e58c6636fa509525adaa8',
'src/lib/tonic':
Var('fuchsia_git') + '/tonic' + '@' + '8e0776dc4aa1c7fab21b742279ef90527c59b216',
Var('fuchsia_git') + '/tonic' + '@' + '66fc8a71ae54c628537e7f4b2e8bf9304788c19d',
'src/third_party/gtest':
Var('fuchsia_git') + '/third_party/gtest' + '@' + 'c00f82917331efbbd27124b537e4ccc915a02b72',
......
......@@ -4,31 +4,33 @@
#include "flutter/sky/engine/core/script/dart_controller.h"
#include <utility>
#include "dart/runtime/include/dart_tools_api.h"
#include "flutter/glue/trace_event.h"
#include "flutter/sky/engine/bindings/dart_mojo_internal.h"
#include "flutter/sky/engine/bindings/dart_runtime_hooks.h"
#include "flutter/sky/engine/bindings/dart_ui.h"
#include "flutter/sky/engine/core/script/dart_init.h"
#include "flutter/sky/engine/core/script/dart_service_isolate.h"
#include "flutter/sky/engine/core/script/ui_dart_state.h"
#include "flutter/sky/engine/public/platform/Platform.h"
#include "flutter/sky/engine/public/platform/sky_settings.h"
#include "flutter/sky/engine/wtf/MakeUnique.h"
#include "flutter/tonic/dart_debugger.h"
#include "flutter/tonic/dart_dependency_catcher.h"
#include "flutter/tonic/dart_io.h"
#include "flutter/tonic/dart_library_loader.h"
#include "flutter/tonic/dart_snapshot_loader.h"
#include "flutter/tonic/dart_state.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/files/directory.h"
#include "lib/ftl/files/path.h"
#include "lib/tonic/dart_class_library.h"
#include "lib/tonic/dart_message_handler.h"
#include "lib/tonic/dart_wrappable.h"
#include "lib/tonic/file_loader/file_loader.h"
#include "lib/tonic/logging/dart_error.h"
#include "lib/tonic/logging/dart_invoke.h"
#include "lib/tonic/scopes/dart_api_scope.h"
#include "lib/tonic/scopes/dart_isolate_scope.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "flutter/sky/engine/bindings/dart_mojo_internal.h"
#include "flutter/sky/engine/bindings/dart_runtime_hooks.h"
#include "flutter/sky/engine/bindings/dart_ui.h"
#include "flutter/sky/engine/core/script/dart_init.h"
#include "flutter/sky/engine/core/script/dart_service_isolate.h"
#include "flutter/sky/engine/core/script/ui_dart_state.h"
#include "flutter/sky/engine/public/platform/Platform.h"
#include "flutter/sky/engine/public/platform/sky_settings.h"
#include "flutter/sky/engine/wtf/MakeUnique.h"
#ifdef OS_ANDROID
#include "flutter/lib/jni/dart_jni.h"
......@@ -38,6 +40,16 @@ using tonic::LogIfError;
using tonic::ToDart;
namespace blink {
namespace {
// TODO(abarth): Consider adding this to //lib/ftl.
std::string ResolvePath(std::string path) {
if (!path.empty() && path[0] == '/')
return path;
return files::SimplifyPath(files::GetCurrentDirectory() + "/" + path);
}
} // namespace
DartController::DartController() : ui_dart_state_(nullptr) {}
......@@ -53,6 +65,9 @@ DartController::~DartController() {
}
bool DartController::SendStartMessage(Dart_Handle root_library) {
if (LogIfError(root_library))
return true;
{
// Temporarily exit the isolate while we make it runnable.
Dart_Isolate isolate = dart_state()->isolate();
......@@ -93,67 +108,30 @@ bool DartController::SendStartMessage(Dart_Handle root_library) {
return LogIfError(result);
}
void DartController::DidLoadMainLibrary(std::string name) {
FTL_DCHECK(Dart_CurrentIsolate() == dart_state()->isolate());
tonic::DartApiScope dart_api_scope;
FTL_CHECK(!LogIfError(Dart_FinalizeLoading(true)));
Dart_Handle library = Dart_LookupLibrary(ToDart(name));
if (LogIfError(library))
exit(1);
if (SendStartMessage(library))
exit(1);
}
void DartController::DidLoadSnapshot() {
TRACE_EVENT0("flutter", "DartController::DidLoadSnapshot");
void DartController::RunFromPrecompiledSnapshot() {
TRACE_EVENT0("flutter", "DartController::RunFromPrecompiledSnapshot");
FTL_DCHECK(Dart_CurrentIsolate() == nullptr);
snapshot_loader_ = nullptr;
Dart_Isolate isolate = dart_state()->isolate();
tonic::DartIsolateScope isolate_scope(isolate);
tonic::DartApiScope dart_api_scope;
Dart_Handle library = Dart_RootLibrary();
if (LogIfError(library))
exit(1);
if (SendStartMessage(library))
tonic::DartState::Scope scope(dart_state());
if (SendStartMessage(Dart_RootLibrary()))
exit(1);
}
void DartController::RunFromPrecompiledSnapshot() {
DidLoadSnapshot();
}
void DartController::RunFromSnapshot(
mojo::ScopedDataPipeConsumerHandle snapshot) {
snapshot_loader_ = WTF::MakeUnique<DartSnapshotLoader>(dart_state());
snapshot_loader_->LoadSnapshot(snapshot.Pass(),
[this]() { DidLoadSnapshot(); });
}
void DartController::RunFromSnapshotBuffer(const uint8_t* buffer, size_t size) {
DartState::Scope scope(dart_state());
void DartController::RunFromSnapshot(const uint8_t* buffer, size_t size) {
tonic::DartState::Scope scope(dart_state());
LogIfError(Dart_LoadScriptFromSnapshot(buffer, size));
Dart_Handle library = Dart_RootLibrary();
if (LogIfError(library))
exit(1);
if (SendStartMessage(library))
if (SendStartMessage(Dart_RootLibrary()))
exit(1);
}
void DartController::RunFromLibrary(std::string name,
DartLibraryProvider* library_provider) {
DartState::Scope scope(dart_state());
DartLibraryLoader& loader = dart_state()->library_loader();
loader.set_library_provider(library_provider);
DartDependencyCatcher dependency_catcher(loader);
loader.LoadScript(name);
loader.WaitForDependencies(dependency_catcher.dependencies(),
[this, name]() { DidLoadMainLibrary(name); });
void DartController::RunFromSource(const std::string& main,
const std::string& packages) {
tonic::DartState::Scope scope(dart_state());
tonic::FileLoader& loader = dart_state()->file_loader();
if (!packages.empty() && !loader.LoadPackagesMap(ResolvePath(packages)))
FTL_LOG(WARNING) << "Failed to load package map: " << packages;
LogIfError(loader.LoadScript(main));
if (SendStartMessage(Dart_RootLibrary()))
exit(1);
}
void DartController::CreateIsolateFor(std::unique_ptr<UIDartState> state) {
......@@ -164,15 +142,15 @@ void DartController::CreateIsolateFor(std::unique_ptr<UIDartState> state) {
nullptr, static_cast<DartState*>(state.get()), &error);
FTL_CHECK(isolate) << error;
ui_dart_state_ = state.release();
auto& message_handler = dart_state()->message_handler();
FTL_DCHECK(Platform::current());
message_handler.Initialize(
dart_state()->message_handler().Initialize(
ftl::RefPtr<ftl::TaskRunner>(Platform::current()->GetUITaskRunner()));
Dart_SetShouldPauseOnStart(SkySettings::Get().start_paused);
ui_dart_state_->SetIsolate(isolate);
FTL_CHECK(!LogIfError(Dart_SetLibraryTagHandler(DartLibraryTagHandler)));
FTL_CHECK(!LogIfError(
Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag)));
{
tonic::DartApiScope dart_api_scope;
......
......@@ -13,8 +13,6 @@
namespace blink {
class UIDartState;
class DartLibraryProvider;
class DartSnapshotLoader;
class DartController {
public:
......@@ -23,27 +21,21 @@ class DartController {
static void InitVM();
void RunFromLibrary(std::string name, DartLibraryProvider* library_provider);
void RunFromPrecompiledSnapshot();
void RunFromSnapshot(mojo::ScopedDataPipeConsumerHandle snapshot);
void RunFromSnapshotBuffer(const uint8_t* buffer, size_t size);
void RunFromSnapshot(const uint8_t* buffer, size_t size);
void RunFromSource(const std::string& main, const std::string& packages);
void CreateIsolateFor(std::unique_ptr<UIDartState> ui_dart_state);
void Shutdown();
UIDartState* dart_state() const { return ui_dart_state_; }
private:
void DidLoadMainLibrary(std::string url);
void DidLoadSnapshot();
bool SendStartMessage(Dart_Handle root_library);
// The DartState associated with the main isolate. This will be deleted
// during isolate shutdown.
UIDartState* ui_dart_state_;
std::unique_ptr<DartSnapshotLoader> snapshot_loader_;
FTL_DISALLOW_COPY_AND_ASSIGN(DartController);
};
}
......
......@@ -16,10 +16,7 @@
#include "dart/runtime/include/dart_mirrors_api.h"
#include "flutter/assets/zip_asset_store.h"
#include "flutter/tonic/dart_debugger.h"
#include "flutter/tonic/dart_dependency_catcher.h"
#include "flutter/tonic/dart_io.h"
#include "flutter/tonic/dart_library_loader.h"
#include "flutter/tonic/dart_snapshot_loader.h"
#include "flutter/tonic/dart_state.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/files/eintr_wrapper.h"
......@@ -70,12 +67,6 @@ namespace blink {
const char kSnapshotAssetKey[] = "snapshot_blob.bin";
Dart_Handle DartLibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
return DartLibraryLoader::HandleLibraryTag(tag, library, url);
}
namespace {
static const char* kDartProfilingArgs[] = {
......@@ -192,7 +183,8 @@ Dart_Isolate ServiceIsolateCreateCallback(const char* script_uri,
FTL_CHECK(isolate) << error;
dart_state->SetIsolate(isolate);
FTL_CHECK(Dart_IsServiceIsolate(isolate));
FTL_CHECK(!LogIfError(Dart_SetLibraryTagHandler(DartLibraryTagHandler)));
FTL_CHECK(!LogIfError(
Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag)));
{
tonic::DartApiScope dart_api_scope;
DartIO::InitForIsolate();
......@@ -205,8 +197,8 @@ Dart_Isolate ServiceIsolateCreateCallback(const char* script_uri,
const intptr_t port = settings.observatory_port;
const bool disable_websocket_origin_check = false;
const bool service_isolate_booted = DartServiceIsolate::Startup(
ip, port, DartLibraryTagHandler, IsRunningPrecompiledCode(),
disable_websocket_origin_check, error);
ip, port, tonic::DartState::HandleLibraryTag,
IsRunningPrecompiledCode(), disable_websocket_origin_check, error);
FTL_CHECK(service_isolate_booted) << error;
}
......@@ -260,8 +252,8 @@ Dart_Isolate IsolateCreateCallback(const char* script_uri,
nullptr, dart_state, error);
FTL_CHECK(isolate) << error;
dart_state->SetIsolate(isolate);
FTL_CHECK(!LogIfError(Dart_SetLibraryTagHandler(DartLibraryTagHandler)));
FTL_CHECK(!LogIfError(
Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag)));
{
tonic::DartApiScope dart_api_scope;
......
......@@ -67,9 +67,6 @@ void SetServiceIsolateHook(ServiceIsolateHook hook);
void SetRegisterNativeServiceProtocolExtensionHook(
RegisterNativeServiceProtocolExtensionHook hook);
Dart_Handle DartLibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
} // namespace blink
#endif // SKY_ENGINE_CORE_SCRIPT_DART_INIT_H_
......@@ -18,8 +18,7 @@ std::unique_ptr<SkyView> SkyView::Create(SkyViewClient* client) {
return std::unique_ptr<SkyView>(new SkyView(client));
}
SkyView::SkyView(SkyViewClient* client)
: client_(client) {}
SkyView::SkyView(SkyViewClient* client) : client_(client) {}
SkyView::~SkyView() {}
......@@ -67,19 +66,6 @@ void SkyView::CreateView(const std::string& script_uri) {
GetWindow()->UpdateLocale(language_code_, country_code_);
}
void SkyView::RunFromLibrary(const std::string& name,
DartLibraryProvider* library_provider) {
dart_controller_->RunFromLibrary(name, library_provider);
}
void SkyView::RunFromPrecompiledSnapshot() {
dart_controller_->RunFromPrecompiledSnapshot();
}
void SkyView::RunFromSnapshot(mojo::ScopedDataPipeConsumerHandle snapshot) {
dart_controller_->RunFromSnapshot(snapshot.Pass());
}
void SkyView::BeginFrame(ftl::TimePoint frame_time) {
GetWindow()->BeginFrame(frame_time);
}
......@@ -123,5 +109,4 @@ Dart_Port SkyView::GetMainPort() {
return dart_controller_->dart_state()->main_port();
}
} // namespace blink
......@@ -43,11 +43,7 @@ class SkyView : public WindowClient, public IsolateClient {
void BeginFrame(ftl::TimePoint frame_time);
void CreateView(const std::string& script_uri);
void RunFromLibrary(const std::string& name,
DartLibraryProvider* library_provider);
void RunFromPrecompiledSnapshot();
void RunFromSnapshot(mojo::ScopedDataPipeConsumerHandle snapshot);
DartController* dart_controller() const { return dart_controller_.get(); }
void HandlePointerPacket(const pointer::PointerPacketPtr& packet);
......
......@@ -6,14 +6,16 @@
#include <unistd.h>
#include <utility>
#include "flutter/assets/directory_asset_bundle.h"
#include "flutter/assets/zip_asset_bundle.h"
#include "flutter/tonic/dart_library_provider_files.h"
#include "flutter/glue/movable_wrapper.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/files/path.h"
#include "mojo/public/cpp/application/connect.h"
#include "flutter/sky/engine/bindings/mojo_services.h"
#include "flutter/sky/engine/core/script/dart_controller.h"
#include "flutter/sky/engine/core/script/dart_init.h"
#include "flutter/sky/engine/core/script/ui_dart_state.h"
#include "flutter/sky/engine/public/platform/Platform.h"
......@@ -83,25 +85,20 @@ void Engine::BeginFrame(ftl::TimePoint frame_time) {
void Engine::RunFromSource(const std::string& main,
const std::string& packages,
const std::string& assets_directory) {
const std::string& bundle) {
TRACE_EVENT0("flutter", "Engine::RunFromSource");
// Assets.
ConfigureDirectoryAssetBundle(assets_directory);
// .packages.
std::string packages_path = packages;
if (packages_path.empty())
packages_path = FindPackagesPath(main);
DartLibraryProviderFiles* provider = new DartLibraryProviderFiles();
dart_library_provider_.reset(provider);
if (!packages_path.empty())
provider->LoadPackagesMap(packages_path);
RunFromLibrary(main);
if (!bundle.empty())
ConfigureDirectoryAssetBundle(bundle);
ConfigureView(main);
sky_view_->dart_controller()->RunFromSource(main, packages_path);
}
Dart_Port Engine::GetUIIsolateMainPort() {
if (!sky_view_) {
if (!sky_view_)
return ILLEGAL_PORT;
}
return sky_view_->GetMainPort();
}
......@@ -183,34 +180,24 @@ void Engine::OnPointerPacket(pointer::PointerPacketPtr packet) {
sky_view_->HandlePointerPacket(packet);
}
void Engine::RunFromLibrary(const std::string& name) {
TRACE_EVENT0("flutter", "Engine::RunFromLibrary");
sky_view_ = blink::SkyView::Create(this);
sky_view_->CreateView(name);
sky_view_->RunFromLibrary(name, dart_library_provider_.get());
sky_view_->SetViewportMetrics(viewport_metrics_);
sky_view_->SetLocale(language_code_, country_code_);
if (!initial_route_.empty())
sky_view_->PushRoute(initial_route_);
}
void Engine::RunFromSnapshotStream(
const std::string& script_uri,
mojo::ScopedDataPipeConsumerHandle snapshot) {
TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
sky_view_ = blink::SkyView::Create(this);
sky_view_->CreateView(script_uri);
sky_view_->RunFromSnapshot(snapshot.Pass());
sky_view_->SetViewportMetrics(viewport_metrics_);
sky_view_->SetLocale(language_code_, country_code_);
if (!initial_route_.empty())
sky_view_->PushRoute(initial_route_);
ConfigureView(script_uri);
snapshot_drainer_.reset(new glue::DrainDataPipeJob(
std::move(snapshot), [this](std::vector<char> snapshot) {
FTL_DCHECK(sky_view_);
FTL_DCHECK(sky_view_->dart_controller());
sky_view_->dart_controller()->RunFromSnapshot(
reinterpret_cast<uint8_t*>(snapshot.data()), snapshot.size());
}));
}
void Engine::ConfigureZipAssetBundle(const mojo::String& path) {
void Engine::ConfigureZipAssetBundle(const std::string& path) {
asset_store_ = ftl::MakeRefCounted<blink::ZipAssetStore>(
path.get(), ftl::RefPtr<ftl::TaskRunner>(
blink::Platform::current()->GetIOTaskRunner()));
path, ftl::RefPtr<ftl::TaskRunner>(
blink::Platform::current()->GetIOTaskRunner()));
new blink::ZipAssetBundle(mojo::GetProxy(&root_bundle_), asset_store_);
}
......@@ -221,43 +208,32 @@ void Engine::ConfigureDirectoryAssetBundle(const std::string& path) {
blink::Platform::current()->GetIOTaskRunner()));
}
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");
ConfigureZipAssetBundle(bundle_path);
void Engine::ConfigureView(const std::string& script_uri) {
snapshot_drainer_.reset();
sky_view_ = blink::SkyView::Create(this);
sky_view_->CreateView("http://localhost");
sky_view_->RunFromPrecompiledSnapshot();
sky_view_->CreateView(std::move(script_uri));
sky_view_->SetViewportMetrics(viewport_metrics_);
sky_view_->SetLocale(language_code_, country_code_);
if (!initial_route_.empty())
sky_view_->PushRoute(initial_route_);
}
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");
ConfigureZipAssetBundle(bundle_path.get());
ConfigureView("http://localhost");
sky_view_->dart_controller()->RunFromPrecompiledSnapshot();
}
void Engine::RunFromFile(const mojo::String& main,
const mojo::String& packages,
const mojo::String& bundle) {
TRACE_EVENT0("flutter", "Engine::RunFromFile");
std::string main_dart(main);
if (bundle.size() != 0) {
// The specification of an FLX bundle is optional.
ConfigureZipAssetBundle(bundle);
}
std::string packages_path = packages;
if (packages_path.empty())
packages_path = FindPackagesPath(main_dart);
DartLibraryProviderFiles* provider = new DartLibraryProviderFiles();
dart_library_provider_.reset(provider);
if (!packages_path.empty())
provider->LoadPackagesMap(packages_path);
RunFromLibrary(main_dart);
RunFromSource(main, packages, bundle);
}
void Engine::RunFromBundle(const mojo::String& script_uri,
const mojo::String& path) {
TRACE_EVENT0("flutter", "Engine::RunFromBundle");
ConfigureZipAssetBundle(path);
mojo::DataPipe pipe;
asset_store_->GetAsStream(blink::kSnapshotAssetKey,
......
......@@ -6,6 +6,13 @@
#define SKY_SHELL_UI_ENGINE_H_
#include "flutter/assets/zip_asset_store.h"
#include "flutter/glue/drain_data_pipe_job.h"
#include "flutter/services/engine/sky_engine.mojom.h"
#include "flutter/services/rasterizer/rasterizer.mojom.h"
#include "flutter/sky/engine/public/sky/sky_view_client.h"
#include "flutter/sky/engine/public/sky/sky_view.h"
#include "flutter/sky/shell/rasterizer.h"
#include "flutter/sky/shell/ui_delegate.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/weak_ptr.h"
#include "lib/ftl/tasks/task_runner.h"
......@@ -16,12 +23,6 @@
#include "mojo/public/cpp/system/handle.h"
#include "mojo/public/interfaces/application/service_provider.mojom.h"
#include "mojo/services/asset_bundle/interfaces/asset_bundle.mojom.h"
#include "flutter/sky/engine/public/sky/sky_view_client.h"
#include "flutter/sky/engine/public/sky/sky_view.h"
#include "flutter/services/engine/sky_engine.mojom.h"
#include "flutter/services/rasterizer/rasterizer.mojom.h"
#include "flutter/sky/shell/rasterizer.h"
#include "flutter/sky/shell/ui_delegate.h"
#include "third_party/skia/include/core/SkPicture.h"
namespace sky {
......@@ -51,7 +52,7 @@ class Engine : public UIDelegate,
void RunFromSource(const std::string& main,
const std::string& packages,
const std::string& assets_directory);
const std::string& bundle);
Dart_Port GetUIIsolateMainPort();
......@@ -91,7 +92,6 @@ class Engine : public UIDelegate,
void BindToServiceProvider(
mojo::InterfaceRequest<mojo::ServiceProvider> request);
void RunFromLibrary(const std::string& name);
void RunFromSnapshotStream(const std::string& script_uri,
mojo::ScopedDataPipeConsumerHandle snapshot);
......@@ -100,8 +100,9 @@ class Engine : public UIDelegate,
void StopAnimator();
void StartAnimatorIfPossible();
void ConfigureZipAssetBundle(const mojo::String& path);
void ConfigureZipAssetBundle(const std::string& path);
void ConfigureDirectoryAssetBundle(const std::string& path);
void ConfigureView(const std::string& script_uri);
Config config_;
std::unique_ptr<Animator> animator_;
......@@ -112,9 +113,10 @@ class Engine : public UIDelegate,
mojo::BindingSet<mojo::ServiceProvider> service_provider_bindings_;
mojo::asset_bundle::AssetBundlePtr root_bundle_;
std::unique_ptr<blink::DartLibraryProvider> dart_library_provider_;
std::unique_ptr<blink::SkyView> sky_view_;
std::unique_ptr<glue::DrainDataPipeJob> snapshot_drainer_;
std::string initial_route_;
ViewportMetricsPtr viewport_metrics_;
std::string language_code_;
......
......@@ -116,16 +116,7 @@ tonic::FileLoader& GetLoader() {
Dart_Handle HandleLibraryTag(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
FTL_CHECK(Dart_IsLibrary(library));
FTL_CHECK(Dart_IsString(url));
tonic::FileLoader& loader = GetLoader();
if (tag == Dart_kCanonicalizeUrl)
return loader.CanonicalizeURL(library, url);
if (tag == Dart_kImportTag)
return loader.Import(url);
if (tag == Dart_kSourceTag)
return loader.Source(library, url);
return Dart_NewApiError("Unknown library tag.");
return GetLoader().HandleLibraryTag(tag, library, url);
}
std::vector<char> CreateSnapshot() {
......
......@@ -6,31 +6,15 @@ source_set("tonic") {
sources = [
"dart_debugger.cc",
"dart_debugger.h",
"dart_dependency_catcher.cc",
"dart_dependency_catcher.h",
"dart_io.cc",
"dart_io.h",
"dart_isolate_reloader.cc",
"dart_isolate_reloader.h",
"dart_library_loader.cc",
"dart_library_loader.h",
"dart_library_provider.cc",
"dart_library_provider.h",
"dart_library_provider_files.cc",
"dart_library_provider_files.h",
"dart_snapshot_loader.cc",
"dart_snapshot_loader.h",
"dart_state.cc",
"dart_state.h",
]
deps = [
"//base",
"//dart/runtime/bin:embedded_dart_io",
"//flutter/glue",
"//lib/tonic/parsers",
"//mojo/data_pipe_utils",
"//mojo/public/cpp/system",
"//lib/ftl",
]
public_deps = [
......
// Copyright 2015 The Chromium 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/tonic/dart_dependency_catcher.h"
#include "flutter/tonic/dart_library_loader.h"
namespace blink {
DartDependencyCatcher::DartDependencyCatcher(DartLibraryLoader& loader)
: loader_(loader) {
loader_.set_dependency_catcher(this);
}
DartDependencyCatcher::~DartDependencyCatcher() {
loader_.set_dependency_catcher(nullptr);
}
void DartDependencyCatcher::AddDependency(DartDependency* dependency) {
dependencies_.insert(dependency);
}
} // namespace blink
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_TONIC_DART_DEPENDENCY_CATCHER_H_
#define FLUTTER_TONIC_DART_DEPENDENCY_CATCHER_H_
#include <unordered_set>
#include "lib/ftl/macros.h"
namespace blink {
class DartLibraryLoader;
// A base class to represent a dependency.
class DartDependency {};
// To catch the dependencies for a library, put a DartDependencyCatcher on the
// stack during the call to Dart_LoadLibrary.
class DartDependencyCatcher {
public:
explicit DartDependencyCatcher(DartLibraryLoader& loader);
~DartDependencyCatcher();
void AddDependency(DartDependency* dependency);
const std::unordered_set<DartDependency*>& dependencies() const {
return dependencies_;
}
private:
DartLibraryLoader& loader_;
std::unordered_set<DartDependency*> dependencies_;
FTL_DISALLOW_COPY_AND_ASSIGN(DartDependencyCatcher);
};
} // namespace blink
#endif // FLUTTER_TONIC_DART_DEPENDENCY_CATCHER_H_
// Copyright 2016 The Chromium 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/tonic/dart_isolate_reloader.h"
#include <utility>
#include "flutter/tonic/dart_dependency_catcher.h"
#include "flutter/tonic/dart_library_loader.h"
#include "flutter/tonic/dart_library_provider.h"
#include "flutter/tonic/dart_state.h"
#include "flutter/glue/drain_data_pipe_job.h"
#include "flutter/glue/thread.h"
#include "lib/ftl/logging.h"
#include "lib/ftl/synchronization/monitor.h"
#include "lib/tonic/converter/dart_converter.h"
#include "lib/tonic/logging/dart_error.h"
#include "lib/tonic/scopes/dart_api_scope.h"
#include "lib/tonic/scopes/dart_isolate_scope.h"
using tonic::ToDart;
using tonic::StdStringToDart;
using tonic::StdStringFromDart;
namespace blink {
// As each source file is loaded, a LoadResult is queued to be processed on the
// isolate's thread. A LoadResult contains the payload or an error message.
class DartIsolateReloader::LoadResult {
public:
// Successful load result.
LoadResult(intptr_t tag,
const std::string& url,
const std::string& library_url,
const std::string& resolved_url,
std::vector<char> payload)
: success_(true),
tag_(tag),
url_(url),
library_url_(library_url),
resolved_url_(resolved_url),
payload_(std::move(payload)) {
FTL_DCHECK(success());
}
// Error load result.
LoadResult(intptr_t tag,
const std::string& url,
const std::string& library_url,
const std::string& error)
: success_(false),
tag_(tag),
url_(url),
library_url_(library_url),
error_(error) {}
bool success() const { return success_; }
Dart_Handle Finish() {
if (!success()) {
return StdStringToDart(error_);
}
Dart_Handle uri = StdStringToDart(url_);
Dart_Handle resolved_uri = Dart_Null();
if (!resolved_url_.empty()) {
resolved_uri = StdStringToDart(resolved_url_);
}
Dart_Handle library = Dart_Null();
if (!library_url_.empty()) {
library = Dart_LookupLibrary(StdStringToDart(library_url_));
}
Dart_Handle source = Dart_NewStringFromUTF8(
reinterpret_cast<const uint8_t*>(payload_.data()), payload_.size());
Dart_Handle result = Dart_Null();
switch (tag_) {
case Dart_kImportTag:
result = Dart_LoadLibrary(uri, resolved_uri, source, 0, 0);
break;
case Dart_kSourceTag:
result = Dart_LoadSource(library, uri, resolved_uri, source, 0, 0);
break;
case Dart_kScriptTag:
result = Dart_LoadScript(uri, resolved_uri, source, 0, 0);
break;
}
if (Dart_IsError(result)) {
return result;
}
return Dart_Null();
}
private:
bool success_;
intptr_t tag_;
std::string url_;
std::string library_url_;
std::string resolved_url_;
std::string error_;
std::vector<char> payload_;
};
DartIsolateReloader::DartIsolateReloader(DartLibraryProvider* library_provider)
: thread_("DartIsolateReloader"),
library_provider_(library_provider),
load_error_(Dart_Null()),
pending_requests_(0) {
FTL_CHECK(thread_.Start());
}
DartIsolateReloader::~DartIsolateReloader() {}
void DartIsolateReloader::SendRequest(Dart_LibraryTag tag,
Dart_Handle url,
Dart_Handle library_url) {
ftl::RefPtr<ftl::TaskRunner> runner = thread_.task_runner();
std::string url_string = StdStringFromDart(url);
std::string library_url_string = StdStringFromDart(library_url);
ftl::MonitorLocker locker(&monitor_);
// Post a task to the worker thread. This task will request the I/O and
// post a LoadResult to be processed once complete.
runner->PostTask([this, tag, url_string, library_url_string]() {
RequestTask(library_provider_, this, static_cast<intptr_t>(tag), url_string,
library_url_string);
});
pending_requests_++;
}
void DartIsolateReloader::PostResult(std::unique_ptr<LoadResult> load_result) {
ftl::MonitorLocker locker(&monitor_);
pending_requests_--;
load_results_.push(std::move(load_result));
locker.Signal();
}
// As each source file is requested, a LoadRequest is queued to be processed on
// worker thread.
class DartIsolateReloader::LoadRequest {
public:
LoadRequest(DartLibraryProvider* library_provider,
DartIsolateReloader* isolate_reloader,
intptr_t tag,
const std::string& url,
const std::string& library_url)
: isolate_reloader_(isolate_reloader),
tag_(tag),
url_(url),
library_url_(library_url) {
auto stream = library_provider->GetLibraryAsStream(url_);
OnStreamAvailable(std::move(stream.handle), std::move(stream.resolved_url));
}
protected:
void OnStreamAvailable(mojo::ScopedDataPipeConsumerHandle handle,
std::string resolved_url) {
if (!handle.is_valid()) {
std::unique_ptr<DartIsolateReloader::LoadResult> result(
new DartIsolateReloader::LoadResult(
tag_, url_, library_url_,
"File " + url_ + " could not be read."));
FTL_LOG(ERROR) << "Load failed for " << url_;
isolate_reloader_->PostResult(std::move(result));
// We are finished with this request.
delete this;
return;
}
resolved_url_ = std::move(resolved_url);
drainer_.reset(new glue::DrainDataPipeJob(
std::move(handle), [this](std::vector<char> buffer) {
std::unique_ptr<DartIsolateReloader::LoadResult> result(
new DartIsolateReloader::LoadResult(
tag_, url_, library_url_, resolved_url_, std::move(buffer)));
isolate_reloader_->PostResult(std::move(result));
// We are finished with this request.
delete this;
}));
}
private:
DartIsolateReloader* isolate_reloader_;
intptr_t tag_;
std::string url_;
std::string library_url_;
std::string resolved_url_;
std::vector<uint8_t> buffer_;
std::unique_ptr<glue::DrainDataPipeJob> drainer_;
};
void DartIsolateReloader::RequestTask(DartLibraryProvider* library_provider,
DartIsolateReloader* isolate_reloader,
intptr_t tag,
const std::string& url,
const std::string& library_url) {
FTL_DCHECK(isolate_reloader);
FTL_DCHECK(library_provider);
FTL_DCHECK(tag > 0);
// Construct a new LoadRequest. The pointer is dropped here because
// the request deletes itself on success and failure.
new LoadRequest(library_provider, isolate_reloader, tag, url, library_url);
}
void DartIsolateReloader::HandleLoadResultLocked(LoadResult* load_result) {
if (load_error_ != Dart_Null()) {
// Already have a sticky error. Just drop this result.
return;
}
// Drop the lock temporarily around the call to Finish because it may
// trigger a recursive call into the tag handler.
monitor_.Exit();
Dart_Handle error_or_null = load_result->Finish();
monitor_.Enter();
if (!Dart_IsNull(error_or_null)) {
// Set sticky error.
load_error_ = error_or_null;
}
}
void DartIsolateReloader::ProcessResultQueueLocked() {
while (load_results_.size() > 0) {
// Grab the first load result.
std::unique_ptr<LoadResult> result = std::move(load_results_.front());
load_results_.pop();
HandleLoadResultLocked(result.get());
}
}
bool DartIsolateReloader::IsCompleteLocked() {
return (pending_requests_ == 0) && load_results_.empty();
}
bool DartIsolateReloader::BlockUntilComplete() {
ftl::MonitorLocker locker(&monitor_);
while (true) {
ProcessResultQueueLocked();
if (IsCompleteLocked()) {
break;
}
// Wait to be notified about new I/O results.
locker.Wait();
}
return !Dart_IsNull(load_error_);
}
Dart_Handle DartIsolateReloader::HandleLibraryTag(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
if (tag == Dart_kCanonicalizeUrl) {
// Pass through to actual tag handler.
return DartLibraryLoader::HandleLibraryTag(tag, library, url);
}
DartState* dart_state = DartState::Current();
FTL_DCHECK(dart_state);
DartIsolateReloader* isolate_reloader = dart_state->isolate_reloader();
// The first call into the tag handler ends up blocking the calling thread
// until the entire reload has completed. All other calls into the
// tag handler schedule requests and return immediately.
const bool blocking_call = (tag == Dart_kScriptTag);
if (!isolate_reloader) {
// The first call into this tag handler must be for the script.
FTL_DCHECK(tag == Dart_kScriptTag);
// Associate the reloader with the isolate. The reloader is owned
// by the dart_state.
dart_state->set_isolate_reloader(
std::unique_ptr<DartIsolateReloader>(new DartIsolateReloader(
dart_state->library_loader().library_provider())));
// Get a pointer to the reloader.
isolate_reloader = dart_state->isolate_reloader();
// Switch the tag handler.
Dart_SetLibraryTagHandler(DartIsolateReloader::HandleLibraryTag);
} else {
// We should not see another request for the script.
FTL_DCHECK(tag != Dart_kScriptTag);
}
// Issue I/O request.
isolate_reloader->SendRequest(tag, url, (library != Dart_Null())
? Dart_LibraryUrl(library)
: Dart_Null());
if (blocking_call) {
// Block and process LoadResults until the load is complete.
const bool load_error = isolate_reloader->BlockUntilComplete();
// Grab the (possibly null) load error from the reloader before its gone.
Dart_Handle result = isolate_reloader->load_error_;
// The reloader will be deleted once we call set_isolate_reloader below.
isolate_reloader = nullptr;
// Disassociate reloader from the isolate, this causes it to be deleted.
dart_state->set_isolate_reloader(nullptr);
Dart_SetLibraryTagHandler(DartLibraryLoader::HandleLibraryTag);
if (load_error) {
// If we hit an error, return the load error.
return result;
} else {
// Finalize loading.
result = Dart_FinalizeLoading(true);
if (Dart_IsError(result)) {
// If we hit an error, return the load error.
return result;
}
}
}
return Dart_Null();
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_TONIC_DART_ISOLATE_RELOADER_H_
#define FLUTTER_TONIC_DART_ISOLATE_RELOADER_H_
#include <string>
#include <vector>
#include <queue>
#include "dart/runtime/include/dart_api.h"
#include "flutter/glue/thread.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/synchronization/monitor.h"
namespace blink {
class DartLibraryProvider;
// Reloading an isolate must be an atomic operation, meaning, no other tasks
// can run while reloading. A nested run loop is not sufficient because other
// tasks that invoke Dart code can be run. When |HandleLibraryTag| is invoked
// the calling thread will be blocked until the load has fully completed. To
// avoid relying on the message loop we use our own queue and notification
// mechanism.
class DartIsolateReloader {
public:
// The |DartLibraryProvider| used to load the library sources.
DartIsolateReloader(DartLibraryProvider* library_provider);
~DartIsolateReloader();
static Dart_Handle HandleLibraryTag(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
private:
class LoadRequest;
class LoadResult;
void SendRequest(Dart_LibraryTag tag,
Dart_Handle url,
Dart_Handle library_url);
void PostResult(std::unique_ptr<LoadResult> load_result);
static void RequestTask(DartLibraryProvider* library_provider,
DartIsolateReloader* isolate_reloader,
intptr_t tag,
const std::string& url,
const std::string& library_url);
void HandleLoadResultLocked(LoadResult* load_result);
void ProcessResultQueueLocked();
bool IsCompleteLocked();
bool BlockUntilComplete();
glue::Thread thread_;
DartLibraryProvider* library_provider_;
ftl::Monitor monitor_;
// The monitor is used to protect the following fields:
Dart_Handle load_error_;
std::queue<std::unique_ptr<LoadResult>> load_results_;
intptr_t pending_requests_;
FTL_DISALLOW_COPY_AND_ASSIGN(DartIsolateReloader);
};
} // namespace blink
#endif // FLUTTER_TONIC_DART_ISOLATE_RELOADER_H_
// Copyright 2015 The Chromium 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/tonic/dart_library_loader.h"
#include <utility>
#include "flutter/tonic/dart_dependency_catcher.h"
#include "flutter/tonic/dart_isolate_reloader.h"
#include "flutter/tonic/dart_library_provider.h"
#include "flutter/tonic/dart_state.h"
#include "flutter/glue/drain_data_pipe_job.h"
#include "flutter/glue/trace_event.h"
#include "lib/tonic/converter/dart_converter.h"
#include "lib/tonic/dart_persistent_value.h"
#include "lib/tonic/logging/dart_error.h"
#include "lib/tonic/scopes/dart_api_scope.h"
#include "lib/tonic/scopes/dart_isolate_scope.h"
using tonic::StdStringFromDart;
using tonic::ToDart;
namespace blink {
namespace {
// Helper to erase a T* from a container of std::unique_ptr<T>s.
template <typename T, typename C>
void EraseUniquePtr(C& container, T* item) {
std::unique_ptr<T> key = std::unique_ptr<T>(item);
container.erase(key);
key.release();
}
} // namespace
// A DartLibraryLoader::Job represents a network load. It fetches data from the
// network and buffers the data in std::vector. To cancel the job, delete this
// object.
class DartLibraryLoader::Job : public DartDependency {
public:
Job(DartLibraryLoader* loader, const std::string& name)
: loader_(loader), name_(name) {
auto stream = loader->library_provider()->GetLibraryAsStream(name);
OnStreamAvailable(std::move(stream.handle), std::move(stream.resolved_url));
}
const std::string& name() const { return name_; }
const std::string& resolved_url() const { return resolved_url_; }
protected:
DartLibraryLoader* loader_;
virtual void OnDataAvailable(std::vector<char> buffer) = 0;
private:
void OnStreamAvailable(mojo::ScopedDataPipeConsumerHandle pipe,
const std::string& resolved_url) {
if (!pipe.is_valid()) {
loader_->DidFailJob(this);
return;
}
resolved_url_ = resolved_url;
drainer_.reset(new glue::DrainDataPipeJob(
std::move(pipe), [this](std::vector<char> buffer) {
OnDataAvailable(std::move(buffer));
}));
}
std::string name_;
std::string resolved_url_;
std::unique_ptr<glue::DrainDataPipeJob> drainer_;
};
class DartLibraryLoader::ImportJob : public Job {
public:
ImportJob(DartLibraryLoader* loader,
const std::string& name,
bool should_load_as_script)
: Job(loader, name), should_load_as_script_(should_load_as_script) {
TRACE_EVENT_ASYNC_BEGIN1("flutter", "DartLibraryLoader::ImportJob", this,
"url", name);
}
bool should_load_as_script() const { return should_load_as_script_; }
private:
void OnDataAvailable(std::vector<char> buffer) override {
TRACE_EVENT_ASYNC_END0("flutter", "DartLibraryLoader::ImportJob", this);
loader_->DidCompleteImportJob(this, std::move(buffer));
}
bool should_load_as_script_;
};
class DartLibraryLoader::SourceJob : public Job {
public:
SourceJob(DartLibraryLoader* loader,
const std::string& name,
Dart_Handle library)
: Job(loader, name), library_(loader->dart_state(), library) {
TRACE_EVENT_ASYNC_BEGIN1("flutter", "DartLibraryLoader::SourceJob", this,
"url", name);
}
Dart_PersistentHandle library() const { return library_.value(); }
private:
void OnDataAvailable(std::vector<char> buffer) override {
TRACE_EVENT_ASYNC_END0("flutter", "DartLibraryLoader::SourceJob", this);
loader_->DidCompleteSourceJob(this, std::move(buffer));
}
tonic::DartPersistentValue library_;
};
// A DependencyWatcher represents a request to watch for when a given set of
// dependencies (either libraries or parts of libraries) have finished loading.
// When the dependencies are satisfied (including transitive dependencies), then
// the |callback| will be invoked.
class DartLibraryLoader::DependencyWatcher {
public:
DependencyWatcher(const std::unordered_set<DartDependency*>& dependencies,
const ftl::Closure& callback)
: dependencies_(dependencies), callback_(callback) {
FTL_DCHECK(!dependencies_.empty());
}
bool DidResolveDependency(
DartDependency* resolved_dependency,
const std::unordered_set<DartDependency*>& new_dependencies) {
const auto& it = dependencies_.find(resolved_dependency);
if (it == dependencies_.end())
return false;
dependencies_.erase(it);
for (const auto& dependency : new_dependencies)
dependencies_.insert(dependency);
return dependencies_.empty();
}
const ftl::Closure& callback() const { return callback_; }
private:
std::unordered_set<DartDependency*> dependencies_;
ftl::Closure callback_;
};
// A WatcherSignaler is responsible for signaling DependencyWatchers when their
// dependencies resolve and for calling the DependencyWatcher's callback. We use
// a separate object of this task because we want to carefully manage when we
// call the callbacks, which can call into us again reentrantly.
//
// WatcherSignaler is designed to be placed on the stack as a RAII. After its
// destructor runs, we might have executed aribitrary script.
class DartLibraryLoader::WatcherSignaler {
public:
WatcherSignaler(DartLibraryLoader& loader,
DartDependency* resolved_dependency)
: loader_(loader),
catcher_(new DartDependencyCatcher(loader)),
resolved_dependency_(resolved_dependency) {}
~WatcherSignaler() {
std::vector<DependencyWatcher*> completed_watchers;
for (const auto& watcher : loader_.dependency_watchers_) {
if (watcher->DidResolveDependency(resolved_dependency_,
catcher_->dependencies()))
completed_watchers.push_back(watcher.get());
}
// Notice that we remove the dependency catcher and extract all the
// callbacks before running any of them. We don't want to be re-entered
// below the callbacks and end up in an inconsistent state.
catcher_ = nullptr;
std::vector<ftl::Closure> callbacks;
for (const auto& watcher : completed_watchers) {
callbacks.push_back(watcher->callback());
EraseUniquePtr(loader_.dependency_watchers_, watcher);
}
// Finally, run all the callbacks while touching only data on the stack.
for (const auto& callback : callbacks)
callback();
}
private:
DartLibraryLoader& loader_;
std::unique_ptr<DartDependencyCatcher> catcher_;
DartDependency* resolved_dependency_;
};
DartLibraryLoader::DartLibraryLoader(DartState* dart_state)
: dart_state_(dart_state),
library_provider_(nullptr),
dependency_catcher_(nullptr) {}
DartLibraryLoader::~DartLibraryLoader() {}
Dart_Handle DartLibraryLoader::HandleLibraryTag(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
FTL_DCHECK(Dart_IsLibrary(library) || Dart_IsNull(library));
FTL_DCHECK(Dart_IsString(url));
if (tag == Dart_kCanonicalizeUrl) {
return DartState::Current()->library_loader().CanonicalizeURL(library, url);
}
if (tag == Dart_kImportTag) {
return DartState::Current()->library_loader().Import(library, url);
}
if (tag == Dart_kSourceTag) {
return DartState::Current()->library_loader().Source(library, url);
}
if (tag == Dart_kScriptTag) {
return DartIsolateReloader::HandleLibraryTag(tag, library, url);
}
FTL_NOTREACHED();
return Dart_NewApiError("Unknown library tag.");
}
void DartLibraryLoader::WaitForDependencies(
const std::unordered_set<DartDependency*>& dependencies,
const ftl::Closure& callback) {
if (dependencies.empty())
return callback();
dependency_watchers_.insert(std::unique_ptr<DependencyWatcher>(
new DependencyWatcher(dependencies, callback)));
}
void DartLibraryLoader::LoadLibrary(const std::string& name) {
const auto& result = pending_libraries_.insert(std::make_pair(name, nullptr));
if (result.second) {
// New entry.
std::unique_ptr<Job> job =
std::unique_ptr<Job>(new ImportJob(this, name, false));
result.first->second = job.get();
jobs_.insert(std::move(job));
}
if (dependency_catcher_)
dependency_catcher_->AddDependency(result.first->second);
}
void DartLibraryLoader::LoadScript(const std::string& name) {
const auto& result = pending_libraries_.insert(std::make_pair(name, nullptr));
if (result.second) {
// New entry.
std::unique_ptr<Job> job =
std::unique_ptr<Job>(new ImportJob(this, name, true));
result.first->second = job.get();
jobs_.insert(std::move(job));
}
if (dependency_catcher_)
dependency_catcher_->AddDependency(result.first->second);
}
Dart_Handle DartLibraryLoader::Import(Dart_Handle library, Dart_Handle url) {
LoadLibrary(StdStringFromDart(url));
return Dart_True();
}
Dart_Handle DartLibraryLoader::Source(Dart_Handle library, Dart_Handle url) {
std::unique_ptr<Job> job = std::unique_ptr<Job>(
new SourceJob(this, StdStringFromDart(url), library));
if (dependency_catcher_)
dependency_catcher_->AddDependency(job.get());
jobs_.insert(std::move(job));
return Dart_True();
}
Dart_Handle DartLibraryLoader::CanonicalizeURL(Dart_Handle library,
Dart_Handle url) {
return library_provider_->CanonicalizeURL(library, url);
}
void DartLibraryLoader::DidCompleteImportJob(ImportJob* job,
std::vector<char> buffer) {
tonic::DartIsolateScope scope(dart_state_->isolate());
tonic::DartApiScope api_scope;
WatcherSignaler watcher_signaler(*this, job);
Dart_Handle result;
Dart_Handle source = Dart_NewStringFromUTF8(
reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
if (job->should_load_as_script()) {
result = Dart_LoadScript(ToDart(job->name()), ToDart(job->resolved_url()),
source, 0, 0);
} else {
result = Dart_LoadLibrary(ToDart(job->name()), ToDart(job->resolved_url()),
source, 0, 0);
}
if (Dart_IsError(result)) {
FTL_LOG(ERROR) << "Error Loading " << job->name() << " "
<< Dart_GetError(result);
}
pending_libraries_.erase(job->name());
EraseUniquePtr<Job>(jobs_, job);
}
void DartLibraryLoader::DidCompleteSourceJob(SourceJob* job,
std::vector<char> buffer) {
tonic::DartIsolateScope scope(dart_state_->isolate());
tonic::DartApiScope api_scope;
WatcherSignaler watcher_signaler(*this, job);
Dart_Handle source = Dart_NewStringFromUTF8(
reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
Dart_Handle result = Dart_LoadSource(
Dart_HandleFromPersistent(job->library()), ToDart(job->name()),
ToDart(job->resolved_url()), source, 0, 0);
if (Dart_IsError(result)) {
FTL_LOG(ERROR) << "Error Loading " << job->name() << " "
<< Dart_GetError(result);
}
EraseUniquePtr<Job>(jobs_, job);
}
void DartLibraryLoader::DidFailJob(Job* job) {
tonic::DartIsolateScope scope(dart_state_->isolate());
tonic::DartApiScope api_scope;
WatcherSignaler watcher_signaler(*this, job);
FTL_LOG(ERROR) << "Library Load failed: " << job->name();
// TODO(eseidel): Call Dart_LibraryHandleError in the SourceJob case?
EraseUniquePtr<Job>(jobs_, job);
}
} // namespace blink
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_TONIC_DART_LIBRARY_LOADER_H_
#define FLUTTER_TONIC_DART_LIBRARY_LOADER_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "dart/runtime/include/dart_api.h"
#include "lib/ftl/functional/closure.h"
#include "lib/ftl/logging.h"
#include "lib/ftl/macros.h"
namespace blink {
class DartDependency;
class DartDependencyCatcher;
class DartLibraryProvider;
class DartState;
// TODO(abarth): This class seems more complicated than it needs to be. Is
// there some way of simplifying this system? For example, we have a bunch
// of inner classes that could potentially be factored out in some other way.
class DartLibraryLoader {
public:
explicit DartLibraryLoader(DartState* dart_state);
~DartLibraryLoader();
// TODO(dart): This can be called both on the main thread from application
// isolates or from the handle watcher isolate thread.
static Dart_Handle HandleLibraryTag(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
void LoadLibrary(const std::string& name);
void LoadScript(const std::string& name);
void WaitForDependencies(
const std::unordered_set<DartDependency*>& dependencies,
const ftl::Closure& callback);
void set_dependency_catcher(DartDependencyCatcher* dependency_catcher) {
FTL_DCHECK(!dependency_catcher_ || !dependency_catcher);
dependency_catcher_ = dependency_catcher;
}
DartState* dart_state() const { return dart_state_; }
DartLibraryProvider* library_provider() const { return library_provider_; }
// The |DartLibraryProvider| must outlive the |DartLibraryLoader|.
void set_library_provider(DartLibraryProvider* library_provider) {
library_provider_ = library_provider;
}
private:
class Job;
class ImportJob;
class SourceJob;
class DependencyWatcher;
class WatcherSignaler;
Dart_Handle Import(Dart_Handle library, Dart_Handle url);
Dart_Handle Source(Dart_Handle library, Dart_Handle url);
Dart_Handle CanonicalizeURL(Dart_Handle library, Dart_Handle url);
void DidCompleteImportJob(ImportJob* job, std::vector<char> buffer);
void DidCompleteSourceJob(SourceJob* job, std::vector<char> buffer);
void DidFailJob(Job* job);
DartState* dart_state_;
DartLibraryProvider* library_provider_;
std::unordered_map<std::string, Job*> pending_libraries_;
std::unordered_set<std::unique_ptr<Job>> jobs_;
std::unordered_set<std::unique_ptr<DependencyWatcher>> dependency_watchers_;
DartDependencyCatcher* dependency_catcher_;
FTL_DISALLOW_COPY_AND_ASSIGN(DartLibraryLoader);
};
} // namespace blink
#endif // FLUTTER_TONIC_DART_LIBRARY_LOADER_H_
// Copyright 2015 The Chromium 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/tonic/dart_library_provider.h"
namespace blink {
DartLibraryProvider::~DartLibraryProvider() {
}
} // namespace blink
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_TONIC_DART_LIBRARY_PROVIDER_H_
#define FLUTTER_TONIC_DART_LIBRARY_PROVIDER_H_
#include <functional>
#include <string>
#include "dart/runtime/include/dart_api.h"
#include "mojo/public/cpp/system/data_pipe.h"
namespace blink {
struct DartLibraryStream {
mojo::ScopedDataPipeConsumerHandle handle;
std::string resolved_url;
};
class DartLibraryProvider {
public:
virtual DartLibraryStream GetLibraryAsStream(const std::string& name) = 0;
virtual Dart_Handle CanonicalizeURL(Dart_Handle library, Dart_Handle url) = 0;
virtual ~DartLibraryProvider();
};
} // namespace blink
#endif // FLUTTER_TONIC_DART_LIBRARY_PROVIDER_H_
// Copyright 2015 The Chromium 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/tonic/dart_library_provider_files.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "base/threading/worker_pool.h"
#include "lib/tonic/converter/dart_converter.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
namespace sky {
namespace shell {
namespace {
void CopyComplete(base::FilePath file, std::string uri, bool success) {
if (!success)
LOG(FATAL) << "Failed to load " << file.AsUTF8Unsafe() << " (" << uri
<< ")";
}
// Extract the scheme prefix ('package:' or 'file:' from )
static std::string ExtractSchemePrefix(std::string url) {
if (base::StartsWithASCII(url, "package:", true)) {
return "package:";
} else if (base::StartsWithASCII(url, "file:", true)) {
return "file:";
}
return "";
}
// Extract the path from a package: or file: url.
static std::string ExtractPath(std::string url) {
if (base::StartsWithASCII(url, "package:", true)) {
base::ReplaceFirstSubstringAfterOffset(&url, 0, "package:", "");
} else if (base::StartsWithASCII(url, "file:", true)) {
base::ReplaceFirstSubstringAfterOffset(&url, 0, "file:", "");
}
return url;
}
base::FilePath SimplifyPath(const base::FilePath& path) {
std::vector<base::FilePath::StringType> components;
path.GetComponents(&components);
auto it = components.begin();
base::FilePath result(*it++);
for (; it != components.end(); it++) {
auto& component = *it;
if (component == base::FilePath::kCurrentDirectory)
continue;
if (component == base::FilePath::kParentDirectory)
result = result.DirName();
else
result = result.Append(component);
}
return result;
}
} // namespace
DartLibraryProviderFiles::DartLibraryProviderFiles() {}
DartLibraryProviderFiles::~DartLibraryProviderFiles() {}
void DartLibraryProviderFiles::LoadPackagesMap(const std::string& packages) {
packages_ = base::FilePath(packages);
std::string packages_source;
if (!base::ReadFileToString(base::MakeAbsoluteFilePath(packages_),
&packages_source)) {
LOG(ERROR) << "error: Unable to load .packages file '"
<< packages_.AsUTF8Unsafe() << "'.";
exit(1);
}
std::string error;
if (!packages_map_.Parse(packages_source, &error)) {
LOG(ERROR) << "error: Unable to parse .packages file '"
<< packages_.AsUTF8Unsafe() << "'.\n"
<< error;
exit(1);
}
}
blink::DartLibraryStream DartLibraryProviderFiles::GetLibraryAsStream(
const std::string& name) {
mojo::DataPipe pipe;
base::FilePath path = GetFilePathForURL(name);
base::FilePath source = base::MakeAbsoluteFilePath(path);
blink::DartLibraryStream result;
result.handle = std::move(pipe.consumer_handle);
result.resolved_url = "file://" + source.value();
scoped_refptr<base::TaskRunner> runner =
base::WorkerPool::GetTaskRunner(true);
mojo::common::CopyFromFile(source, pipe.producer_handle.Pass(), 0,
runner.get(),
base::Bind(&CopyComplete, source, name));
return result;
}
Dart_Handle DartLibraryProviderFiles::CanonicalizeURL(Dart_Handle library,
Dart_Handle url) {
std::string string = tonic::StdStringFromDart(url);
if (base::StartsWithASCII(string, "dart:", true))
return url;
if (base::StartsWithASCII(string, "package:", true))
return url;
if (base::StartsWithASCII(string, "file:", true)) {
base::ReplaceFirstSubstringAfterOffset(&string, 0, "file:", "");
return tonic::StdStringToDart(string);
;
}
std::string library_url = tonic::StdStringFromDart(Dart_LibraryUrl(library));
std::string prefix = ExtractSchemePrefix(library_url);
std::string path = ExtractPath(library_url);
base::FilePath base_path(path);
base::FilePath resolved_path = base_path.DirName().Append(string);
base::FilePath normalized_path = SimplifyPath(resolved_path);
return tonic::StdStringToDart(prefix + normalized_path.AsUTF8Unsafe());
}
base::FilePath DartLibraryProviderFiles::GetFilePathForURL(std::string url) {
if (base::StartsWithASCII(url, "package:", true))
return GetFilePathForPackageURL(url);
if (base::StartsWithASCII(url, "file:", true))
return GetFilePathForFileURL(url);
return base::FilePath(url);
}
base::FilePath DartLibraryProviderFiles::GetFilePathForPackageURL(
std::string url) {
DCHECK(base::StartsWithASCII(url, "package:", true));
base::ReplaceFirstSubstringAfterOffset(&url, 0, "package:", "");
size_t slash = url.find('/');
if (slash == std::string::npos)
return base::FilePath();
std::string package = url.substr(0, slash);
std::string library_path = url.substr(slash + 1);
std::string package_path = packages_map_.Resolve(package);
if (package_path.empty())
return base::FilePath();
if (base::StartsWithASCII(package_path, "file://", true)) {
base::ReplaceFirstSubstringAfterOffset(&package_path, 0, "file://", "");
return base::FilePath(package_path + library_path);
}
return packages_.DirName().Append(package_path).Append(library_path);
}
base::FilePath DartLibraryProviderFiles::GetFilePathForFileURL(
std::string url) {
DCHECK(base::StartsWithASCII(url, "file://", true));
base::ReplaceFirstSubstringAfterOffset(&url, 0, "file://", "");
return base::FilePath(url);
}
} // namespace shell
} // namespace sky
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SKY_SHELL_DART_DART_LIBRARY_PROVIDER_FILES_H_
#define SKY_SHELL_DART_DART_LIBRARY_PROVIDER_FILES_H_
#include "base/files/file_path.h"
#include "flutter/tonic/dart_library_provider.h"
#include "lib/ftl/macros.h"
#include "lib/tonic/parsers/packages_map.h"
namespace sky {
namespace shell {
class DartLibraryProviderFiles : public blink::DartLibraryProvider {
public:
DartLibraryProviderFiles();
~DartLibraryProviderFiles() override;
void LoadPackagesMap(const std::string& packages);
protected:
// |DartLibraryProvider| implementation:
blink::DartLibraryStream GetLibraryAsStream(const std::string& name) override;
Dart_Handle CanonicalizeURL(Dart_Handle library, Dart_Handle url) override;
private:
base::FilePath GetFilePathForURL(std::string url);
base::FilePath GetFilePathForPackageURL(std::string url);
base::FilePath GetFilePathForFileURL(std::string url);
base::FilePath packages_;
tonic::PackagesMap packages_map_;
FTL_DISALLOW_COPY_AND_ASSIGN(DartLibraryProviderFiles);
};
} // namespace shell
} // namespace sky
#endif // SKY_SHELL_DART_DART_LIBRARY_PROVIDER_FILES_H_
// Copyright 2015 The Chromium 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/tonic/dart_snapshot_loader.h"
#include <utility>
#include "flutter/tonic/dart_state.h"
#include "flutter/glue/trace_event.h"
#include "lib/tonic/converter/dart_converter.h"
#include "lib/tonic/logging/dart_error.h"
#include "lib/tonic/scopes/dart_api_scope.h"
#include "lib/tonic/scopes/dart_isolate_scope.h"
using tonic::LogIfError;
namespace blink {
DartSnapshotLoader::DartSnapshotLoader(tonic::DartState* dart_state)
: dart_state_(dart_state->GetWeakPtr()) {}
DartSnapshotLoader::~DartSnapshotLoader() {}
void DartSnapshotLoader::LoadSnapshot(mojo::ScopedDataPipeConsumerHandle pipe,
const ftl::Closure& callback) {
TRACE_EVENT_ASYNC_BEGIN0("flutter", "DartSnapshotLoader::LoadSnapshot", this);
drainer_.reset(new glue::DrainDataPipeJob(
std::move(pipe), [this, callback](std::vector<char> buffer) {
TRACE_EVENT_ASYNC_END0("flutter", "DartSnapshotLoader::LoadSnapshot",
this);
// TODO(abarth): Should we check dart_state_ for null?
{
tonic::DartIsolateScope scope(dart_state_->isolate());
tonic::DartApiScope api_scope;
LogIfError(Dart_LoadScriptFromSnapshot(
reinterpret_cast<uint8_t*>(buffer.data()), buffer.size()));
}
callback();
}));
}
} // namespace blink
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_TONIC_DART_SNAPSHOT_LOADER_H_
#define FLUTTER_TONIC_DART_SNAPSHOT_LOADER_H_
#include <vector>
#include "dart/runtime/include/dart_api.h"
#include "flutter/glue/drain_data_pipe_job.h"
#include "lib/ftl/functional/closure.h"
#include "lib/ftl/macros.h"
#include "lib/tonic/dart_state.h"
namespace blink {
class DartSnapshotLoader {
public:
explicit DartSnapshotLoader(tonic::DartState* dart_state);
~DartSnapshotLoader();
void LoadSnapshot(mojo::ScopedDataPipeConsumerHandle pipe,
const ftl::Closure& callback);
private:
ftl::WeakPtr<tonic::DartState> dart_state_;
std::unique_ptr<glue::DrainDataPipeJob> drainer_;
FTL_DISALLOW_COPY_AND_ASSIGN(DartSnapshotLoader);
};
} // namespace blink
#endif // FLUTTER_TONIC_DART_SNAPSHOT_LOADER_H_
......@@ -4,13 +4,9 @@
#include "flutter/tonic/dart_state.h"
#include "lib/tonic/converter/dart_converter.h"
#include "flutter/tonic/dart_library_loader.h"
namespace blink {
DartState::DartState()
: library_loader_(new DartLibraryLoader(this)) {}
DartState::DartState() {}
DartState::~DartState() {}
......
......@@ -6,21 +6,13 @@
#define FLUTTER_TONIC_DART_STATE_H_
#include "dart/runtime/include/dart_api.h"
#include "flutter/tonic/dart_isolate_reloader.h"
#include "lib/tonic/dart_persistent_value.h"
#include "lib/tonic/dart_state.h"
#include "lib/tonic/scopes/dart_api_scope.h"
#include "lib/tonic/scopes/dart_isolate_scope.h"
namespace blink {
class DartExceptionFactory;
class DartLibraryLoader;
// DartState represents the state associated with a given Dart isolate. The
// lifetime of this object is controlled by the DartVM. If you want to hold a
// reference to a DartState instance, please hold a base::WeakPtr<DartState>.
//
// DartState is analogous to gin::PerIsolateData and JSC::ExecState.
class DartState : public tonic::DartState {
public:
DartState();
......@@ -29,19 +21,6 @@ class DartState : public tonic::DartState {
static DartState* From(Dart_Isolate isolate);
static DartState* Current();
DartLibraryLoader& library_loader() { return *library_loader_; }
// Takes ownership of |isolate_reloader|.
void set_isolate_reloader(
std::unique_ptr<DartIsolateReloader> isolate_reloader) {
isolate_reloader_ = std::move(isolate_reloader);
}
DartIsolateReloader* isolate_reloader() { return isolate_reloader_.get(); }
private:
std::unique_ptr<DartLibraryLoader> library_loader_;
std::unique_ptr<DartIsolateReloader> isolate_reloader_;
protected:
FTL_DISALLOW_COPY_AND_ASSIGN(DartState);
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册