From 8354f04cbae7c02350c7a8a394c6b8577f66d668 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 20 Mar 2018 18:37:09 -0700 Subject: [PATCH 1/3] Updates in flutter/runtime for the shell refactor (Patch 8). This changes is part of a large patch for easier review. Try the whole patch in one go by checking out https://github.com/chinmaygarde/flutter_engine/tree/shell directly. This patch contains the following changes: * blink::DartVM (instead of the old dart_init.cc) manages all the VM instance. * blink::DartIsolate is the C++ object references by the shell for interacting with Dart isolates. The only strong referneces to these objects are in the VM. * blink::DartSnapshot objects can resolve the appropriate dart snapshot data from various sources and own referneces to these snapshots that can be collected when the isolate or VM goes away. * blink::ServiceProtocol manages the service protocol endpoints that the engine cares about and provides endpoints for out of the box. Also provides hooks for custom endpoints used as necessary by different platforms. * Unit tests for testing the VM and isolates in isolation. * Asset font selecto peeks into the unified asset manager for font manifests instead of specific asset resolvers. --- runtime/BUILD.gn | 60 ++- runtime/asset_font_selector.cc | 38 +- runtime/asset_font_selector.h | 17 +- runtime/dart_controller.cc | 250 ----------- runtime/dart_controller.h | 55 --- runtime/dart_init.cc | 724 ------------------------------ runtime/dart_init.h | 64 --- runtime/dart_isolate.cc | 685 ++++++++++++++++++++++++++++ runtime/dart_isolate.h | 142 ++++++ runtime/dart_isolate_unittests.cc | 100 +++++ runtime/dart_service_isolate.h | 2 - runtime/dart_snapshot.cc | 159 +++++++ runtime/dart_snapshot.h | 49 ++ runtime/dart_snapshot_source.cc | 72 +++ runtime/dart_snapshot_source.h | 34 ++ runtime/dart_vm.cc | 433 ++++++++++++++++++ runtime/dart_vm.h | 69 +++ runtime/dart_vm_unittests.cc | 21 + runtime/fixtures/simple_main.dart | 7 + runtime/runtime_controller.cc | 273 ++++++----- runtime/runtime_controller.h | 99 ++-- runtime/runtime_delegate.cc | 8 +- runtime/runtime_delegate.h | 8 +- runtime/runtime_init.cc | 35 -- runtime/runtime_init.h | 21 - runtime/service_protocol.cc | 277 ++++++++++++ runtime/service_protocol.h | 93 ++++ 27 files changed, 2431 insertions(+), 1364 deletions(-) delete mode 100644 runtime/dart_controller.cc delete mode 100644 runtime/dart_controller.h delete mode 100644 runtime/dart_init.cc delete mode 100644 runtime/dart_init.h create mode 100644 runtime/dart_isolate.cc create mode 100644 runtime/dart_isolate.h create mode 100644 runtime/dart_isolate_unittests.cc create mode 100644 runtime/dart_snapshot.cc create mode 100644 runtime/dart_snapshot.h create mode 100644 runtime/dart_snapshot_source.cc create mode 100644 runtime/dart_snapshot_source.h create mode 100644 runtime/dart_vm.cc create mode 100644 runtime/dart_vm.h create mode 100644 runtime/dart_vm_unittests.cc create mode 100644 runtime/fixtures/simple_main.dart delete mode 100644 runtime/runtime_init.cc delete mode 100644 runtime/runtime_init.h create mode 100644 runtime/service_protocol.cc create mode 100644 runtime/service_protocol.h diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index dea8a8906d031..9c8478dabf76a 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -4,6 +4,7 @@ import("//third_party/dart/runtime/bin/vmservice/vmservice_sources.gni") import("$flutter_root/common/config.gni") +import("$flutter_root/testing/testing.gni") action("gen_embedded_resources_cc") { script = "//third_party/dart/runtime/tools/create_resources.py" @@ -37,9 +38,7 @@ source_set("embedded_resources_cc") { deps = [ ":gen_embedded_resources_cc", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] } source_set("test_font") { @@ -50,9 +49,7 @@ source_set("test_font") { deps = [ "//third_party/skia", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] defines = [] if (flutter_runtime_mode == "debug" || current_toolchain == host_toolchain) { # Though the test font data is small, we dont want to add to the binary size @@ -63,16 +60,19 @@ source_set("test_font") { } source_set("runtime") { - sources = [ "asset_font_selector.cc", "asset_font_selector.h", - "dart_controller.cc", - "dart_controller.h", - "dart_init.cc", - "dart_init.h", + "dart_isolate.cc", + "dart_isolate.h", "dart_service_isolate.cc", "dart_service_isolate.h", + "dart_snapshot.cc", + "dart_snapshot.h", + "dart_snapshot_source.cc", + "dart_snapshot_source.h", + "dart_vm.cc", + "dart_vm.h", "embedder_resources.cc", "embedder_resources.h", "platform_impl.cc", @@ -81,8 +81,8 @@ source_set("runtime") { "runtime_controller.h", "runtime_delegate.cc", "runtime_delegate.h", - "runtime_init.cc", - "runtime_init.h", + "service_protocol.cc", + "service_protocol.h", "start_up.cc", "start_up.h", "test_font_selector.cc", @@ -92,25 +92,24 @@ source_set("runtime") { deps = [ ":embedded_resources_cc", ":test_font", - "//third_party/dart/runtime:dart_api", - "//third_party/dart/runtime/bin:embedded_dart_io", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", + "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/lib/io", "$flutter_root/lib/ui", "$flutter_root/sky/engine/platform", "$flutter_root/third_party/txt", "//garnet/public/lib/fxl", + "//third_party/dart/runtime:dart_api", + "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/rapidjson", "//third_party/skia", "//topaz/lib/tonic", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] # In AOT mode, precompiled snapshots contain the instruction buffer. # Generation of the same requires all application specific script code to be @@ -119,3 +118,28 @@ source_set("runtime") { deps += [ "$flutter_root/lib/snapshot" ] } } + +test_fixtures("runtime_fixtures") { + fixtures = [ "fixtures/simple_main.dart" ] +} + +executable("runtime_unittests") { + testonly = true + + sources = [ + "dart_isolate_unittests.cc", + "dart_vm_unittests.cc", + ] + + deps = [ + ":runtime", + ":runtime_fixtures", + "$flutter_root/fml", + "$flutter_root/lib/snapshot", + "$flutter_root/testing", + "//garnet/public/lib/fxl", + "//third_party/dart/runtime:libdart_jit", + "//third_party/skia", + "//topaz/lib/tonic", + ] +} diff --git a/runtime/asset_font_selector.cc b/runtime/asset_font_selector.cc index abf4bf9874ddd..2a43f39e3a89b 100644 --- a/runtime/asset_font_selector.cc +++ b/runtime/asset_font_selector.cc @@ -80,27 +80,15 @@ struct FontMatcher { } // namespace -void AssetFontSelector::Install( - fxl::RefPtr asset_provider) { +void AssetFontSelector::Install(fxl::RefPtr asset_manager) { RefPtr font_selector = - adoptRef(new AssetFontSelector(std::move(asset_provider))); + adoptRef(new AssetFontSelector(std::move(asset_manager))); font_selector->parseFontManifest(); UIDartState::Current()->set_font_selector(font_selector); } -void AssetFontSelector::Install(fxl::RefPtr asset_store) { - RefPtr font_selector = - adoptRef(new AssetFontSelector(std::move(asset_store))); - font_selector->parseFontManifest(); - UIDartState::Current()->set_font_selector(font_selector); -} - -AssetFontSelector::AssetFontSelector( - fxl::RefPtr asset_provider) - : asset_provider_(std::move(asset_provider)) {} - -AssetFontSelector::AssetFontSelector(fxl::RefPtr asset_store) - : asset_store_(std::move(asset_store)) {} +AssetFontSelector::AssetFontSelector(fxl::RefPtr asset_manager) + : asset_manager_(std::move(asset_manager)) {} AssetFontSelector::~AssetFontSelector() {} @@ -118,12 +106,9 @@ AssetFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {} void AssetFontSelector::parseFontManifest() { std::vector font_manifest_data; - if (!asset_provider_ || - !asset_provider_->GetAsBuffer(kFontManifestAssetPath, - &font_manifest_data)) { - if (!asset_store_ || - !asset_store_->GetAsBuffer(kFontManifestAssetPath, &font_manifest_data)) - return; + if (!asset_manager_->GetAsBuffer(kFontManifestAssetPath, + &font_manifest_data)) { + return; } rapidjson::Document document; @@ -239,13 +224,8 @@ sk_sp AssetFontSelector::getTypefaceAsset( } std::unique_ptr typeface_asset(new TypefaceAsset); - if (!asset_provider_ || !asset_provider_->GetAsBuffer( - asset_path, &typeface_asset->data)) { - if (!asset_store_ || - !asset_store_->GetAsBuffer(asset_path, &typeface_asset->data)) { - typeface_cache_.insert(std::make_pair(asset_path, nullptr)); - return nullptr; - } + if (!asset_manager_->GetAsBuffer(asset_path, &typeface_asset->data)) { + return nullptr; } sk_sp font_mgr(SkFontMgr::RefDefault()); diff --git a/runtime/asset_font_selector.h b/runtime/asset_font_selector.h index 921c0472dba78..8d7e946d89e7e 100644 --- a/runtime/asset_font_selector.h +++ b/runtime/asset_font_selector.h @@ -8,7 +8,7 @@ #include #include -#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/asset_manager.h" #include "flutter/assets/zip_asset_store.h" #include "flutter/sky/engine/platform/fonts/FontCacheKey.h" #include "flutter/sky/engine/platform/fonts/FontSelector.h" @@ -24,11 +24,7 @@ class AssetFontSelector : public FontSelector { ~AssetFontSelector() override; - static void Install(fxl::RefPtr asset_provider); - - // TODO(zarah): Remove this and related code using asset_store once flx is - // removed. - static void Install(fxl::RefPtr asset_store); + static void Install(fxl::RefPtr asset_manager); PassRefPtr getFontData(const FontDescription& font_description, const AtomicString& family_name) override; @@ -44,19 +40,14 @@ class AssetFontSelector : public FontSelector { private: struct TypefaceAsset; - explicit AssetFontSelector( - fxl::RefPtr asset_provider); - - explicit AssetFontSelector(fxl::RefPtr asset_store); + explicit AssetFontSelector(fxl::RefPtr asset_manager); void parseFontManifest(); sk_sp getTypefaceAsset(const FontDescription& font_description, const AtomicString& family_name); - fxl::RefPtr asset_provider_; - - fxl::RefPtr asset_store_; + fxl::RefPtr asset_manager_; HashMap> font_family_map_; diff --git a/runtime/dart_controller.cc b/runtime/dart_controller.cc deleted file mode 100644 index 84cfceeaecc10..0000000000000 --- a/runtime/dart_controller.cc +++ /dev/null @@ -1,250 +0,0 @@ -// 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/runtime/dart_controller.h" -#include "lib/fxl/build_config.h" - -#if defined(OS_WIN) -#include -#undef GetCurrentDirectory -#endif - -#include - -#include "flutter/common/settings.h" -#include "flutter/common/threads.h" -#include "flutter/glue/trace_event.h" -#include "flutter/lib/io/dart_io.h" -#include "flutter/lib/ui/dart_runtime_hooks.h" -#include "flutter/lib/ui/dart_ui.h" -#include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "lib/fxl/files/directory.h" -#include "lib/fxl/files/path.h" -#include "lib/tonic/dart_class_library.h" -#include "lib/tonic/dart_message_handler.h" -#include "lib/tonic/dart_state.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 "third_party/dart/runtime/include/dart_tools_api.h" - -using tonic::LogIfError; -using tonic::ToDart; - -namespace blink { -namespace { -#if defined(OS_WIN) - -std::string FindAndReplace(const std::string& str, - const std::string& findStr, - const std::string& replaceStr) { - std::string rStr = str; - size_t pos = 0; - while ((pos = rStr.find(findStr, pos)) != std::string::npos) { - rStr.replace(pos, findStr.length(), replaceStr); - pos += replaceStr.length(); - } - return rStr; -} - -std::string SanitizePath(const std::string& path) { - return FindAndReplace(path, "\\\\", "/"); -} - -std::string ResolvePath(std::string path) { - std::string sanitized = SanitizePath(path); - if ((sanitized.length() > 2) && (sanitized[1] == ':')) { - return sanitized; - } - return files::SimplifyPath(files::GetCurrentDirectory() + "/" + sanitized); -} - -#else // defined(OS_WIN) - -std::string SanitizePath(const std::string& path) { - return path; -} - -// TODO(abarth): Consider adding this to //garnet/public/lib/fxl. -std::string ResolvePath(std::string path) { - if (!path.empty() && path[0] == '/') - return path; - return files::SimplifyPath(files::GetCurrentDirectory() + "/" + path); -} - -#endif - -} // namespace - -DartController::DartController() : ui_dart_state_(nullptr) {} - -DartController::~DartController() { - if (ui_dart_state_) { - ui_dart_state_->set_isolate_client(nullptr); - - if (!ui_dart_state_->shutting_down()) { - // Don't use a tonic::DartIsolateScope here since we never exit the - // isolate. - Dart_EnterIsolate(ui_dart_state_->isolate()); - // Clear the message notify callback. - Dart_SetMessageNotifyCallback(nullptr); - Dart_ShutdownIsolate(); - } - } -} - -const std::string DartController::main_entrypoint_ = "main"; - -bool DartController::SendStartMessage(Dart_Handle root_library, - const std::string& entrypoint) { - if (LogIfError(root_library)) - return true; - - { - // Temporarily exit the isolate while we make it runnable. - Dart_Isolate isolate = dart_state()->isolate(); - FXL_DCHECK(Dart_CurrentIsolate() == isolate); - Dart_ExitIsolate(); - Dart_IsolateMakeRunnable(isolate); - Dart_EnterIsolate(isolate); - } - - // In order to support pausing the isolate at start, we indirectly invoke - // main by sending a message to the isolate. - - // Get the closure of main(). - Dart_Handle main_closure = Dart_GetClosure( - root_library, Dart_NewStringFromCString(entrypoint.c_str())); - if (LogIfError(main_closure)) - return true; - - // Grab the 'dart:isolate' library. - Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); - DART_CHECK_VALID(isolate_lib); - - // Send the start message containing the entry point by calling - // _startMainIsolate in dart:isolate. - const intptr_t kNumIsolateArgs = 2; - Dart_Handle isolate_args[kNumIsolateArgs]; - isolate_args[0] = main_closure; - isolate_args[1] = Dart_Null(); - Dart_Handle result = Dart_Invoke(isolate_lib, ToDart("_startMainIsolate"), - kNumIsolateArgs, isolate_args); - return LogIfError(result); -} - -tonic::DartErrorHandleType DartController::RunFromKernel( - const std::vector& kernel, - const std::string& entrypoint) { - tonic::DartState::Scope scope(dart_state()); - tonic::DartErrorHandleType error = tonic::kNoError; - if (Dart_IsNull(Dart_RootLibrary())) { - Dart_Handle result = Dart_LoadScriptFromKernel(kernel.data(), kernel.size()); - LogIfError(result); - error = tonic::GetErrorHandleType(result); - } - if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { - return tonic::kUnknownErrorType; - } - return error; -} - -tonic::DartErrorHandleType DartController::RunFromPrecompiledSnapshot( - const std::string& entrypoint) { - TRACE_EVENT0("flutter", "DartController::RunFromPrecompiledSnapshot"); - FXL_DCHECK(Dart_CurrentIsolate() == nullptr); - tonic::DartState::Scope scope(dart_state()); - if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { - return tonic::kUnknownErrorType; - } - return tonic::kNoError; -} - -tonic::DartErrorHandleType DartController::RunFromScriptSnapshot( - const uint8_t* buffer, - size_t size, - const std::string& entrypoint) { - tonic::DartState::Scope scope(dart_state()); - tonic::DartErrorHandleType error = tonic::kNoError; - if (Dart_IsNull(Dart_RootLibrary())) { - Dart_Handle result = Dart_LoadScriptFromSnapshot(buffer, size); - LogIfError(result); - error = tonic::GetErrorHandleType(result); - } - if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { - return tonic::kUnknownErrorType; - } - return error; -} - -tonic::DartErrorHandleType DartController::RunFromSource( - const std::string& main, - const std::string& packages) { - tonic::DartState::Scope scope(dart_state()); - tonic::DartErrorHandleType error = tonic::kNoError; - if (Dart_IsNull(Dart_RootLibrary())) { - tonic::FileLoader& loader = dart_state()->file_loader(); - if (!packages.empty() && !loader.LoadPackagesMap(ResolvePath(packages))) - FXL_LOG(WARNING) << "Failed to load package map: " << packages; - Dart_Handle result = loader.LoadScript(SanitizePath(main)); - LogIfError(result); - error = tonic::GetErrorHandleType(result); - } - if (SendStartMessage(Dart_RootLibrary())) { - return tonic::kCompilationErrorType; - } - return error; -} - -void DartController::CreateIsolateFor(const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - std::unique_ptr state) { - char* error = nullptr; - - void* platform_kernel = GetKernelPlatformBinary(); - - Dart_Isolate isolate; - if (platform_kernel != nullptr) { - isolate = Dart_CreateIsolateFromKernel( - script_uri.c_str(), "main", platform_kernel, nullptr /* flags */, - static_cast(state.get()), &error); - } else { - isolate = - Dart_CreateIsolate(script_uri.c_str(), "main", isolate_snapshot_data, - isolate_snapshot_instr, nullptr, - static_cast(state.get()), &error); - } - FXL_CHECK(isolate) << error; - ui_dart_state_ = state.release(); - ui_dart_state_->set_is_controller_state(true); - dart_state()->message_handler().Initialize(blink::Threads::UI()); - - Dart_SetShouldPauseOnStart(Settings::Get().start_paused); - - ui_dart_state_->set_debug_name_prefix(script_uri); - ui_dart_state_->SetIsolate(isolate); - FXL_CHECK(!LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); - - { - tonic::DartApiScope dart_api_scope; - DartIO::InitForIsolate(); - DartUI::InitForIsolate(); - DartRuntimeHooks::Install(DartRuntimeHooks::MainIsolate, script_uri); - - std::unique_ptr ui_class_provider( - new tonic::DartClassProvider(dart_state(), "dart:ui")); - dart_state()->class_library().add_provider("ui", - std::move(ui_class_provider)); - } - Dart_ExitIsolate(); -} - -} // namespace blink diff --git a/runtime/dart_controller.h b/runtime/dart_controller.h deleted file mode 100644 index 4b11a8660b7e7..0000000000000 --- a/runtime/dart_controller.h +++ /dev/null @@ -1,55 +0,0 @@ -// 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_RUNTIME_DART_CONTROLLER_H_ -#define FLUTTER_RUNTIME_DART_CONTROLLER_H_ - -#include -#include - -#include "lib/fxl/macros.h" -#include "lib/tonic/logging/dart_error.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace blink { -class UIDartState; - -class DartController { - public: - DartController(); - ~DartController(); - - tonic::DartErrorHandleType RunFromKernel( - const std::vector& kernel, - const std::string& entrypoint = main_entrypoint_); - tonic::DartErrorHandleType RunFromPrecompiledSnapshot( - const std::string& entrypoint = main_entrypoint_); - tonic::DartErrorHandleType RunFromScriptSnapshot( - const uint8_t* buffer, - size_t size, - const std::string& entrypoint = main_entrypoint_); - tonic::DartErrorHandleType RunFromSource(const std::string& main, - const std::string& packages); - - void CreateIsolateFor(const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - std::unique_ptr ui_dart_state); - - UIDartState* dart_state() const { return ui_dart_state_; } - - private: - bool SendStartMessage(Dart_Handle root_library, - const std::string& entrypoint = main_entrypoint_); - - static const std::string main_entrypoint_; - - // The DartState associated with the main isolate. - UIDartState* ui_dart_state_; - - FXL_DISALLOW_COPY_AND_ASSIGN(DartController); -}; -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_CONTROLLER_H_ diff --git a/runtime/dart_init.cc b/runtime/dart_init.cc deleted file mode 100644 index 5dd9e202a6398..0000000000000 --- a/runtime/dart_init.cc +++ /dev/null @@ -1,724 +0,0 @@ -// 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/runtime/dart_init.h" -#include "flutter/sky/engine/wtf/OperatingSystem.h" - -#include -#include -#include - -#if defined(OS_WIN) -#include -#include -#undef ERROR - -#define access _access -#define R_OK 0x4 - -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) -#endif - -#else -#include -#endif - -#include -#include -#include -#include - -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/assets/unzipper_provider.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/common/settings.h" -#include "flutter/glue/trace_event.h" -#include "flutter/lib/io/dart_io.h" -#include "flutter/lib/ui/dart_runtime_hooks.h" -#include "flutter/lib/ui/dart_ui.h" -#include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/window.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "flutter/runtime/start_up.h" -#include "lib/fxl/arraysize.h" -#include "lib/fxl/build_config.h" -#include "lib/fxl/files/path.h" -#include "lib/fxl/files/file.h" -#include "lib/fxl/logging.h" -#include "lib/fxl/time/time_delta.h" -#include "lib/tonic/converter/dart_converter.h" -#include "lib/tonic/dart_class_library.h" -#include "lib/tonic/dart_state.h" -#include "lib/tonic/dart_sticky_error.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 "lib/tonic/typed_data/uint8_list.h" -#include "third_party/dart/runtime/bin/embedded_dart_io.h" -#include "third_party/dart/runtime/include/dart_mirrors_api.h" - -using tonic::DartClassProvider; -using tonic::LogIfError; -using tonic::ToDart; - -namespace dart { -namespace observatory { - -#if !OS(FUCHSIA) && FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE - -// These two symbols are defined in |observatory_archive.cc| which is generated -// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. -// Both of these symbols will be part of the data segment and therefore are read -// only. -extern unsigned int observatory_assets_archive_len; -extern const uint8_t* observatory_assets_archive; - -#endif // FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE - -} // namespace observatory -} // namespace dart - -namespace blink { - -const char kKernelAssetKey[] = "kernel_blob.bin"; -const char kSnapshotAssetKey[] = "snapshot_blob.bin"; -const char kPlatformKernelAssetKey[] = "platform.dill"; - -namespace { - -// Arguments passed to the Dart VM in all configurations. -static const char* kDartLanguageArgs[] = { - "--enable_mirrors=false", "--background_compilation", "--await_is_keyword", - "--causal_async_stacks", "--limit-ints-to-64-bits", -}; - -static const char* kDartPrecompilationArgs[] = { - "--precompilation", -}; - -static const char* kDartWriteProtectCodeArgs[] FXL_ALLOW_UNUSED_TYPE = { - "--no_write_protect_code", -}; - -static const char* kDartAssertArgs[] = { - // clang-format off - "--enable_asserts", - // clang-format on -}; - -static const char* kDartCheckedModeArgs[] = { - // clang-format off - "--enable_type_checks", - "--error_on_bad_type", - "--error_on_bad_override", - // clang-format on -}; - -static const char* kDartStrongModeArgs[] = { - // clang-format off - "--limit_ints_to_64_bits", - "--reify_generic_functions", - "--strong", - "--sync_async", - // clang-format on -}; - -static const char* kDartStartPausedArgs[]{ - "--pause_isolates_on_start", -}; - -static const char* kDartTraceStartupArgs[]{ - "--timeline_streams=Compiler,Dart,Embedder,GC", -}; - -static const char* kDartEndlessTraceBufferArgs[]{ - "--timeline_recorder=endless", -}; - -static const char* kDartFuchsiaTraceArgs[] FXL_ALLOW_UNUSED_TYPE = { - "--systrace_timeline", - "--timeline_streams=VM,Isolate,Compiler,Dart,GC", -}; - -constexpr char kFileUriPrefix[] = "file://"; -constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; - -static const uint8_t* g_default_isolate_snapshot_data = nullptr; -static const uint8_t* g_default_isolate_snapshot_instructions = nullptr; -static bool g_service_isolate_initialized = false; -static ServiceIsolateHook g_service_isolate_hook = nullptr; -static RegisterNativeServiceProtocolExtensionHook - g_register_native_service_protocol_extensions_hook = nullptr; - -// Kernel representation of core dart libraries(loaded from platform.dill). -// TODO(aam): This (and platform_data below) have to be released when engine -// gets torn down. At that point we could also call Dart_Cleanup to complete -// Dart VM cleanup. -static void* kernel_platform = nullptr; -// Bytes actually read from platform.dill that are referenced by kernel_platform -static std::vector platform_data; - -void IsolateShutdownCallback(void* callback_data) { - if (tonic::DartStickyError::IsSet()) { - tonic::DartApiScope api_scope; - FXL_LOG(ERROR) << "Isolate " << tonic::StdStringFromDart(Dart_DebugName()) - << " exited with an error"; - Dart_Handle sticky_error = Dart_GetStickyError(); - FXL_CHECK(LogIfError(sticky_error)); - } - - UIDartState* dart_state = static_cast(callback_data); - // If the isolate that's shutting down is the main one, tell the higher layers - // of the stack. - if ((dart_state != NULL) && dart_state->is_controller_state()) { - dart_state->set_shutting_down(true); - if (dart_state->isolate_client()) { - dart_state->isolate_client()->DidShutdownMainIsolate(); - } - } -} - -// The cleanup callback frees the DartState object. -void IsolateCleanupCallback(void* callback_data) { - UIDartState* dart_state = static_cast(callback_data); - delete dart_state; -} - -bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { - if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) { - // Assume modified. - return true; - } - - const char* path = source_url + kFileUriPrefixLength; - struct stat info; - if (stat(path, &info) < 0) - return true; - - // If st_mtime is zero, it's more likely that the file system doesn't support - // mtime than that the file was actually modified in the 1970s. - if (!info.st_mtime) - return true; - - // It's very unclear what time bases we're with here. The Dart API doesn't - // document the time base for since_ms. Reading the code, the value varies by - // platform, with a typical source being something like gettimeofday. - // - // We add one to st_mtime because st_mtime has less precision than since_ms - // and we want to treat the file as modified if the since time is between - // ticks of the mtime. - fxl::TimeDelta mtime = fxl::TimeDelta::FromSeconds(info.st_mtime + 1); - fxl::TimeDelta since = fxl::TimeDelta::FromMilliseconds(since_ms); - - return mtime > since; -} - -void ThreadExitCallback() {} - -bool IsServiceIsolateURL(const char* url_name) { - return url_name != nullptr && - std::string(url_name) == DART_VM_SERVICE_ISOLATE_NAME; -} - -static bool StringEndsWith(const std::string& string, - const std::string& ending) { - if (ending.size() > string.size()) - return false; - - return string.compare(string.size() - ending.size(), ending.size(), ending) == - 0; -} - -static void ReleaseFetchedBytes(uint8_t* buffer) { - free(buffer); -} - -Dart_Isolate ServiceIsolateCreateCallback(const char* script_uri, - Dart_IsolateFlags* flags, - char** error) { -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE - // No VM-service in release mode. - return nullptr; -#else // FLUTTER_RUNTIME_MODE - UIDartState* dart_state = new UIDartState(nullptr, nullptr); - - bool is_running_from_kernel = GetKernelPlatformBinary() != nullptr; - - flags->load_vmservice_library = true; - Dart_Isolate isolate = - is_running_from_kernel - ? Dart_CreateIsolateFromKernel( - script_uri, "main", kernel_platform, flags, - static_cast(dart_state), error) - : Dart_CreateIsolate( - script_uri, "main", g_default_isolate_snapshot_data, - g_default_isolate_snapshot_instructions, flags, - static_cast(dart_state), error); - - FXL_CHECK(isolate) << error; - dart_state->set_debug_name_prefix(script_uri); - dart_state->SetIsolate(isolate); - FXL_CHECK(Dart_IsServiceIsolate(isolate)); - FXL_CHECK(!LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); - { - tonic::DartApiScope dart_api_scope; - DartIO::InitForIsolate(); - DartUI::InitForIsolate(); - DartRuntimeHooks::Install(DartRuntimeHooks::SecondaryIsolate, script_uri); - const Settings& settings = Settings::Get(); - if (settings.enable_observatory) { - std::string ip = settings.ipv6 ? "::1" : "127.0.0.1"; - const intptr_t port = settings.observatory_port; - const bool disable_websocket_origin_check = false; - const bool service_isolate_booted = DartServiceIsolate::Startup( - ip, port, tonic::DartState::HandleLibraryTag, - !IsRunningPrecompiledCode() && !is_running_from_kernel, - disable_websocket_origin_check, error); - FXL_CHECK(service_isolate_booted) << error; - } - - if (g_service_isolate_hook) - g_service_isolate_hook(IsRunningPrecompiledCode()); - } - Dart_ExitIsolate(); - - g_service_isolate_initialized = true; - // Register any native service protocol extensions. - if (g_register_native_service_protocol_extensions_hook) { - g_register_native_service_protocol_extensions_hook( - IsRunningPrecompiledCode()); - } - return isolate; -#endif // FLUTTER_RUNTIME_MODE -} - -static bool GetAssetAsBuffer( - const std::string& name, - std::vector* data, - fxl::RefPtr& directory_asset_bundle, - fxl::RefPtr& asset_store) { - return (directory_asset_bundle && - directory_asset_bundle->GetAsBuffer(name, data)) || - (asset_store && asset_store->GetAsBuffer(name, data)); -} - -Dart_Isolate IsolateCreateCallback(const char* script_uri, - const char* main, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - void* callback_data, - char** error) { - TRACE_EVENT0("flutter", __func__); - - if (IsServiceIsolateURL(script_uri)) { - return ServiceIsolateCreateCallback(script_uri, flags, error); - } - - std::string entry_uri = script_uri; - // Are we running from a Dart source file? - const bool running_from_source = StringEndsWith(entry_uri, ".dart"); - - std::vector kernel_data; - std::vector snapshot_data; - std::string entry_path; - if (!IsRunningPrecompiledCode()) { - // Check that the entry script URI starts with file:// - if (entry_uri.find(kFileUriPrefix) != 0u) { - *error = strdup("Isolates must use file:// URIs"); - return nullptr; - } - // Entry script path (file:// is stripped). - entry_path = std::string(script_uri + strlen(kFileUriPrefix)); - if (!running_from_source) { - // Attempt to copy the snapshot from the asset bundle. - const std::string& bundle_path = entry_path; - - struct stat stat_result = {}; - if (::stat(bundle_path.c_str(), &stat_result) == 0) { - fxl::RefPtr directory_asset_bundle; - // TODO(zarah): Remove usage of zip_asset_store once app.flx is removed. - fxl::RefPtr zip_asset_store; - // bundle_path is either the path to app.flx or the flutter assets - // directory. - std::string flx_path = bundle_path; - if (S_ISDIR(stat_result.st_mode)) { - directory_asset_bundle = - fxl::MakeRefCounted(bundle_path); - flx_path = files::GetDirectoryName(bundle_path) + "/app.flx"; - } - - if (access(flx_path.c_str(), R_OK) == 0) { - zip_asset_store = fxl::MakeRefCounted( - GetUnzipperProviderForPath(flx_path)); - } - GetAssetAsBuffer(kKernelAssetKey, &kernel_data, directory_asset_bundle, - zip_asset_store); - GetAssetAsBuffer(kSnapshotAssetKey, &snapshot_data, - directory_asset_bundle, zip_asset_store); - } - } - } - - UIDartState* parent_dart_state = static_cast(callback_data); - UIDartState* dart_state = parent_dart_state->CreateForChildIsolate(); - - Dart_Isolate isolate = - kernel_platform != nullptr - ? Dart_CreateIsolateFromKernel(script_uri, main, kernel_platform, - nullptr /* flags */, dart_state, error) - : Dart_CreateIsolate(script_uri, main, - g_default_isolate_snapshot_data, - g_default_isolate_snapshot_instructions, nullptr, - dart_state, error); - FXL_CHECK(isolate) << error; - dart_state->set_debug_name_prefix(script_uri); - dart_state->SetIsolate(isolate); - FXL_CHECK(!LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); - - { - tonic::DartApiScope dart_api_scope; - DartIO::InitForIsolate(); - DartUI::InitForIsolate(); - DartRuntimeHooks::Install(DartRuntimeHooks::SecondaryIsolate, script_uri); - - std::unique_ptr ui_class_provider( - new DartClassProvider(dart_state, "dart:ui")); - dart_state->class_library().add_provider("ui", - std::move(ui_class_provider)); - - if (!kernel_data.empty()) { - // We are running kernel code. - FXL_CHECK(!LogIfError(Dart_LoadScriptFromKernel(kernel_data.data(), - kernel_data.size()))); - } else if (!snapshot_data.empty()) { - // We are running from a script snapshot. - FXL_CHECK(!LogIfError(Dart_LoadScriptFromSnapshot(snapshot_data.data(), - snapshot_data.size()))); - } else if (running_from_source) { - // We are running from source. - // Forward the .packages configuration from the parent isolate to the - // child isolate. - tonic::FileLoader& parent_loader = parent_dart_state->file_loader(); - const std::string& packages = parent_loader.packages(); - tonic::FileLoader& loader = dart_state->file_loader(); - if (!packages.empty() && !loader.LoadPackagesMap(packages)) { - FXL_LOG(WARNING) << "Failed to load package map: " << packages; - } - // Load the script. - FXL_CHECK(!LogIfError(loader.LoadScript(entry_path))); - } - - dart_state->isolate_client()->DidCreateSecondaryIsolate(isolate); - } - - Dart_ExitIsolate(); - - FXL_CHECK(Dart_IsolateMakeRunnable(isolate)); - return isolate; -} - -Dart_Handle GetVMServiceAssetsArchiveCallback() { -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE - return nullptr; -#elif OS(FUCHSIA) - std::vector observatory_assets_archive; - if (!files::ReadFileToVector("pkg/data/observatory.tar", - &observatory_assets_archive)) { - FXL_LOG(ERROR) << "Fail to load Observatory archive"; - return nullptr; - } - return tonic::DartConverter::ToDart( - observatory_assets_archive.data(), - observatory_assets_archive.size()); -#else - return tonic::DartConverter::ToDart( - ::dart::observatory::observatory_assets_archive, - ::dart::observatory::observatory_assets_archive_len); -#endif -} - -static const char kStdoutStreamId[] = "Stdout"; -static const char kStderrStreamId[] = "Stderr"; - -static bool ServiceStreamListenCallback(const char* stream_id) { - if (strcmp(stream_id, kStdoutStreamId) == 0) { - dart::bin::SetCaptureStdout(true); - return true; - } else if (strcmp(stream_id, kStderrStreamId) == 0) { - dart::bin::SetCaptureStderr(true); - return true; - } - return false; -} - -static void ServiceStreamCancelCallback(const char* stream_id) { - if (strcmp(stream_id, kStdoutStreamId) == 0) { - dart::bin::SetCaptureStdout(false); - } else if (strcmp(stream_id, kStderrStreamId) == 0) { - dart::bin::SetCaptureStderr(false); - } -} - -} // namespace - -bool IsRunningPrecompiledCode() { - return Dart_IsPrecompiledRuntime(); -} - -EmbedderTracingCallbacks* g_tracing_callbacks = nullptr; - -EmbedderTracingCallbacks::EmbedderTracingCallbacks( - EmbedderTracingCallback start, - EmbedderTracingCallback stop) - : start_tracing_callback(start), stop_tracing_callback(stop) {} - -void SetEmbedderTracingCallbacks( - std::unique_ptr callbacks) { - g_tracing_callbacks = callbacks.release(); -} - -static void EmbedderTimelineStartRecording() { - if (g_tracing_callbacks) - g_tracing_callbacks->start_tracing_callback(); -} - -static void EmbedderTimelineStopRecording() { - if (g_tracing_callbacks) - g_tracing_callbacks->stop_tracing_callback(); -} - -static std::vector ProfilingFlags(bool enable_profiling) { -// Disable Dart's built in profiler when building a debug build. This -// works around a race condition that would sometimes stop a crash's -// stack trace from being printed on Android. -#ifndef NDEBUG - enable_profiling = false; -#endif - - // We want to disable profiling by default because it overwhelms LLDB. But - // the VM enables the same by default. In either case, we have some profiling - // flags. - if (enable_profiling) { - return { - // Dart assumes ARM devices are insufficiently powerful and sets the - // default profile period to 100Hz. This number is suitable for older - // Raspberry Pi devices but quite low for current smartphones. - "--profile_period=1000", - // This is the default. But just be explicit. - "--profiler", - // This instructs the profiler to walk C++ frames, and to include - // them in the profile. - "--profile-vm"}; - } else { - return {"--no-profiler"}; - } -} - -void SetServiceIsolateHook(ServiceIsolateHook hook) { - FXL_CHECK(!g_service_isolate_initialized); - g_service_isolate_hook = hook; -} - -void SetRegisterNativeServiceProtocolExtensionHook( - RegisterNativeServiceProtocolExtensionHook hook) { - FXL_CHECK(!g_service_isolate_initialized); - g_register_native_service_protocol_extensions_hook = hook; -} - -void PushBackAll(std::vector* args, - const char** argv, - size_t argc) { - for (size_t i = 0; i < argc; ++i) { - args->push_back(argv[i]); - } -} - -static void EmbedderInformationCallback(Dart_EmbedderInformation* info) { - info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION; - dart::bin::GetIOEmbedderInformation(info); - info->name = "Flutter"; -} - -void* GetKernelPlatformBinary() { - return kernel_platform; -} - -void InitDartVM(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path) { - TRACE_EVENT0("flutter", __func__); - - g_default_isolate_snapshot_data = default_isolate_snapshot_data; - g_default_isolate_snapshot_instructions = - default_isolate_snapshot_instructions; - - const Settings& settings = Settings::Get(); - - { - TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo"); - dart::bin::BootstrapDartIo(); - - if (!settings.temp_directory_path.empty()) { - dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str()); - } - } - - std::vector args; - - // Instruct the VM to ignore unrecognized flags. - // There is a lot of diversity in a lot of combinations when it - // comes to the arguments the VM supports. And, if the VM comes across a flag - // it does not recognize, it exits immediately. - args.push_back("--ignore-unrecognized-flags"); - - for (const auto& profiler_flag : - ProfilingFlags(settings.enable_dart_profiling)) { - args.push_back(profiler_flag); - } - - PushBackAll(&args, kDartLanguageArgs, arraysize(kDartLanguageArgs)); - - if (IsRunningPrecompiledCode()) { - PushBackAll(&args, kDartPrecompilationArgs, - arraysize(kDartPrecompilationArgs)); - } - -#if defined(OS_FUCHSIA) -#if defined(NDEBUG) - // Do not enable checked mode for Fuchsia release builds - // TODO(mikejurka): remove this once precompiled code is working on Fuchsia - const bool use_checked_mode = false; -#else // !defined(NDEBUG) - const bool use_checked_mode = true; -#endif // !defined(NDEBUG) -#else // !defined(OS_FUCHSIA) - // Enable checked mode if we are not running precompiled code. We run non- - // precompiled code only in the debug product mode. - const bool use_checked_mode = - !IsRunningPrecompiledCode() && !settings.dart_non_checked_mode; -#endif // !defined(OS_FUCHSIA) - -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - // Debug mode uses the JIT, disable code page write protection to avoid - // memory page protection changes before and after every compilation. - PushBackAll(&args, kDartWriteProtectCodeArgs, - arraysize(kDartWriteProtectCodeArgs)); -#endif - - if (settings.start_paused) - PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs)); - - if (settings.endless_trace_buffer || settings.trace_startup) { - // If we are tracing startup, make sure the trace buffer is endless so we - // don't lose early traces. - PushBackAll(&args, kDartEndlessTraceBufferArgs, - arraysize(kDartEndlessTraceBufferArgs)); - } - - if (settings.trace_startup) { - PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs)); - } - -#if defined(OS_FUCHSIA) - PushBackAll(&args, kDartFuchsiaTraceArgs, arraysize(kDartFuchsiaTraceArgs)); -#endif - - if (!bundle_path.empty()) { - fxl::RefPtr directory_asset_bundle = - fxl::MakeRefCounted( - std::move(bundle_path)); - directory_asset_bundle->GetAsBuffer(kPlatformKernelAssetKey, - &platform_data); - if (!platform_data.empty()) { - uint8_t* kernel_buf = static_cast(malloc(platform_data.size())); - memcpy(kernel_buf, platform_data.data(), platform_data.size()); - kernel_platform = Dart_ReadKernelBinary(kernel_buf, platform_data.size(), - ReleaseFetchedBytes); - FXL_DCHECK(kernel_platform != nullptr); - } - } - if ((kernel_platform != nullptr) || - Dart_IsDart2Snapshot(g_default_isolate_snapshot_data)) { - // The presence of the kernel platform file or a snapshot that was generated - // for Dart2 indicates we are running in preview-dart-2 mode and in this - // mode enable strong mode options by default. - // Note: When we start using core snapshots instead of the platform file - // in the engine just sniffing the snapshot file should be sufficient. - PushBackAll(&args, kDartStrongModeArgs, arraysize(kDartStrongModeArgs)); - // In addition if we are running in debug mode we also enable asserts. - if (use_checked_mode) { - PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); - } - } else if (use_checked_mode) { - // In non preview-dart-2 mode we enable checked mode and asserts if - // we are running in debug mode. - PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); - PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs)); - } - - for (size_t i = 0; i < settings.dart_flags.size(); i++) - args.push_back(settings.dart_flags[i].c_str()); - - FXL_CHECK(Dart_SetVMFlags(args.size(), args.data())); - - DartUI::InitForGlobal(); - - // Setup embedder tracing hooks. To avoid data races, it is recommended that - // these hooks be installed before the DartInitialize, so do that setup now. - Dart_SetEmbedderTimelineCallbacks(&EmbedderTimelineStartRecording, - &EmbedderTimelineStopRecording); - - Dart_SetFileModifiedCallback(&DartFileModifiedCallback); - - { - TRACE_EVENT0("flutter", "Dart_Initialize"); - Dart_InitializeParams params = {}; - params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; - params.vm_snapshot_data = vm_snapshot_data; - params.vm_snapshot_instructions = vm_snapshot_instructions; - params.create = IsolateCreateCallback; - params.shutdown = IsolateShutdownCallback; - params.cleanup = IsolateCleanupCallback; - params.thread_exit = ThreadExitCallback; - params.get_service_assets = GetVMServiceAssetsArchiveCallback; - params.entropy_source = DartIO::EntropySource; - char* init_error = Dart_Initialize(¶ms); - if (init_error != nullptr) - FXL_LOG(FATAL) << "Error while initializing the Dart VM: " << init_error; - free(init_error); - - // Send the earliest available timestamp in the application lifecycle to - // timeline. The difference between this timestamp and the time we render - // the very first frame gives us a good idea about Flutter's startup time. - // Use a duration event so about:tracing will consider this event when - // deciding the earliest event to use as time 0. - if (blink::engine_main_enter_ts != 0) { - Dart_TimelineEvent("FlutterEngineMainEnter", // label - blink::engine_main_enter_ts, // timestamp0 - blink::engine_main_enter_ts, // timestamp1_or_async_id - Dart_Timeline_Event_Duration, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values - ); - } - } - - // Allow streaming of stdout and stderr by the Dart vm. - Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback, - &ServiceStreamCancelCallback); - - Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); -} - -} // namespace blink diff --git a/runtime/dart_init.h b/runtime/dart_init.h deleted file mode 100644 index 99c8fe89137e3..0000000000000 --- a/runtime/dart_init.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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_RUNTIME_DART_INIT_H_ -#define FLUTTER_RUNTIME_DART_INIT_H_ - -#include "lib/fxl/build_config.h" -#include "lib/fxl/functional/closure.h" -#include "third_party/dart/runtime/include/dart_api.h" - -#include -#include -#include - -namespace blink { - -// Name of the kernel blob asset within the asset directory. -extern const char kKernelAssetKey[]; - -// Name of the snapshot blob asset within the asset directory. -extern const char kSnapshotAssetKey[]; - -// Name of the platform kernel blob asset within the asset directory. -extern const char kPlatformKernelAssetKey[]; - -bool IsRunningPrecompiledCode(); - -using EmbedderTracingCallback = fxl::Closure; - -typedef void (*ServiceIsolateHook)(bool); -typedef void (*RegisterNativeServiceProtocolExtensionHook)(bool); - -struct EmbedderTracingCallbacks { - EmbedderTracingCallback start_tracing_callback; - EmbedderTracingCallback stop_tracing_callback; - - EmbedderTracingCallbacks(EmbedderTracingCallback start, - EmbedderTracingCallback stop); -}; - -void InitDartVM(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path); - -void* GetKernelPlatformBinary(); - -void SetEmbedderTracingCallbacks( - std::unique_ptr callbacks); - -// Provide a function that will be called during initialization of the -// service isolate. -void SetServiceIsolateHook(ServiceIsolateHook hook); - -// Provide a function that will be called to register native service protocol -// extensions. -void SetRegisterNativeServiceProtocolExtensionHook( - RegisterNativeServiceProtocolExtensionHook hook); - -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_INIT_H_ diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc new file mode 100644 index 0000000000000..99cae3b08eb6a --- /dev/null +++ b/runtime/dart_isolate.cc @@ -0,0 +1,685 @@ +// Copyright 2017 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/runtime/dart_isolate.h" + +#include +#include + +#include "flutter/fml/trace_event.h" +#include "flutter/lib/io/dart_io.h" +#include "flutter/lib/ui/dart_runtime_hooks.h" +#include "flutter/lib/ui/dart_ui.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "flutter/runtime/dart_vm.h" +#include "lib/fxl/files/path.h" +#include "lib/tonic/converter/dart_converter.h" +#include "lib/tonic/dart_class_library.h" +#include "lib/tonic/dart_class_provider.h" +#include "lib/tonic/dart_message_handler.h" +#include "lib/tonic/dart_state.h" +#include "lib/tonic/dart_sticky_error.h" +#include "lib/tonic/file_loader/file_loader.h" +#include "lib/tonic/scopes/dart_api_scope.h" +#include "lib/tonic/scopes/dart_isolate_scope.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace blink { + +fml::WeakPtr DartIsolate::CreateRootIsolate( + const DartVM* vm, + TaskRunners task_runners, + std::unique_ptr window, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint, + Dart_IsolateFlags* flags) { + TRACE_EVENT0("flutter", "DartIsolate::CreateRootIsolate"); + Dart_Isolate vm_isolate = nullptr; + fml::WeakPtr embedder_isolate; + + char* error = nullptr; + + // Since this is the root isolate, we fake a parent embedder data object. We + // cannot use unique_ptr here because the destructor is private (since the + // isolate lifecycle is entirely managed by the VM). + DartIsolate* root_embedder_data = + new DartIsolate(vm, // VM + task_runners, // task runners + std::move(resource_context), // resource context + std::move(unref_queue), // skia unref queue + advisory_script_uri, // advisory URI + advisory_script_entrypoint // advisory entrypoint + ); + + std::tie(vm_isolate, embedder_isolate) = CreateDartVMAndEmbedderObjectPair( + advisory_script_uri.c_str(), // advisory script URI + advisory_script_entrypoint.c_str(), // advisory script entrypoint + nullptr, // package root + nullptr, // package config + flags, // flags + root_embedder_data, // parent embedder data + &error // error (out) + ); + + delete root_embedder_data; + + if (error != nullptr) { + free(error); + } + + if (vm_isolate == nullptr) { + return {}; + } + + if (embedder_isolate) { + // Only root isolates can interact with windows. + embedder_isolate->SetWindow(std::move(window)); + embedder_isolate->set_use_blink(vm->GetSettings().using_blink); + } + + return embedder_isolate; +} + +DartIsolate::DartIsolate(const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint) + : UIDartState(std::move(task_runners), + vm->GetSettings().task_observer_add, + vm->GetSettings().task_observer_remove, + std::move(resource_context), + std::move(unref_queue), + advisory_script_uri, + advisory_script_entrypoint, + vm->GetSettings().log_tag), + vm_(vm), + weak_factory_(this) { + weak_prototype_ = weak_factory_.GetWeakPtr(); + + if (vm_ == nullptr) { + return; + } + + phase_ = Phase::Uninitialized; +} + +DartIsolate::~DartIsolate() = default; + +DartIsolate::Phase DartIsolate::GetPhase() const { + return phase_; +} + +const DartVM* DartIsolate::GetDartVM() const { + return vm_; +} + +bool DartIsolate::Initialize(Dart_Isolate dart_isolate) { + TRACE_EVENT0("flutter", "DartIsolate::Initialize"); + if (phase_ != Phase::Uninitialized) { + return false; + } + + if (dart_isolate == nullptr) { + return false; + } + + if (Dart_CurrentIsolate() != dart_isolate) { + return false; + } + + if (Dart_IsolateData(dart_isolate) != this) { + return false; + } + + // After this point, isolate scopes can be safely used. + SetIsolate(dart_isolate); + + // We are entering a new scope (for the first time since initialization) and + // we want to restore the current scope to null when we exit out of this + // method. This balances the implicit Dart_EnterIsolate call made by + // Dart_CreateIsolate (which calls the Initialize). + Dart_ExitIsolate(); + + tonic::DartIsolateScope scope(isolate()); + + if (auto task_runner = GetTaskRunners().GetUITaskRunner()) { + // Isolates may not have any particular thread affinity. Only initialize the + // message handler if a task runner is explicitly specified. + message_handler().Initialize(task_runner); + } + + if (tonic::LogIfError( + Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))) { + return false; + } + + if (!UpdateThreadPoolNames()) { + return false; + } + + phase_ = Phase::Initialized; + return true; +} + +bool DartIsolate::UpdateThreadPoolNames() const { + // TODO(chinmaygarde): This implementation does not account for multiple + // shells sharing the same (or subset of) threads. + const auto& task_runners = GetTaskRunners(); + + if (auto task_runner = task_runners.GetGPUTaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".gpu"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + if (auto task_runner = task_runners.GetUITaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".ui"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + if (auto task_runner = task_runners.GetIOTaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".io"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + if (auto task_runner = task_runners.GetPlatformTaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".platform"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + return true; +} + +bool DartIsolate::LoadLibraries() { + TRACE_EVENT0("flutter", "DartIsolate::LoadLibraries"); + if (phase_ != Phase::Initialized) { + return false; + } + + tonic::DartState::Scope scope(this); + + DartIO::InitForIsolate(); + + DartUI::InitForIsolate(); + + const bool is_service_isolate = Dart_IsServiceIsolate(isolate()); + + DartRuntimeHooks::Install(is_service_isolate + ? DartRuntimeHooks::SecondaryIsolate + : DartRuntimeHooks::MainIsolate, + GetAdvisoryScriptURI()); + + if (!is_service_isolate) { + class_library().add_provider( + "ui", std::make_unique(this, "dart:ui")); + } + + phase_ = Phase::LibrariesSetup; + return true; +} + +bool DartIsolate::PrepareForRunningFromPrecompiledCode() { + TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromPrecompiledCode"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + if (!DartVM::IsRunningPrecompiledCode()) { + return false; + } + + tonic::DartState::Scope scope(this); + + if (Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!MarkIsolateRunnable()) { + return false; + } + + phase_ = Phase::Ready; + return true; +} + +static bool LoadScriptSnapshot(std::unique_ptr mapping) { + if (tonic::LogIfError(Dart_LoadScriptFromSnapshot(mapping->GetMapping(), + mapping->GetSize()))) { + return false; + } + return true; +} + +static bool LoadKernelSnapshot(std::unique_ptr mapping) { + if (tonic::LogIfError(Dart_LoadScriptFromKernel(mapping->GetMapping(), + mapping->GetSize()))) { + return false; + } + + return true; +} + +static bool LoadSnapshot(std::unique_ptr mapping, + bool is_kernel) { + if (is_kernel) { + return LoadKernelSnapshot(std::move(mapping)); + } else { + return LoadScriptSnapshot(std::move(mapping)); + } + return false; +} + +FXL_WARN_UNUSED_RESULT +bool DartIsolate::PrepareForRunningFromSnapshot( + std::unique_ptr mapping) { + TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromSnapshot"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + if (DartVM::IsRunningPrecompiledCode()) { + return false; + } + + if (!mapping || mapping->GetSize() == 0) { + return false; + } + + tonic::DartState::Scope scope(this); + + if (!Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!LoadSnapshot(std::move(mapping), vm_->GetPlatformKernel() != nullptr)) { + return false; + } + + if (Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!MarkIsolateRunnable()) { + return false; + } + + phase_ = Phase::Ready; + return true; +} + +static bool FileNameIsDill(const std::string& name) { + const std::string suffix = ".dill"; + + if (name.size() < suffix.size()) { + return false; + } + + if (name.rfind(suffix, name.size()) == name.size() - suffix.size()) { + return true; + } + return false; +} + +bool DartIsolate::PrepareForRunningFromSource( + const std::string& main_source_file, + const std::string& packages) { + TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromSource"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + if (DartVM::IsRunningPrecompiledCode()) { + return false; + } + + if (main_source_file.empty()) { + return false; + } + + tonic::DartState::Scope scope(this); + + if (!Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + auto& loader = file_loader(); + + if (!packages.empty()) { + auto packages_absolute_path = files::AbsolutePath(packages); + FXL_DLOG(INFO) << "Loading from packages: " << packages_absolute_path; + if (!loader.LoadPackagesMap(packages_absolute_path)) { + return false; + } + } + + auto main_source_absolute_path = files::AbsolutePath(main_source_file); + FXL_DLOG(INFO) << "Loading from source: " << main_source_absolute_path; + + // The "source" file may be a ".dill" file. + if (FileNameIsDill(main_source_absolute_path)) { + auto mapping = + std::make_unique(main_source_absolute_path, false); + if (mapping == nullptr) { + return false; + } + if (!LoadKernelSnapshot(std::move(mapping))) { + return false; + } + } else { + if (tonic::LogIfError(loader.LoadScript(main_source_absolute_path))) { + return false; + } + } + + if (Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!MarkIsolateRunnable()) { + return false; + } + + phase_ = Phase::Ready; + return true; +} + +bool DartIsolate::MarkIsolateRunnable() { + TRACE_EVENT0("flutter", "DartIsolate::MarkIsolateRunnable"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + // This function may only be called from an active isolate scope. + if (Dart_CurrentIsolate() != isolate()) { + return false; + } + + // There must be no current isolate to mark an isolate as being runnable. + Dart_ExitIsolate(); + + if (!Dart_IsolateMakeRunnable(isolate())) { + // Failed. Restore the isolate. + Dart_EnterIsolate(isolate()); + return false; + } + // Success. Restore the isolate. + Dart_EnterIsolate(isolate()); + return true; +} + +FXL_WARN_UNUSED_RESULT +bool DartIsolate::Run(const std::string& entrypoint_name) { + TRACE_EVENT0("flutter", "DartIsolate::Run"); + if (phase_ != Phase::Ready) { + return false; + } + + tonic::DartState::Scope scope(this); + + Dart_Handle entrypoint = Dart_GetClosure( + Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str())); + if (tonic::LogIfError(entrypoint)) { + return false; + } + + Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate")); + if (tonic::LogIfError(isolate_lib)) { + return false; + } + + Dart_Handle isolate_args[] = { + entrypoint, + Dart_Null(), + }; + + if (tonic::LogIfError(Dart_Invoke( + isolate_lib, tonic::ToDart("_startMainIsolate"), + sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) { + return false; + } + + phase_ = Phase::Running; + return true; +} + +bool DartIsolate::Shutdown() { + TRACE_EVENT0("flutter", "DartIsolate::Shutdown"); + // This call may be re-entrant since Dart_ShutdownIsolate can invoke the + // cleanup callback which deletes the embedder side object of the dart isolate + // (a.k.a. this). + if (phase_ == Phase::Shutdown) { + return false; + } + phase_ = Phase::Shutdown; + Dart_Isolate vm_isolate = isolate(); + // The isolate can be nullptr if this instance is the stub isolate data used + // during root isolate creation. + if (vm_isolate != nullptr) { + // We need to enter the isolate because Dart_ShutdownIsolate does not take + // the isolate to shutdown as a parameter. + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + Dart_EnterIsolate(vm_isolate); + Dart_ShutdownIsolate(); + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + } + return true; +} + +static Dart_Isolate DartCreateAndStartServiceIsolate( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + char** error) { + auto vm = DartVM::ForProcessIfInitialized(); + + if (!vm) { + *error = strdup( + "Could not resolve the VM when attempting to create the service " + "isolate."); + return nullptr; + } + + const auto& settings = vm->GetSettings(); + + if (!settings.enable_observatory) { + FXL_DLOG(INFO) << "Observatory is disabled."; + return nullptr; + } + + blink::TaskRunners null_task_runners("io.flutter.vm-service", nullptr, + nullptr, nullptr, nullptr); + + flags->load_vmservice_library = true; + + auto service_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + null_task_runners, // task runners + nullptr, // window + {}, // resource context + {}, // unref queue + advisory_script_uri == nullptr ? "" : advisory_script_uri, // script uri + advisory_script_entrypoint == nullptr + ? "" + : advisory_script_entrypoint, // script entrypoint + flags // flags + ); + + if (!service_isolate) { + *error = strdup("Could not create the service isolate."); + FXL_DLOG(ERROR) << *error; + return nullptr; + } + + // The engine never holds a strong reference to the VM service isolate. Since + // we are about to lose our last weak reference to it, start the VM service + // while we have this reference. + + const bool running_from_sources = + !DartVM::IsRunningPrecompiledCode() && vm->GetPlatformKernel() == nullptr; + + tonic::DartState::Scope scope(service_isolate.get()); + if (!DartServiceIsolate::Startup( + settings.ipv6 ? "::1" : "127.0.0.1", // server IP address + settings.observatory_port, // server observatory port + tonic::DartState::HandleLibraryTag, // embedder library tag handler + running_from_sources, // running from source code + false, // disable websocket origin check + error // error (out) + )) { + // Error is populated by call to startup. + FXL_DLOG(ERROR) << *error; + return nullptr; + } + + vm->GetServiceProtocol().ToggleHooks(true); + + return service_isolate->isolate(); +} + +// |Dart_IsolateCreateCallback| +Dart_Isolate DartIsolate::DartIsolateCreateCallback( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* parent_embedder_isolate, + char** error) { + if (parent_embedder_isolate == nullptr && + strcmp(advisory_script_uri, "vm-service") == 0) { + // The VM attempts to start the VM service for us on |Dart_Initialize|. In + // such a case, the callback data will be null and the script URI will be + // "vm-service". In such cases, we just create the service isolate like + // normal but dont hold a reference to it at all. We also start this isolate + // since we will never again reference it from the engine. + return DartCreateAndStartServiceIsolate(advisory_script_uri, // + advisory_script_entrypoint, // + package_root, // + package_config, // + flags, // + error // + ); + } + + return CreateDartVMAndEmbedderObjectPair( + advisory_script_uri, advisory_script_entrypoint, package_root, + package_config, flags, parent_embedder_isolate, error) + .first; +} + +std::pair> +DartIsolate::CreateDartVMAndEmbedderObjectPair( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* parent_embedder_isolate, + char** error) { + TRACE_EVENT0("flutter", "DartIsolate::CreateDartVMAndEmbedderObjectPair"); + if (parent_embedder_isolate == nullptr || + parent_embedder_isolate->GetDartVM() == nullptr) { + *error = + strdup("Parent isolate did not have embedder specific callback data."); + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + const DartVM* vm = parent_embedder_isolate->GetDartVM(); + + // Create the native object on the embedder side. This object is deleted in + // the cleanup callback. + auto embedder_isolate = + new DartIsolate(vm, // + parent_embedder_isolate->GetTaskRunners(), // + parent_embedder_isolate->GetResourceContext(), // + parent_embedder_isolate->GetSkiaUnrefQueue(), // + advisory_script_uri, // + advisory_script_entrypoint // + ); + + // Create the Dart VM isolate and give it the embedder object as the baton. + Dart_Isolate isolate = + vm->GetPlatformKernel() != nullptr + ? Dart_CreateIsolateFromKernel(advisory_script_uri, // + advisory_script_entrypoint, // + vm->GetPlatformKernel(), // + flags, // + embedder_isolate, // + error // + ) + : Dart_CreateIsolate( + advisory_script_uri, // + advisory_script_entrypoint, // + vm->GetIsolateSnapshot().GetData()->GetSnapshotPointer(), // + vm->GetIsolateSnapshot().GetInstructionsIfPresent(), // + flags, // + embedder_isolate, // + error // + ); + + if (isolate == nullptr) { + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + if (!embedder_isolate->Initialize(isolate)) { + *error = strdup("Embedder could not initialize the Dart isolate."); + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + if (!embedder_isolate->LoadLibraries()) { + *error = + strdup("Embedder could not load libraries in the new Dart isolate."); + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + // The ownership of the embedder object is controlled by the Dart VM. So the + // only reference returned to the caller is weak. + return {isolate, embedder_isolate->GetWeakIsolatePtr()}; +} + +// |Dart_IsolateShutdownCallback| +void DartIsolate::DartIsolateShutdownCallback(DartIsolate* embedder_isolate) { + if (!tonic::DartStickyError::IsSet()) { + return; + } + + tonic::DartApiScope api_scope; + FXL_LOG(ERROR) << "Isolate " << tonic::StdStringFromDart(Dart_DebugName()) + << " exited with an error"; + Dart_Handle sticky_error = Dart_GetStickyError(); + FXL_CHECK(tonic::LogIfError(sticky_error)); +} + +// |Dart_IsolateCleanupCallback| +void DartIsolate::DartIsolateCleanupCallback(DartIsolate* embedder_isolate) { + delete embedder_isolate; +} + +fml::WeakPtr DartIsolate::GetWeakIsolatePtr() const { + return weak_prototype_; +} + +void DartIsolate::AddIsolateShutdownCallback(fxl::Closure closure) { + shutdown_callbacks_.emplace_back( + std::make_unique(std::move(closure))); +} + +} // namespace blink diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h new file mode 100644 index 0000000000000..fb63ed5c0bc1f --- /dev/null +++ b/runtime/dart_isolate.h @@ -0,0 +1,142 @@ +// Copyright 2017 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. + +#ifndef FLUTTER_RUNTIME_DART_ISOLATE_H_ +#define FLUTTER_RUNTIME_DART_ISOLATE_H_ + +#include +#include + +#include "flutter/common/task_runners.h" +#include "flutter/fml/mapping.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/window.h" +#include "lib/fxl/compiler_specific.h" +#include "lib/fxl/macros.h" +#include "lib/tonic/dart_state.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace blink { +class DartVM; + +class DartIsolate : public UIDartState { + public: + enum class Phase { + Unknown, + Uninitialized, + Initialized, + LibrariesSetup, + Ready, + Running, + Shutdown, + }; + + static fml::WeakPtr CreateRootIsolate( + const DartVM* vm, + TaskRunners task_runners, + std::unique_ptr window, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri = "main.dart", + std::string advisory_script_entrypoint = "main", + Dart_IsolateFlags* flags = nullptr); + + Phase GetPhase() const; + + FXL_WARN_UNUSED_RESULT + bool PrepareForRunningFromPrecompiledCode(); + + FXL_WARN_UNUSED_RESULT + bool PrepareForRunningFromSnapshot(std::unique_ptr snapshot); + + FXL_WARN_UNUSED_RESULT + bool PrepareForRunningFromSource(const std::string& main_source_file, + const std::string& packages); + + FXL_WARN_UNUSED_RESULT + bool Run(const std::string& entrypoint); + + FXL_WARN_UNUSED_RESULT + bool Shutdown(); + + void AddIsolateShutdownCallback(fxl::Closure closure); + + const DartVM* GetDartVM() const; + + fml::WeakPtr GetWeakIsolatePtr() const; + + private: + class AutoFireClosure { + public: + AutoFireClosure(fxl::Closure closure) : closure_(std::move(closure)) {} + ~AutoFireClosure() { + if (closure_) { + closure_(); + } + } + + private: + fxl::Closure closure_; + FXL_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure); + }; + friend class DartVM; + + const DartVM* vm_ = nullptr; + Phase phase_ = Phase::Unknown; + std::vector> shutdown_callbacks_; + fml::WeakPtr weak_prototype_; + fml::WeakPtrFactory weak_factory_; + + DartIsolate(const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint); + + ~DartIsolate() override; + + FXL_WARN_UNUSED_RESULT + bool Initialize(Dart_Isolate isolate); + + FXL_WARN_UNUSED_RESULT + bool LoadLibraries(); + + bool UpdateThreadPoolNames() const; + + FXL_WARN_UNUSED_RESULT + bool MarkIsolateRunnable(); + + // |Dart_IsolateCreateCallback| + static Dart_Isolate DartIsolateCreateCallback( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* embedder_isolate, + char** error); + + static std::pair /* embedder */> + CreateDartVMAndEmbedderObjectPair(const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* parent_embedder_isolate, + char** error); + + // |Dart_IsolateShutdownCallback| + static void DartIsolateShutdownCallback(DartIsolate* embedder_isolate); + + // |Dart_IsolateCleanupCallback| + static void DartIsolateCleanupCallback(DartIsolate* embedder_isolate); + + FXL_DISALLOW_COPY_AND_ASSIGN(DartIsolate); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_ISOLATE_H_ diff --git a/runtime/dart_isolate_unittests.cc b/runtime/dart_isolate_unittests.cc new file mode 100644 index 0000000000000..1a870fc96d7cb --- /dev/null +++ b/runtime/dart_isolate_unittests.cc @@ -0,0 +1,100 @@ +// Copyright 2017 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/fml/thread.h" +#include "flutter/runtime/dart_isolate.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/testing/testing.h" +#include "flutter/testing/thread_test.h" + +#define CURRENT_TEST_NAME \ + std::string { \ + ::testing::UnitTest::GetInstance()->current_test_info()->name() \ + } + +namespace blink { + +using DartIsolateTest = ::testing::ThreadTest; + +TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + TaskRunners task_runners(CURRENT_TEST_NAME, // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner() // + ); + auto root_isolate = + DartIsolate::CreateRootIsolate(vm.get(), // vm + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); + ASSERT_TRUE(root_isolate); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); + ASSERT_TRUE(root_isolate->Shutdown()); +} + +TEST_F(DartIsolateTest, IsolateCanAssociateSnapshot) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + TaskRunners task_runners(CURRENT_TEST_NAME, // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner() // + ); + auto root_isolate = + DartIsolate::CreateRootIsolate(vm.get(), // vm + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); + ASSERT_TRUE(root_isolate); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); + ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( + testing::GetFixturesPath() + std::string{"/simple_main.dart"}, "")); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Ready); + ASSERT_TRUE(root_isolate->Shutdown()); +} + +TEST_F(DartIsolateTest, CanResolveAndInvokeMethod) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + TaskRunners task_runners(CURRENT_TEST_NAME, // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner() // + ); + auto root_isolate = + DartIsolate::CreateRootIsolate(vm.get(), // vm + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); + ASSERT_TRUE(root_isolate); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); + ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( + testing::GetFixturesPath() + std::string{"/simple_main.dart"}, "")); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Ready); + ASSERT_TRUE(root_isolate->Run("simple_main")); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Running); + ASSERT_TRUE(root_isolate->Shutdown()); +} + +} // namespace blink diff --git a/runtime/dart_service_isolate.h b/runtime/dart_service_isolate.h index 9edd663feb6bd..59a02e2e9d495 100644 --- a/runtime/dart_service_isolate.h +++ b/runtime/dart_service_isolate.h @@ -13,8 +13,6 @@ namespace blink { class DartServiceIsolate { public: - static bool Bootstrap(); - static bool Startup(std::string server_ip, intptr_t server_port, Dart_LibraryTagHandler embedder_tag_handler, diff --git a/runtime/dart_snapshot.cc b/runtime/dart_snapshot.cc new file mode 100644 index 0000000000000..c282da1e9d2de --- /dev/null +++ b/runtime/dart_snapshot.cc @@ -0,0 +1,159 @@ +// Copyright 2017 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/runtime/dart_snapshot.h" + +#include + +#include "flutter/fml/native_library.h" +#include "flutter/fml/paths.h" +#include "flutter/fml/trace_event.h" +#include "flutter/runtime/dart_snapshot_source.h" +#include "flutter/runtime/dart_vm.h" + +namespace blink { + +static const char* kVMDataSymbol = "kDartVmSnapshotData"; +static const char* kVMInstructionsSymbol = "kDartVmSnapshotInstructions"; +static const char* kIsolateDataSymbol = "kDartIsolateSnapshotData"; +static const char* kIsolateInstructionsSymbol = + "kDartIsolateSnapshotInstructions"; + +static std::unique_ptr ResolveVMData( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = fml::paths::JoinPaths( + {settings.aot_snapshot_path, settings.aot_vm_snapshot_data_filename}); + if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + path.c_str(), false /* executable */)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotSource::CreateWithSymbolInLibrary(loaded_process, + kVMDataSymbol); +} + +static std::unique_ptr ResolveVMInstructions( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = fml::paths::JoinPaths( + {settings.aot_snapshot_path, settings.aot_vm_snapshot_instr_filename}); + if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + path.c_str(), true /* executable */)) { + return source; + } + } + + if (settings.application_library_path.size() > 0) { + auto library = + fml::NativeLibrary::Create(settings.application_library_path.c_str()); + if (auto source = DartSnapshotSource::CreateWithSymbolInLibrary( + library, kVMInstructionsSymbol)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotSource::CreateWithSymbolInLibrary(loaded_process, + kVMInstructionsSymbol); +} + +static std::unique_ptr ResolveIsolateData( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = + fml::paths::JoinPaths({settings.aot_snapshot_path, + settings.aot_isolate_snapshot_data_filename}); + if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + path.c_str(), false /* executable */)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotSource::CreateWithSymbolInLibrary(loaded_process, + kIsolateDataSymbol); +} + +static std::unique_ptr ResolveIsolateInstructions( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = + fml::paths::JoinPaths({settings.aot_snapshot_path, + settings.aot_isolate_snapshot_instr_filename}); + if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + path.c_str(), true /* executable */)) { + return source; + } + } + + if (settings.application_library_path.size() > 0) { + auto library = + fml::NativeLibrary::Create(settings.application_library_path.c_str()); + if (auto source = DartSnapshotSource::CreateWithSymbolInLibrary( + library, kIsolateInstructionsSymbol)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotSource::CreateWithSymbolInLibrary( + loaded_process, kIsolateInstructionsSymbol); +} + +std::unique_ptr DartSnapshot::VMSnapshotFromSettings( + const Settings& settings) { + TRACE_EVENT0("flutter", "DartSnapshot::VMSnapshotFromSettings"); + auto snapshot = + std::make_unique(ResolveVMData(settings), // + ResolveVMInstructions(settings) // + ); + if (snapshot->IsValid()) { + return snapshot; + } + return nullptr; +} + +std::unique_ptr DartSnapshot::IsolateSnapshotFromSettings( + const Settings& settings) { + TRACE_EVENT0("flutter", "DartSnapshot::IsolateSnapshotFromSettings"); + auto snapshot = + std::make_unique(ResolveIsolateData(settings), // + ResolveIsolateInstructions(settings) // + ); + if (snapshot->IsValid()) { + return snapshot; + } + return nullptr; +} + +DartSnapshot::DartSnapshot(std::unique_ptr data, + std::unique_ptr instructions) + : data_(std::move(data)), instructions_(std::move(instructions)) {} + +DartSnapshot::~DartSnapshot() = default; + +bool DartSnapshot::IsValid() const { + return static_cast(data_); +} + +bool DartSnapshot::IsValidForAOT() const { + return data_ && instructions_; +} + +const DartSnapshotSource* DartSnapshot::GetData() const { + return data_.get(); +} + +const DartSnapshotSource* DartSnapshot::GetInstructions() const { + return instructions_.get(); +} + +const uint8_t* DartSnapshot::GetInstructionsIfPresent() const { + return instructions_ ? instructions_->GetSnapshotPointer() : nullptr; +} + +} // namespace blink diff --git a/runtime/dart_snapshot.h b/runtime/dart_snapshot.h new file mode 100644 index 0000000000000..0cf3c3ba31459 --- /dev/null +++ b/runtime/dart_snapshot.h @@ -0,0 +1,49 @@ +// Copyright 2017 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. + +#ifndef FLUTTER_RUNTIME_DART_SNAPSHOT_H_ +#define FLUTTER_RUNTIME_DART_SNAPSHOT_H_ + +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/runtime/dart_snapshot_source.h" +#include "lib/fxl/macros.h" + +namespace blink { + +class DartSnapshot { + public: + static std::unique_ptr VMSnapshotFromSettings( + const Settings& settings); + + static std::unique_ptr IsolateSnapshotFromSettings( + const Settings& settings); + + DartSnapshot(std::unique_ptr data, + std::unique_ptr instructions); + + ~DartSnapshot(); + + bool IsValid() const; + + bool IsValidForAOT() const; + + const DartSnapshotSource* GetData() const; + + const DartSnapshotSource* GetInstructions() const; + + const uint8_t* GetInstructionsIfPresent() const; + + private: + std::unique_ptr data_; + std::unique_ptr instructions_; + + FXL_DISALLOW_COPY_AND_ASSIGN(DartSnapshot); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_H_ diff --git a/runtime/dart_snapshot_source.cc b/runtime/dart_snapshot_source.cc new file mode 100644 index 0000000000000..9c3fb7d65cf0f --- /dev/null +++ b/runtime/dart_snapshot_source.cc @@ -0,0 +1,72 @@ +// Copyright 2017 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/runtime/dart_snapshot_source.h" + +#include + +#include "flutter/fml/mapping.h" + +namespace blink { + +class NativeLibrarySnapshotSource final : public DartSnapshotSource { + public: + NativeLibrarySnapshotSource(fxl::RefPtr library, + const char* symbol_name) + : library_(std::move(library)) { + if (library_) { + symbol_ = library_->ResolveSymbol(symbol_name); + } + } + + const uint8_t* GetSnapshotPointer() const override { return symbol_; } + + size_t GetSnapshotSize() const override { return 0; } + + private: + fxl::RefPtr library_; + const uint8_t* symbol_ = nullptr; + + FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrarySnapshotSource); +}; + +class FileSnapshotSource final : public DartSnapshotSource { + public: + FileSnapshotSource(const char* path, bool executable) + : mapping_(path, executable) { + if (mapping_.GetSize() > 0) { + symbol_ = mapping_.GetMapping(); + } + } + + const uint8_t* GetSnapshotPointer() const override { return symbol_; } + + size_t GetSnapshotSize() const override { return mapping_.GetSize(); } + + private: + fml::FileMapping mapping_; + const uint8_t* symbol_ = nullptr; + + FXL_DISALLOW_COPY_AND_ASSIGN(FileSnapshotSource); +}; + +std::unique_ptr +DartSnapshotSource::CreateWithSymbolInLibrary( + fxl::RefPtr library, + const char* symbol_name) { + auto source = std::make_unique( + std::move(library), symbol_name); + return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); +} + +std::unique_ptr +DartSnapshotSource::CreateWithContentsOfFile(const char* file_path, + bool executable) { + auto source = std::make_unique(file_path, executable); + return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); +} + +DartSnapshotSource::~DartSnapshotSource() = default; + +} // namespace blink diff --git a/runtime/dart_snapshot_source.h b/runtime/dart_snapshot_source.h new file mode 100644 index 0000000000000..8a2cb5d3f4f57 --- /dev/null +++ b/runtime/dart_snapshot_source.h @@ -0,0 +1,34 @@ +// Copyright 2017 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. + +#ifndef FLUTTER_RUNTIME_DART_SNAPSHOT_SOURCE_H_ +#define FLUTTER_RUNTIME_DART_SNAPSHOT_SOURCE_H_ + +#include + +#include "flutter/fml/native_library.h" +#include "lib/fxl/macros.h" + +namespace blink { + +class DartSnapshotSource { + public: + static std::unique_ptr CreateWithSymbolInLibrary( + fxl::RefPtr library, + const char* symbol_name); + + static std::unique_ptr CreateWithContentsOfFile( + const char* file_path, + bool executable); + + virtual ~DartSnapshotSource(); + + virtual const uint8_t* GetSnapshotPointer() const = 0; + + virtual size_t GetSnapshotSize() const = 0; +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_SOURCE_H_ diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc new file mode 100644 index 0000000000000..b874bab199b8e --- /dev/null +++ b/runtime/dart_vm.cc @@ -0,0 +1,433 @@ +// Copyright 2017 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/runtime/dart_vm.h" + +#include + +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/fml/trace_event.h" +#include "flutter/lib/io/dart_io.h" +#include "flutter/lib/ui/dart_runtime_hooks.h" +#include "flutter/lib/ui/dart_ui.h" +#include "flutter/runtime/dart_isolate.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "flutter/runtime/start_up.h" +#include "lib/fxl/arraysize.h" +#include "lib/fxl/compiler_specific.h" +#include "lib/fxl/logging.h" +#include "lib/fxl/time/time_delta.h" +#include "lib/tonic/converter/dart_converter.h" +#include "lib/tonic/dart_class_library.h" +#include "lib/tonic/dart_class_provider.h" +#include "lib/tonic/dart_sticky_error.h" +#include "lib/tonic/file_loader/file_loader.h" +#include "lib/tonic/logging/dart_error.h" +#include "lib/tonic/scopes/dart_api_scope.h" +#include "lib/tonic/typed_data/uint8_list.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" + +namespace dart { +namespace observatory { + +#if !OS(FUCHSIA) && (FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE) + +// These two symbols are defined in |observatory_archive.cc| which is generated +// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. +// Both of these symbols will be part of the data segment and therefore are read +// only. +extern unsigned int observatory_assets_archive_len; +extern const uint8_t* observatory_assets_archive; + +#endif // FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE + +} // namespace observatory +} // namespace dart + +namespace blink { + +// Arguments passed to the Dart VM in all configurations. +static const char* kDartLanguageArgs[] = { + "--enable_mirrors=false", + "--background_compilation", + "--await_is_keyword", + "--causal_async_stacks", +}; + +static const char* kDartPrecompilationArgs[] = { + "--precompilation", +}; + +FXL_ALLOW_UNUSED_TYPE +static const char* kDartWriteProtectCodeArgs[] = { + "--no_write_protect_code", +}; + +static const char* kDartAssertArgs[] = { + // clang-format off + "--enable_asserts", + // clang-format on +}; + +static const char* kDartCheckedModeArgs[] = { + // clang-format off + "--enable_type_checks", + "--error_on_bad_type", + "--error_on_bad_override", + // clang-format on +}; + +static const char* kDartStrongModeArgs[] = { + // clang-format off + "--strong", + "--reify_generic_functions", + "--limit_ints_to_64_bits", + // clang-format on +}; + +static const char* kDartStartPausedArgs[]{ + "--pause_isolates_on_start", +}; + +static const char* kDartTraceStartupArgs[]{ + "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", +}; + +static const char* kDartEndlessTraceBufferArgs[]{ + "--timeline_recorder=endless", +}; + +static const char* kDartFuchsiaTraceArgs[] FXL_ALLOW_UNUSED_TYPE = { + "--systrace_timeline", + "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", +}; + +constexpr char kFileUriPrefix[] = "file://"; +constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; + +bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { + if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) { + // Assume modified. + return true; + } + + const char* path = source_url + kFileUriPrefixLength; + struct stat info; + if (stat(path, &info) < 0) + return true; + + // If st_mtime is zero, it's more likely that the file system doesn't support + // mtime than that the file was actually modified in the 1970s. + if (!info.st_mtime) + return true; + + // It's very unclear what time bases we're with here. The Dart API doesn't + // document the time base for since_ms. Reading the code, the value varies by + // platform, with a typical source being something like gettimeofday. + // + // We add one to st_mtime because st_mtime has less precision than since_ms + // and we want to treat the file as modified if the since time is between + // ticks of the mtime. + fxl::TimeDelta mtime = fxl::TimeDelta::FromSeconds(info.st_mtime + 1); + fxl::TimeDelta since = fxl::TimeDelta::FromMilliseconds(since_ms); + + return mtime > since; +} + +void ThreadExitCallback() {} + +Dart_Handle GetVMServiceAssetsArchiveCallback() { +#if OS(FUCHSIA) || (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE) + return nullptr; +#else // FLUTTER_RUNTIME_MODE + return tonic::DartConverter::ToDart( + ::dart::observatory::observatory_assets_archive, + ::dart::observatory::observatory_assets_archive_len); +#endif // FLUTTER_RUNTIME_MODE +} + +static const char kStdoutStreamId[] = "Stdout"; +static const char kStderrStreamId[] = "Stderr"; + +static bool ServiceStreamListenCallback(const char* stream_id) { + if (strcmp(stream_id, kStdoutStreamId) == 0) { + dart::bin::SetCaptureStdout(true); + return true; + } else if (strcmp(stream_id, kStderrStreamId) == 0) { + dart::bin::SetCaptureStderr(true); + return true; + } + return false; +} + +static void ServiceStreamCancelCallback(const char* stream_id) { + if (strcmp(stream_id, kStdoutStreamId) == 0) { + dart::bin::SetCaptureStdout(false); + } else if (strcmp(stream_id, kStderrStreamId) == 0) { + dart::bin::SetCaptureStderr(false); + } +} + +bool DartVM::IsRunningPrecompiledCode() { + return Dart_IsPrecompiledRuntime(); +} + +static std::vector ProfilingFlags(bool enable_profiling) { +// Disable Dart's built in profiler when building a debug build. This +// works around a race condition that would sometimes stop a crash's +// stack trace from being printed on Android. +#ifndef NDEBUG + enable_profiling = false; +#endif + + // We want to disable profiling by default because it overwhelms LLDB. But + // the VM enables the same by default. In either case, we have some profiling + // flags. + if (enable_profiling) { + return { + // Dart assumes ARM devices are insufficiently powerful and sets the + // default profile period to 100Hz. This number is suitable for older + // Raspberry Pi devices but quite low for current smartphones. + "--profile_period=1000", + // This is the default. But just be explicit. + "--profiler", + // This instructs the profiler to walk C++ frames, and to include + // them in the profile. + "--profile-vm"}; + } else { + return {"--no-profiler"}; + } +} + +void PushBackAll(std::vector* args, + const char** argv, + size_t argc) { + for (size_t i = 0; i < argc; ++i) { + args->push_back(argv[i]); + } +} + +static void EmbedderInformationCallback(Dart_EmbedderInformation* info) { + info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION; + dart::bin::GetIOEmbedderInformation(info); + info->name = "Flutter"; +} + +std::once_flag gVMInitialization; +static fxl::RefPtr gVM; + +fxl::RefPtr DartVM::ForProcess(Settings settings) { + std::call_once(gVMInitialization, + [settings]() { gVM = fxl::MakeRefCounted(settings); }); + return gVM; +} + +fxl::RefPtr DartVM::ForProcessIfInitialized() { + return gVM; +} + +DartVM::DartVM(const Settings& settings) + : settings_(settings), + vm_snapshot_(DartSnapshot::VMSnapshotFromSettings(settings)), + isolate_snapshot_(DartSnapshot::IsolateSnapshotFromSettings(settings)), + platform_kernel_mapping_( + std::make_unique(settings.kernel_snapshot_path)), + weak_factory_(this) { + TRACE_EVENT0("flutter", "DartVMInitializer"); + + FXL_DCHECK(vm_snapshot_ && vm_snapshot_->IsValid()) + << "VM snapshot must be valid."; + + FXL_DCHECK(isolate_snapshot_ && isolate_snapshot_->IsValid()) + << "Isolate snapshot must be valid."; + + if (platform_kernel_mapping_->GetSize() > 0) { + // The platform kernel mapping lifetime is managed by this instance of the + // DartVM and hence will exceed that of the PlatformKernel. So provide an + // empty release callback. + Dart_ReleaseBufferCallback empty = [](auto arg) {}; + platform_kernel_ = reinterpret_cast(Dart_ReadKernelBinary( + platform_kernel_mapping_->GetMapping(), // buffer + platform_kernel_mapping_->GetSize(), // buffer size + empty // buffer deleter + )); + } + + { + TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo"); + dart::bin::BootstrapDartIo(); + + if (!settings.temp_directory_path.empty()) { + dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str()); + } + } + + std::vector args; + + // Instruct the VM to ignore unrecognized flags. + // There is a lot of diversity in a lot of combinations when it + // comes to the arguments the VM supports. And, if the VM comes across a flag + // it does not recognize, it exits immediately. + args.push_back("--ignore-unrecognized-flags"); + + for (const auto& profiler_flag : + ProfilingFlags(settings.enable_dart_profiling)) { + args.push_back(profiler_flag); + } + + PushBackAll(&args, kDartLanguageArgs, arraysize(kDartLanguageArgs)); + + if (IsRunningPrecompiledCode()) { + PushBackAll(&args, kDartPrecompilationArgs, + arraysize(kDartPrecompilationArgs)); + } + +#if defined(OS_FUCHSIA) && defined(NDEBUG) + // Do not enable checked mode for Fuchsia release builds + // TODO(mikejurka): remove this once precompiled code is working on Fuchsia + const bool use_checked_mode = false; +#else + // Enable checked mode if we are not running precompiled code. We run non- + // precompiled code only in the debug product mode. + const bool use_checked_mode = + !IsRunningPrecompiledCode() && !settings.dart_non_checked_mode; +#endif + +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + // Debug mode uses the JIT, disable code page write protection to avoid + // memory page protection changes before and after every compilation. + PushBackAll(&args, kDartWriteProtectCodeArgs, + arraysize(kDartWriteProtectCodeArgs)); +#endif + + const bool is_preview_dart2 = + platform_kernel_ != nullptr || + Dart_IsDart2Snapshot(isolate_snapshot_->GetData()->GetSnapshotPointer()); + + if (is_preview_dart2) { + FXL_DLOG(INFO) << "Dart 2 is enabled."; + } else { + FXL_DLOG(INFO) << "Dart 2 is NOT enabled."; + } + + if (is_preview_dart2) { + PushBackAll(&args, kDartStrongModeArgs, arraysize(kDartStrongModeArgs)); + if (use_checked_mode) { + PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); + } + } else if (use_checked_mode) { + PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); + PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs)); + } + + if (settings.start_paused) { + PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs)); + } + + if (settings.endless_trace_buffer || settings.trace_startup) { + // If we are tracing startup, make sure the trace buffer is endless so we + // don't lose early traces. + PushBackAll(&args, kDartEndlessTraceBufferArgs, + arraysize(kDartEndlessTraceBufferArgs)); + } + + if (settings.trace_startup) { + PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs)); + } + +#if defined(OS_FUCHSIA) + PushBackAll(&args, kDartFuchsiaTraceArgs, arraysize(kDartFuchsiaTraceArgs)); +#endif + + for (size_t i = 0; i < settings.dart_flags.size(); i++) + args.push_back(settings.dart_flags[i].c_str()); + + FXL_CHECK(Dart_SetVMFlags(args.size(), args.data())); + + DartUI::InitForGlobal(); + + { + TRACE_EVENT0("flutter", "Dart_Initialize"); + Dart_InitializeParams params = {}; + params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; + params.vm_snapshot_data = vm_snapshot_->GetData()->GetSnapshotPointer(); + params.vm_snapshot_instructions = vm_snapshot_->GetInstructionsIfPresent(); + params.create = reinterpret_cast( + DartIsolate::DartIsolateCreateCallback); + params.shutdown = reinterpret_cast( + DartIsolate::DartIsolateShutdownCallback); + params.cleanup = reinterpret_cast( + DartIsolate::DartIsolateCleanupCallback); + params.thread_exit = ThreadExitCallback; + params.get_service_assets = GetVMServiceAssetsArchiveCallback; + params.entropy_source = DartIO::EntropySource; + char* init_error = Dart_Initialize(¶ms); + if (init_error) { + FXL_LOG(FATAL) << "Error while initializing the Dart VM: " << init_error; + ::free(init_error); + } + // Send the earliest available timestamp in the application lifecycle to + // timeline. The difference between this timestamp and the time we render + // the very first frame gives us a good idea about Flutter's startup time. + // Use a duration event so about:tracing will consider this event when + // deciding the earliest event to use as time 0. + if (blink::engine_main_enter_ts != 0) { + Dart_TimelineEvent("FlutterEngineMainEnter", // label + blink::engine_main_enter_ts, // timestamp0 + blink::engine_main_enter_ts, // timestamp1_or_async_id + Dart_Timeline_Event_Duration, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values + ); + } + } + + // Allow streaming of stdout and stderr by the Dart vm. + Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback, + &ServiceStreamCancelCallback); + + Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); +} + +DartVM::~DartVM() { + if (Dart_CurrentIsolate() != nullptr) { + Dart_ExitIsolate(); + } + char* result = Dart_Cleanup(); + if (result != nullptr) { + FXL_LOG(ERROR) << "Could not cleanly shut down the Dart VM. Message: \"" + << result << "\"."; + free(result); + } +} + +const Settings& DartVM::GetSettings() const { + return settings_; +} + +DartVM::PlatformKernel* DartVM::GetPlatformKernel() const { + return platform_kernel_; +} + +const DartSnapshot& DartVM::GetVMSnapshot() const { + return *vm_snapshot_.get(); +} + +const DartSnapshot& DartVM::GetIsolateSnapshot() const { + return *isolate_snapshot_.get(); +} + +ServiceProtocol& DartVM::GetServiceProtocol() { + return service_protocol_; +} + +fxl::WeakPtr DartVM::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +} // namespace blink diff --git a/runtime/dart_vm.h b/runtime/dart_vm.h new file mode 100644 index 0000000000000..53af941cf998c --- /dev/null +++ b/runtime/dart_vm.h @@ -0,0 +1,69 @@ +// Copyright 2017 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. + +#ifndef FLUTTER_RUNTIME_DART_VM_H_ +#define FLUTTER_RUNTIME_DART_VM_H_ + +#include +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/runtime/dart_isolate.h" +#include "flutter/runtime/dart_snapshot.h" +#include "flutter/runtime/service_protocol.h" +#include "lib/fxl/build_config.h" +#include "lib/fxl/functional/closure.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/ref_counted.h" +#include "lib/fxl/memory/ref_ptr.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace blink { + +class DartVM : public fxl::RefCountedThreadSafe { + public: + class PlatformKernel; + + FXL_WARN_UNUSED_RESULT + static fxl::RefPtr ForProcess(Settings settings); + + static fxl::RefPtr ForProcessIfInitialized(); + + static bool IsRunningPrecompiledCode(); + + const Settings& GetSettings() const; + + PlatformKernel* GetPlatformKernel() const; + + const DartSnapshot& GetVMSnapshot() const; + + const DartSnapshot& GetIsolateSnapshot() const; + + fxl::WeakPtr GetWeakPtr(); + + ServiceProtocol& GetServiceProtocol(); + + private: + const Settings settings_; + const std::unique_ptr vm_snapshot_; + const std::unique_ptr isolate_snapshot_; + std::unique_ptr platform_kernel_mapping_; + PlatformKernel* platform_kernel_ = nullptr; + ServiceProtocol service_protocol_; + fxl::WeakPtrFactory weak_factory_; + + DartVM(const Settings& settings); + + ~DartVM(); + + FRIEND_REF_COUNTED_THREAD_SAFE(DartVM); + FRIEND_MAKE_REF_COUNTED(DartVM); + FXL_DISALLOW_COPY_AND_ASSIGN(DartVM); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_VM_H_ diff --git a/runtime/dart_vm_unittests.cc b/runtime/dart_vm_unittests.cc new file mode 100644 index 0000000000000..5b2f5e6ee8299 --- /dev/null +++ b/runtime/dart_vm_unittests.cc @@ -0,0 +1,21 @@ +// Copyright 2017 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/runtime/dart_vm.h" +#include "gtest/gtest.h" + +namespace blink { + +TEST(DartVM, SimpleInitialization) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + ASSERT_EQ(vm, DartVM::ForProcess(settings)); + ASSERT_FALSE(DartVM::IsRunningPrecompiledCode()); + ASSERT_EQ(vm->GetPlatformKernel(), nullptr); +} + +} // namespace blink diff --git a/runtime/fixtures/simple_main.dart b/runtime/fixtures/simple_main.dart new file mode 100644 index 0000000000000..552dfbe344902 --- /dev/null +++ b/runtime/fixtures/simple_main.dart @@ -0,0 +1,7 @@ +// 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. + +void simple_main() { + print("Hello"); +} diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 75796cd68697e..13761be935558 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -4,192 +4,243 @@ #include "flutter/runtime/runtime_controller.h" +#include "flutter/fml/message_loop.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/window.h" -#include "flutter/runtime/dart_controller.h" #include "flutter/runtime/runtime_delegate.h" #include "lib/tonic/dart_message_handler.h" -using tonic::DartState; - namespace blink { -std::unique_ptr RuntimeController::Create( - RuntimeDelegate* client) { - return std::unique_ptr(new RuntimeController(client)); +RuntimeController::RuntimeController( + RuntimeDelegate& p_client, + const DartVM* p_vm, + TaskRunners p_task_runners, + fml::WeakPtr p_resource_context, + fxl::RefPtr p_unref_queue) + : RuntimeController(p_client, + p_vm, + std::move(p_task_runners), + std::move(p_resource_context), + std::move(p_unref_queue), + WindowData{/* default window data */}) {} + +RuntimeController::RuntimeController( + RuntimeDelegate& p_client, + const DartVM* p_vm, + TaskRunners p_task_runners, + fml::WeakPtr p_resource_context, + fxl::RefPtr p_unref_queue, + WindowData p_window_data) + : client_(p_client), + vm_(p_vm), + task_runners_(p_task_runners), + resource_context_(p_resource_context), + unref_queue_(p_unref_queue), + window_data_(std::move(p_window_data)), + root_isolate_( + DartIsolate::CreateRootIsolate(vm_, + task_runners_, + std::make_unique(this), + resource_context_, + unref_queue_)) { + root_isolate_->SetReturnCodeCallback([this](uint32_t code) { + root_isolate_return_code_ = {true, code}; + }); + if (auto window = GetWindowIfAvailable()) { + tonic::DartState::Scope scope(root_isolate_.get()); + window->DidCreateIsolate(); + if (!FlushRuntimeStateToIsolate()) { + FXL_DLOG(ERROR) << "Could not setup intial isolate state."; + } + } else { + FXL_DCHECK(false) << "RuntimeController created without window binding."; + } + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); +} + +RuntimeController::~RuntimeController() { + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + if (root_isolate_) { + root_isolate_->SetReturnCodeCallback(nullptr); + auto result = root_isolate_->Shutdown(); + if (!result) { + FXL_DLOG(ERROR) << "Could not shutdown the root isolate."; + } + root_isolate_ = {}; + } } -RuntimeController::RuntimeController(RuntimeDelegate* client) - : client_(client) {} - -RuntimeController::~RuntimeController() {} +std::unique_ptr RuntimeController::Clone() const { + return std::unique_ptr(new RuntimeController( + client_, // + vm_, // + task_runners_, // + resource_context_, // + unref_queue_, // + window_data_ // + )); +} -void RuntimeController::CreateDartController( - const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - int dirfd) { - FXL_DCHECK(!dart_controller_); +bool RuntimeController::FlushRuntimeStateToIsolate() { + return SetViewportMetrics(window_data_.viewport_metrics) && + SetLocale(window_data_.language_code, window_data_.country_code) && + SetSemanticsEnabled(window_data_.semantics_enabled); +} - dart_controller_.reset(new DartController()); - dart_controller_->CreateIsolateFor( - script_uri, isolate_snapshot_data, isolate_snapshot_instr, - std::make_unique(this, std::make_unique(this), - dirfd)); +bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { + window_data_.viewport_metrics = metrics; - UIDartState* dart_state = dart_controller_->dart_state(); - DartState::Scope scope(dart_state); - dart_state->window()->DidCreateIsolate(); - client_->DidCreateMainIsolate(dart_state->isolate()); + if (auto window = GetWindowIfAvailable()) { + window->UpdateWindowMetrics(metrics); + return true; + } + return false; +} - Window* window = GetWindow(); +bool RuntimeController::SetLocale(const std::string& language_code, + const std::string& country_code) { + window_data_.language_code = language_code; + window_data_.country_code = country_code; - window->UpdateLocale(language_code_, country_code_); + if (auto window = GetWindowIfAvailable()) { + window->UpdateLocale(window_data_.language_code, window_data_.country_code); + return true; + } - if (semantics_enabled_) - window->UpdateSemanticsEnabled(semantics_enabled_); + return false; } -void RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { - GetWindow()->UpdateWindowMetrics(metrics); -} +bool RuntimeController::SetUserSettingsData(const std::string& data) { + window_data_.user_settings_data = data; -void RuntimeController::SetLocale(const std::string& language_code, - const std::string& country_code) { - if (language_code_ == language_code && country_code_ == country_code) - return; + if (auto window = GetWindowIfAvailable()) { + window->UpdateUserSettingsData(window_data_.user_settings_data); + return true; + } - language_code_ = language_code; - country_code_ = country_code; - GetWindow()->UpdateLocale(language_code_, country_code_); + return false; } -void RuntimeController::SetUserSettingsData(const std::string& data) { - if (user_settings_data_ == data) - return; - user_settings_data_ = data; - GetWindow()->UpdateUserSettingsData(user_settings_data_); -} +bool RuntimeController::SetSemanticsEnabled(bool enabled) { + window_data_.semantics_enabled = enabled; + + if (auto window = GetWindowIfAvailable()) { + window->UpdateSemanticsEnabled(window_data_.semantics_enabled); + return true; + } -void RuntimeController::SetSemanticsEnabled(bool enabled) { - if (semantics_enabled_ == enabled) - return; - semantics_enabled_ = enabled; - GetWindow()->UpdateSemanticsEnabled(semantics_enabled_); + return false; } -void RuntimeController::BeginFrame(fxl::TimePoint frame_time) { - GetWindow()->BeginFrame(frame_time); +bool RuntimeController::BeginFrame(fxl::TimePoint frame_time) { + if (auto window = GetWindowIfAvailable()) { + window->BeginFrame(frame_time); + return true; + } + return false; } -void RuntimeController::NotifyIdle(int64_t deadline) { - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return; +bool RuntimeController::NotifyIdle(int64_t deadline) { + if (!root_isolate_) { + return false; } - DartState::Scope scope(dart_state); + + tonic::DartState::Scope scope(root_isolate_.get()); Dart_NotifyIdle(deadline); + return true; } -void RuntimeController::DispatchPlatformMessage( +bool RuntimeController::DispatchPlatformMessage( fxl::RefPtr message) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", "mode", - "basic"); - GetWindow()->DispatchPlatformMessage(std::move(message)); + if (auto window = GetWindowIfAvailable()) { + TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", + "mode", "basic"); + window->DispatchPlatformMessage(std::move(message)); + return true; + } + return false; } -void RuntimeController::DispatchPointerDataPacket( +bool RuntimeController::DispatchPointerDataPacket( const PointerDataPacket& packet) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", - "mode", "basic"); - GetWindow()->DispatchPointerDataPacket(packet); + if (auto window = GetWindowIfAvailable()) { + TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", + "mode", "basic"); + window->DispatchPointerDataPacket(packet); + return true; + } + return false; } -void RuntimeController::DispatchSemanticsAction(int32_t id, +bool RuntimeController::DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args) { TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode", "basic"); - GetWindow()->DispatchSemanticsAction(id, action, std::move(args)); + if (auto window = GetWindowIfAvailable()) { + window->DispatchSemanticsAction(id, action, std::move(args)); + return true; + } + return false; } -Window* RuntimeController::GetWindow() { - return dart_controller_->dart_state()->window(); +Window* RuntimeController::GetWindowIfAvailable() { + return root_isolate_ ? root_isolate_->window() : nullptr; } std::string RuntimeController::DefaultRouteName() { - return client_->DefaultRouteName(); + return client_.DefaultRouteName(); } void RuntimeController::ScheduleFrame() { - client_->ScheduleFrame(); + client_.ScheduleFrame(); } void RuntimeController::Render(Scene* scene) { - client_->Render(scene->takeLayerTree()); + client_.Render(scene->takeLayerTree()); } void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { - if (semantics_enabled_) - client_->UpdateSemantics(update->takeNodes()); + if (window_data_.semantics_enabled) { + client_.UpdateSemantics(update->takeNodes()); + } } void RuntimeController::HandlePlatformMessage( fxl::RefPtr message) { - client_->HandlePlatformMessage(std::move(message)); -} - -void RuntimeController::DidCreateSecondaryIsolate(Dart_Isolate isolate) { - client_->DidCreateSecondaryIsolate(isolate); -} - -void RuntimeController::DidShutdownMainIsolate() { - client_->DidShutdownMainIsolate(); + client_.HandlePlatformMessage(std::move(message)); } Dart_Port RuntimeController::GetMainPort() { - if (!dart_controller_) { - return ILLEGAL_PORT; - } - if (!dart_controller_->dart_state()) { - return ILLEGAL_PORT; - } - return dart_controller_->dart_state()->main_port(); + return root_isolate_ ? root_isolate_->main_port() : ILLEGAL_PORT; } std::string RuntimeController::GetIsolateName() { - if (!dart_controller_) { - return ""; - } - if (!dart_controller_->dart_state()) { - return ""; - } - return dart_controller_->dart_state()->debug_name(); + return root_isolate_ ? root_isolate_->debug_name() : ""; } bool RuntimeController::HasLivePorts() { - if (!dart_controller_) { + if (!root_isolate_) { return false; } - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return false; - } - DartState::Scope scope(dart_state); + tonic::DartState::Scope scope(root_isolate_.get()); return Dart_HasLivePorts(); } tonic::DartErrorHandleType RuntimeController::GetLastError() { - if (!dart_controller_) { - return tonic::kNoError; - } - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return tonic::kNoError; - } - return dart_state->message_handler().isolate_last_error(); + return root_isolate_ ? root_isolate_->message_handler().isolate_last_error() + : tonic::kNoError; +} + +fml::WeakPtr RuntimeController::GetRootIsolate() { + return root_isolate_; +} + +std::pair RuntimeController::GetRootIsolateReturnCode() { + return root_isolate_return_code_; } } // namespace blink diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 628bc699395c0..326c517f31db2 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -7,71 +7,108 @@ #include +#include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/window.h" +#include "flutter/runtime/dart_vm.h" #include "lib/fxl/macros.h" namespace blink { -class DartController; -class DartLibraryProvider; class Scene; class RuntimeDelegate; class View; class Window; -class RuntimeController : public WindowClient, public IsolateClient { +class RuntimeController final : public WindowClient { public: - static std::unique_ptr Create(RuntimeDelegate* client); + RuntimeController(RuntimeDelegate& client, + const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue); + ~RuntimeController(); - void CreateDartController(const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - int dirfd = -1); - DartController* dart_controller() const { return dart_controller_.get(); } + std::unique_ptr Clone() const; + + bool SetViewportMetrics(const ViewportMetrics& metrics); - void SetViewportMetrics(const ViewportMetrics& metrics); - void SetLocale(const std::string& language_code, + bool SetLocale(const std::string& language_code, const std::string& country_code); - void SetUserSettingsData(const std::string& data); - void SetSemanticsEnabled(bool enabled); - void BeginFrame(fxl::TimePoint frame_time); - void NotifyIdle(int64_t deadline); + bool SetUserSettingsData(const std::string& data); + + bool SetSemanticsEnabled(bool enabled); + + bool BeginFrame(fxl::TimePoint frame_time); + + bool NotifyIdle(int64_t deadline); - void DispatchPlatformMessage(fxl::RefPtr message); - void DispatchPointerDataPacket(const PointerDataPacket& packet); - void DispatchSemanticsAction(int32_t id, + bool DispatchPlatformMessage(fxl::RefPtr message); + + bool DispatchPointerDataPacket(const PointerDataPacket& packet); + + bool DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args); Dart_Port GetMainPort(); + std::string GetIsolateName(); + bool HasLivePorts(); + tonic::DartErrorHandleType GetLastError(); - private: - explicit RuntimeController(RuntimeDelegate* client); + fml::WeakPtr GetRootIsolate(); - Window* GetWindow(); + std::pair GetRootIsolateReturnCode(); + private: + struct WindowData { + ViewportMetrics viewport_metrics; + std::string language_code; + std::string country_code; + std::string user_settings_data = "{}"; + bool semantics_enabled = false; + }; + + RuntimeDelegate& client_; + const DartVM* vm_; + TaskRunners task_runners_; + fml::WeakPtr resource_context_; + fxl::RefPtr unref_queue_; + WindowData window_data_; + fml::WeakPtr root_isolate_; + std::pair root_isolate_return_code_ = {false, 0}; + + RuntimeController(RuntimeDelegate& client, + const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + WindowData data); + + Window* GetWindowIfAvailable(); + + bool FlushRuntimeStateToIsolate(); + + // |blink::WindowClient| std::string DefaultRouteName() override; + + // |blink::WindowClient| void ScheduleFrame() override; + + // |blink::WindowClient| void Render(Scene* scene) override; - void UpdateSemantics(SemanticsUpdate* update) override; - void HandlePlatformMessage(fxl::RefPtr message) override; - void DidCreateSecondaryIsolate(Dart_Isolate isolate) override; - void DidShutdownMainIsolate() override; + // |blink::WindowClient| + void UpdateSemantics(SemanticsUpdate* update) override; - RuntimeDelegate* client_; - std::string language_code_; - std::string country_code_; - std::string user_settings_data_ = "{}"; - bool semantics_enabled_ = false; - std::unique_ptr dart_controller_; + // |blink::WindowClient| + void HandlePlatformMessage(fxl::RefPtr message) override; FXL_DISALLOW_COPY_AND_ASSIGN(RuntimeController); }; diff --git a/runtime/runtime_delegate.cc b/runtime/runtime_delegate.cc index 6ec55c4c2e6a0..902672be06d8f 100644 --- a/runtime/runtime_delegate.cc +++ b/runtime/runtime_delegate.cc @@ -6,12 +6,6 @@ namespace blink { -RuntimeDelegate::~RuntimeDelegate() {} - -void RuntimeDelegate::DidCreateMainIsolate(Dart_Isolate isolate) {} - -void RuntimeDelegate::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} - -void RuntimeDelegate::DidShutdownMainIsolate() {} +RuntimeDelegate::~RuntimeDelegate() = default; } // namespace blink diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 36650fe7fb70b..c6d6c0a92b2b4 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -18,14 +18,14 @@ namespace blink { class RuntimeDelegate { public: virtual std::string DefaultRouteName() = 0; + virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; + virtual void Render(std::unique_ptr layer_tree) = 0; + virtual void UpdateSemantics(blink::SemanticsNodeUpdates update) = 0; - virtual void HandlePlatformMessage(fxl::RefPtr message) = 0; - virtual void DidCreateMainIsolate(Dart_Isolate isolate); - virtual void DidCreateSecondaryIsolate(Dart_Isolate isolate); - virtual void DidShutdownMainIsolate(); + virtual void HandlePlatformMessage(fxl::RefPtr message) = 0; protected: virtual ~RuntimeDelegate(); diff --git a/runtime/runtime_init.cc b/runtime/runtime_init.cc deleted file mode 100644 index eda66e5495aed..0000000000000 --- a/runtime/runtime_init.cc +++ /dev/null @@ -1,35 +0,0 @@ -// 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/runtime/runtime_init.h" - -#include "flutter/glue/trace_event.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/platform_impl.h" -#include "flutter/sky/engine/public/web/Sky.h" -#include "lib/fxl/logging.h" - -namespace blink { -namespace { - -PlatformImpl* g_platform_impl = nullptr; - -} // namespace - -void InitRuntime(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path) { - TRACE_EVENT0("flutter", "InitRuntime"); - - FXL_CHECK(!g_platform_impl); - g_platform_impl = new PlatformImpl(); - InitEngine(g_platform_impl); - InitDartVM(vm_snapshot_data, vm_snapshot_instructions, - default_isolate_snapshot_data, - default_isolate_snapshot_instructions, bundle_path); -} - -} // namespace blink diff --git a/runtime/runtime_init.h b/runtime/runtime_init.h deleted file mode 100644 index 515ae284e3460..0000000000000 --- a/runtime/runtime_init.h +++ /dev/null @@ -1,21 +0,0 @@ -// 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_RUNTIME_RUNTIME_INIT_H_ -#define FLUTTER_RUNTIME_RUNTIME_INIT_H_ - -#include -#include - -namespace blink { - -void InitRuntime(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path); - -} // namespace blink - -#endif // FLUTTER_RUNTIME_RUNTIME_INIT_H_ diff --git a/runtime/service_protocol.cc b/runtime/service_protocol.cc new file mode 100644 index 0000000000000..e3b7cc423fc7a --- /dev/null +++ b/runtime/service_protocol.cc @@ -0,0 +1,277 @@ +// Copyright 2017 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. + +#define RAPIDJSON_HAS_STDSTRING 1 + +#include "flutter/runtime/service_protocol.h" + +#include +#include +#include +#include + +#include "lib/fxl/synchronization/waitable_event.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace blink { + +const fxl::StringView ServiceProtocol::kScreenshotExtensionName = + "_flutter.screenshot"; +const fxl::StringView ServiceProtocol::kScreenshotSkpExtensionName = + "_flutter.screenshotSkp"; +const fxl::StringView ServiceProtocol::kRunInViewExtensionName = + "_flutter.runInView"; +const fxl::StringView ServiceProtocol::kFlushUIThreadTasksExtensionName = + "_flutter.flushUIThreadTasks"; +const fxl::StringView ServiceProtocol::kSetAssetBundlePathExtensionName = + "_flutter.setAssetBundlePath"; + +static constexpr fxl::StringView kViewIdPrefx = "_flutterView/"; +static constexpr fxl::StringView kListViewsExtensionName = "_flutter.listViews"; + +ServiceProtocol::ServiceProtocol() + : endpoints_({ + // Private + kListViewsExtensionName, + + // Public + kScreenshotExtensionName, + kScreenshotSkpExtensionName, + kRunInViewExtensionName, + kFlushUIThreadTasksExtensionName, + kSetAssetBundlePathExtensionName, + }) {} + +ServiceProtocol::~ServiceProtocol() { + ToggleHooks(false); +} + +void ServiceProtocol::AddHandler(Handler* handler) { + std::lock_guard lock(handlers_mutex_); + handlers_.emplace(handler); +} + +void ServiceProtocol::RemoveHandler(Handler* handler) { + std::lock_guard lock(handlers_mutex_); + handlers_.erase(handler); +} + +void ServiceProtocol::ToggleHooks(bool set) { + for (const auto& endpoint : endpoints_) { + Dart_RegisterRootServiceRequestCallback( + endpoint.data(), // method + &ServiceProtocol::HandleMessage, // callback + set ? this : nullptr // user data + ); + } +} + +static void WriteServerErrorResponse(rapidjson::Document& document, + const char* message) { + document.SetObject(); + document.AddMember("code", -32000, document.GetAllocator()); + rapidjson::Value message_value; + message_value.SetString(message, document.GetAllocator()); + document.AddMember("message", message_value, document.GetAllocator()); +} + +bool ServiceProtocol::HandleMessage(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + Handler::ServiceProtocolMap params; + for (intptr_t i = 0; i < num_params; i++) { + params[fxl::StringView{param_keys[i]}] = fxl::StringView{param_values[i]}; + } + +#ifndef NDEBUG + FXL_DLOG(INFO) << "Service protcol method: " << method; + FXL_DLOG(INFO) << "Arguments: " << params.size(); + for (intptr_t i = 0; i < num_params; i++) { + FXL_DLOG(INFO) << " " << i + 1 << ": " << param_keys[i] << " = " + << param_values[i]; + } +#endif // NDEBUG + + rapidjson::Document document; + bool result = HandleMessage(fxl::StringView{method}, // + params, // + static_cast(user_data), // + document // + ); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + *json_object = strndup(buffer.GetString(), buffer.GetSize()); + +#ifndef NDEBUG + FXL_DLOG(INFO) << "Response: " << *json_object; + FXL_DLOG(INFO) << "RPC Result: " << result; +#endif // NDEBUG + + return result; +} + +bool ServiceProtocol::HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + ServiceProtocol* service_protocol, + rapidjson::Document& response) { + if (service_protocol == nullptr) { + WriteServerErrorResponse(response, "Service protocol unavailable."); + return false; + } + + return service_protocol->HandleMessage(method, params, response); +} + +FXL_WARN_UNUSED_RESULT +static bool HandleMessageOnHandler( + ServiceProtocol::Handler* handler, + fxl::StringView method, + const ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& document) { + FXL_DCHECK(handler); + fxl::AutoResetWaitableEvent latch; + bool result = false; + fml::TaskRunner::RunNowOrPostTask( + handler->GetServiceProtocolHandlerTaskRunner(method), + [&latch, // + &result, // + &handler, // + &method, // + ¶ms, // + &document // + ]() { + result = + handler->HandleServiceProtocolMessage(method, params, document); + latch.Signal(); + }); + latch.Wait(); + return result; +} + +bool ServiceProtocol::HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + rapidjson::Document& response) const { + if (method == kListViewsExtensionName) { + // So far, this is the only built-in method that does not forward to the + // dynamic set of handlers. + return HandleListViewsMethod(response); + } + + std::lock_guard lock(handlers_mutex_); + + if (handlers_.size() == 0) { + WriteServerErrorResponse(response, + "There are no running service protocol handlers."); + return false; + } + + // Find the handler by its "viewId" in the params. + auto view_id_param_found = params.find(fxl::StringView{"viewId"}); + if (view_id_param_found != params.end()) { + auto handler = reinterpret_cast(std::stoull( + view_id_param_found->second.data() + kViewIdPrefx.size(), nullptr, 16)); + auto handler_found = handlers_.find(handler); + if (handler_found != handlers_.end()) { + return HandleMessageOnHandler(handler, method, params, response); + } + } + + // Handle legacy calls that do not specify a handler in their args. + // TODO(chinmaygarde): Deprecate these calls in the tools and remove these + // fallbacks. + if (method == kScreenshotExtensionName || + method == kScreenshotSkpExtensionName) { + return HandleMessageOnHandler(*handlers_.begin(), method, params, response); + } + + WriteServerErrorResponse( + response, + "Service protocol could not not handle or find a handler for the " + "requested method."); + return false; +} + +static std::string CreateFlutterViewID(intptr_t handler) { + std::stringstream stream; + stream << kViewIdPrefx << "0x" << std::hex << handler; + return stream.str(); +} + +static std::string CreateIsolateID(int64_t isolate) { + std::stringstream stream; + stream << "isolates/" << isolate; + return stream.str(); +} + +void ServiceProtocol::Handler::Description::Write( + Handler* handler, + rapidjson::Value& view, + rapidjson::MemoryPoolAllocator<>& allocator) const { + view.SetObject(); + view.AddMember("type", "FlutterView", allocator); + view.AddMember("id", CreateFlutterViewID(reinterpret_cast(handler)), + allocator); + if (isolate_port != 0) { + rapidjson::Value isolate(rapidjson::Type::kObjectType); + { + isolate.AddMember("type", "@Isolate", allocator); + isolate.AddMember("fixedId", true, allocator); + isolate.AddMember("id", CreateIsolateID(isolate_port), allocator); + isolate.AddMember("name", isolate_name, allocator); + isolate.AddMember("number", isolate_port, allocator); + } + view.AddMember("isolate", isolate, allocator); + } +} + +bool ServiceProtocol::HandleListViewsMethod( + rapidjson::Document& response) const { + // Collect handler descriptions on their respective task runners. + std::lock_guard lock(handlers_mutex_); + std::vector> descriptions; + for (const auto& handler : handlers_) { + fxl::AutoResetWaitableEvent latch; + Handler::Description description; + + fml::TaskRunner::RunNowOrPostTask( + handler->GetServiceProtocolHandlerTaskRunner( + kListViewsExtensionName), // task runner + [&latch, // + &description, // + &handler // + ]() { + description = handler->GetServiceProtocolDescription(); + latch.Signal(); + }); + latch.Wait(); + descriptions.emplace_back(std::make_pair( + reinterpret_cast(handler), std::move(description))); + } + + auto& allocator = response.GetAllocator(); + + // Construct the response objects. + response.SetObject(); + response.AddMember("type", "FlutterViewList", allocator); + + rapidjson::Value viewsList(rapidjson::Type::kArrayType); + for (const auto& description : descriptions) { + rapidjson::Value view(rapidjson::Type::kObjectType); + description.second.Write(reinterpret_cast(description.first), + view, allocator); + viewsList.PushBack(view, allocator); + } + + response.AddMember("views", viewsList, allocator); + + return true; +} + +} // namespace blink diff --git a/runtime/service_protocol.h b/runtime/service_protocol.h new file mode 100644 index 0000000000000..60427a2a01008 --- /dev/null +++ b/runtime/service_protocol.h @@ -0,0 +1,93 @@ +// Copyright 2017 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. + +#ifndef FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ +#define FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ + +#include +#include +#include +#include + +#include "flutter/fml/task_runner.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/strings/string_view.h" +#include "lib/fxl/synchronization/thread_annotations.h" +#include "third_party/rapidjson/rapidjson/document.h" + +namespace blink { + +class ServiceProtocol { + public: + static const fxl::StringView kScreenshotExtensionName; + static const fxl::StringView kScreenshotSkpExtensionName; + static const fxl::StringView kRunInViewExtensionName; + static const fxl::StringView kFlushUIThreadTasksExtensionName; + static const fxl::StringView kSetAssetBundlePathExtensionName; + + class Handler { + public: + struct Description { + int64_t isolate_port = 0 /* illegal port by default. */; + std::string isolate_name; + + void Write(Handler* handler, + rapidjson::Value& value, + rapidjson::MemoryPoolAllocator<>& allocator) const; + }; + + using ServiceProtocolMap = std::map; + + virtual fxl::RefPtr GetServiceProtocolHandlerTaskRunner( + fxl::StringView method) const = 0; + + virtual Description GetServiceProtocolDescription() const = 0; + + virtual bool HandleServiceProtocolMessage( + fxl::StringView method, // one if the extension names specified above. + const ServiceProtocolMap& params, + rapidjson::Document& response) = 0; + }; + + ServiceProtocol(); + + ~ServiceProtocol(); + + void ToggleHooks(bool set); + + void AddHandler(Handler* handler); + + void RemoveHandler(Handler* handler); + + private: + const std::set endpoints_; + mutable std::mutex handlers_mutex_; + std::set handlers_; + + FXL_WARN_UNUSED_RESULT + static bool HandleMessage(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + FXL_WARN_UNUSED_RESULT + static bool HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + ServiceProtocol* service_protocol, + rapidjson::Document& response); + FXL_WARN_UNUSED_RESULT + bool HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + rapidjson::Document& response) const; + + FXL_WARN_UNUSED_RESULT + bool HandleListViewsMethod(rapidjson::Document& response) const; + + FXL_DISALLOW_COPY_AND_ASSIGN(ServiceProtocol); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ From 31c5046641f68d56458a8286be49340686d34771 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Fri, 23 Mar 2018 16:15:33 -0700 Subject: [PATCH 2/3] Address PR comments. --- runtime/BUILD.gn | 4 +- runtime/dart_isolate.cc | 95 ++++++++++++++++++------------- runtime/dart_isolate.h | 27 ++++++--- runtime/dart_isolate_unittests.cc | 45 ++++++++------- runtime/dart_snapshot.cc | 50 ++++++++-------- runtime/dart_snapshot.h | 29 +++++----- runtime/dart_snapshot_buffer.cc | 72 +++++++++++++++++++++++ runtime/dart_snapshot_buffer.h | 34 +++++++++++ runtime/dart_vm.cc | 19 +++---- runtime/dart_vm.h | 6 +- runtime/runtime_controller.cc | 1 + runtime/service_protocol.cc | 2 +- 12 files changed, 258 insertions(+), 126 deletions(-) create mode 100644 runtime/dart_snapshot_buffer.cc create mode 100644 runtime/dart_snapshot_buffer.h diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 9c8478dabf76a..455d7e228168f 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -69,8 +69,8 @@ source_set("runtime") { "dart_service_isolate.h", "dart_snapshot.cc", "dart_snapshot.h", - "dart_snapshot_source.cc", - "dart_snapshot_source.h", + "dart_snapshot_buffer.cc", + "dart_snapshot_buffer.h", "dart_vm.cc", "dart_vm.h", "embedder_resources.cc", diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 99cae3b08eb6a..6475a2dd655dd 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -29,6 +29,7 @@ namespace blink { fml::WeakPtr DartIsolate::CreateRootIsolate( const DartVM* vm, + fxl::RefPtr isolate_snapshot, TaskRunners task_runners, std::unique_ptr window, fml::WeakPtr resource_context, @@ -45,14 +46,15 @@ fml::WeakPtr DartIsolate::CreateRootIsolate( // Since this is the root isolate, we fake a parent embedder data object. We // cannot use unique_ptr here because the destructor is private (since the // isolate lifecycle is entirely managed by the VM). - DartIsolate* root_embedder_data = - new DartIsolate(vm, // VM - task_runners, // task runners - std::move(resource_context), // resource context - std::move(unref_queue), // skia unref queue - advisory_script_uri, // advisory URI - advisory_script_entrypoint // advisory entrypoint - ); + auto root_embedder_data = std::make_unique( + vm, // VM + std::move(isolate_snapshot), // isolate snapshot + task_runners, // task runners + std::move(resource_context), // resource context + std::move(unref_queue), // skia unref queue + advisory_script_uri, // advisory URI + advisory_script_entrypoint // advisory entrypoint + ); std::tie(vm_isolate, embedder_isolate) = CreateDartVMAndEmbedderObjectPair( advisory_script_uri.c_str(), // advisory script URI @@ -60,12 +62,10 @@ fml::WeakPtr DartIsolate::CreateRootIsolate( nullptr, // package root nullptr, // package config flags, // flags - root_embedder_data, // parent embedder data + root_embedder_data.get(), // parent embedder data &error // error (out) ); - delete root_embedder_data; - if (error != nullptr) { free(error); } @@ -84,6 +84,7 @@ fml::WeakPtr DartIsolate::CreateRootIsolate( } DartIsolate::DartIsolate(const DartVM* vm, + fxl::RefPtr isolate_snapshot, TaskRunners task_runners, fml::WeakPtr resource_context, fxl::RefPtr unref_queue, @@ -98,7 +99,9 @@ DartIsolate::DartIsolate(const DartVM* vm, advisory_script_entrypoint, vm->GetSettings().log_tag), vm_(vm), + isolate_snapshot_(std::move(isolate_snapshot)), weak_factory_(this) { + FXL_DCHECK(isolate_snapshot_) << "Must contain a valid isolate snapshot."; weak_prototype_ = weak_factory_.GetWeakPtr(); if (vm_ == nullptr) { @@ -166,6 +169,9 @@ bool DartIsolate::Initialize(Dart_Isolate dart_isolate) { return true; } +// Updating thread names here does not change the underlying OS thread names. +// Instead, this is just additional metadata for the Observatory to show the +// thread name of the isolate. bool DartIsolate::UpdateThreadPoolNames() const { // TODO(chinmaygarde): This implementation does not account for multiple // shells sharing the same (or subset of) threads. @@ -500,17 +506,19 @@ static Dart_Isolate DartCreateAndStartServiceIsolate( return nullptr; } - blink::TaskRunners null_task_runners("io.flutter.vm-service", nullptr, - nullptr, nullptr, nullptr); + blink::TaskRunners null_task_runners( + "io.flutter." DART_VM_SERVICE_ISOLATE_NAME, nullptr, nullptr, nullptr, + nullptr); flags->load_vmservice_library = true; auto service_isolate = DartIsolate::CreateRootIsolate( - vm.get(), // vm - null_task_runners, // task runners - nullptr, // window - {}, // resource context - {}, // unref queue + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + null_task_runners, // task runners + nullptr, // window + {}, // resource context + {}, // unref queue advisory_script_uri == nullptr ? "" : advisory_script_uri, // script uri advisory_script_entrypoint == nullptr ? "" @@ -560,12 +568,12 @@ Dart_Isolate DartIsolate::DartIsolateCreateCallback( DartIsolate* parent_embedder_isolate, char** error) { if (parent_embedder_isolate == nullptr && - strcmp(advisory_script_uri, "vm-service") == 0) { + strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) { // The VM attempts to start the VM service for us on |Dart_Initialize|. In // such a case, the callback data will be null and the script URI will be - // "vm-service". In such cases, we just create the service isolate like - // normal but dont hold a reference to it at all. We also start this isolate - // since we will never again reference it from the engine. + // DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service + // isolate like normal but dont hold a reference to it at all. We also start + // this isolate since we will never again reference it from the engine. return DartCreateAndStartServiceIsolate(advisory_script_uri, // advisory_script_entrypoint, // package_root, // @@ -603,14 +611,15 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( // Create the native object on the embedder side. This object is deleted in // the cleanup callback. - auto embedder_isolate = - new DartIsolate(vm, // - parent_embedder_isolate->GetTaskRunners(), // - parent_embedder_isolate->GetResourceContext(), // - parent_embedder_isolate->GetSkiaUnrefQueue(), // - advisory_script_uri, // - advisory_script_entrypoint // - ); + auto embedder_isolate = std::make_unique( + vm, // + parent_embedder_isolate->GetIsolateSnapshot(), // + parent_embedder_isolate->GetTaskRunners(), // + parent_embedder_isolate->GetResourceContext(), // + parent_embedder_isolate->GetSkiaUnrefQueue(), // + advisory_script_uri, // + advisory_script_entrypoint // + ); // Create the Dart VM isolate and give it the embedder object as the baton. Dart_Isolate isolate = @@ -619,17 +628,19 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( advisory_script_entrypoint, // vm->GetPlatformKernel(), // flags, // - embedder_isolate, // + embedder_isolate.get(), // error // ) - : Dart_CreateIsolate( - advisory_script_uri, // - advisory_script_entrypoint, // - vm->GetIsolateSnapshot().GetData()->GetSnapshotPointer(), // - vm->GetIsolateSnapshot().GetInstructionsIfPresent(), // - flags, // - embedder_isolate, // - error // + : Dart_CreateIsolate(advisory_script_uri, // + advisory_script_entrypoint, // + embedder_isolate->GetIsolateSnapshot() + ->GetData() + ->GetSnapshotPointer(), // + embedder_isolate->GetIsolateSnapshot() + ->GetInstructionsIfPresent(), // + flags, // + embedder_isolate.get(), // + error // ); if (isolate == nullptr) { @@ -652,7 +663,7 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( // The ownership of the embedder object is controlled by the Dart VM. So the // only reference returned to the caller is weak. - return {isolate, embedder_isolate->GetWeakIsolatePtr()}; + return {isolate, embedder_isolate.release()->GetWeakIsolatePtr()}; } // |Dart_IsolateShutdownCallback| @@ -673,6 +684,10 @@ void DartIsolate::DartIsolateCleanupCallback(DartIsolate* embedder_isolate) { delete embedder_isolate; } +fxl::RefPtr DartIsolate::GetIsolateSnapshot() const { + return isolate_snapshot_; +} + fml::WeakPtr DartIsolate::GetWeakIsolatePtr() const { return weak_prototype_; } diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h index fb63ed5c0bc1f..ce06b56c54471 100644 --- a/runtime/dart_isolate.h +++ b/runtime/dart_isolate.h @@ -12,6 +12,7 @@ #include "flutter/fml/mapping.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/window.h" +#include "flutter/runtime/dart_snapshot.h" #include "lib/fxl/compiler_specific.h" #include "lib/fxl/macros.h" #include "lib/tonic/dart_state.h" @@ -32,8 +33,12 @@ class DartIsolate : public UIDartState { Shutdown, }; + // The root isolate of a Flutter application is special because it gets Window + // bindings. From the VM's perspective, this isolate is not special in any + // way. static fml::WeakPtr CreateRootIsolate( const DartVM* vm, + fxl::RefPtr isolate_snapshot, TaskRunners task_runners, std::unique_ptr window, fml::WeakPtr resource_context, @@ -42,6 +47,16 @@ class DartIsolate : public UIDartState { std::string advisory_script_entrypoint = "main", Dart_IsolateFlags* flags = nullptr); + DartIsolate(const DartVM* vm, + fxl::RefPtr isolate_snapshot, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint); + + ~DartIsolate() override; + Phase GetPhase() const; FXL_WARN_UNUSED_RESULT @@ -64,6 +79,8 @@ class DartIsolate : public UIDartState { const DartVM* GetDartVM() const; + fxl::RefPtr GetIsolateSnapshot() const; + fml::WeakPtr GetWeakIsolatePtr() const; private: @@ -84,19 +101,11 @@ class DartIsolate : public UIDartState { const DartVM* vm_ = nullptr; Phase phase_ = Phase::Unknown; + const fxl::RefPtr isolate_snapshot_; std::vector> shutdown_callbacks_; fml::WeakPtr weak_prototype_; fml::WeakPtrFactory weak_factory_; - DartIsolate(const DartVM* vm, - TaskRunners task_runners, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue, - std::string advisory_script_uri, - std::string advisory_script_entrypoint); - - ~DartIsolate() override; - FXL_WARN_UNUSED_RESULT bool Initialize(Dart_Isolate isolate); diff --git a/runtime/dart_isolate_unittests.cc b/runtime/dart_isolate_unittests.cc index 1a870fc96d7cb..d8f2e02382da1 100644 --- a/runtime/dart_isolate_unittests.cc +++ b/runtime/dart_isolate_unittests.cc @@ -29,13 +29,14 @@ TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { GetCurrentTaskRunner(), // GetCurrentTaskRunner() // ); - auto root_isolate = - DartIsolate::CreateRootIsolate(vm.get(), // vm - std::move(task_runners), // task runners - nullptr, // window - {}, // resource context - nullptr // unref qeueue - ); + auto root_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); ASSERT_TRUE(root_isolate); ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); ASSERT_TRUE(root_isolate->Shutdown()); @@ -53,13 +54,14 @@ TEST_F(DartIsolateTest, IsolateCanAssociateSnapshot) { GetCurrentTaskRunner(), // GetCurrentTaskRunner() // ); - auto root_isolate = - DartIsolate::CreateRootIsolate(vm.get(), // vm - std::move(task_runners), // task runners - nullptr, // window - {}, // resource context - nullptr // unref qeueue - ); + auto root_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); ASSERT_TRUE(root_isolate); ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( @@ -80,13 +82,14 @@ TEST_F(DartIsolateTest, CanResolveAndInvokeMethod) { GetCurrentTaskRunner(), // GetCurrentTaskRunner() // ); - auto root_isolate = - DartIsolate::CreateRootIsolate(vm.get(), // vm - std::move(task_runners), // task runners - nullptr, // window - {}, // resource context - nullptr // unref qeueue - ); + auto root_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); ASSERT_TRUE(root_isolate); ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( diff --git a/runtime/dart_snapshot.cc b/runtime/dart_snapshot.cc index c282da1e9d2de..a41c2e4b83cc6 100644 --- a/runtime/dart_snapshot.cc +++ b/runtime/dart_snapshot.cc @@ -9,7 +9,7 @@ #include "flutter/fml/native_library.h" #include "flutter/fml/paths.h" #include "flutter/fml/trace_event.h" -#include "flutter/runtime/dart_snapshot_source.h" +#include "flutter/runtime/dart_snapshot_buffer.h" #include "flutter/runtime/dart_vm.h" namespace blink { @@ -20,28 +20,28 @@ static const char* kIsolateDataSymbol = "kDartIsolateSnapshotData"; static const char* kIsolateInstructionsSymbol = "kDartIsolateSnapshotInstructions"; -static std::unique_ptr ResolveVMData( +static std::unique_ptr ResolveVMData( const Settings& settings) { if (settings.aot_snapshot_path.size() > 0) { auto path = fml::paths::JoinPaths( {settings.aot_snapshot_path, settings.aot_vm_snapshot_data_filename}); - if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( path.c_str(), false /* executable */)) { return source; } } auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotSource::CreateWithSymbolInLibrary(loaded_process, + return DartSnapshotBuffer::CreateWithSymbolInLibrary(loaded_process, kVMDataSymbol); } -static std::unique_ptr ResolveVMInstructions( +static std::unique_ptr ResolveVMInstructions( const Settings& settings) { if (settings.aot_snapshot_path.size() > 0) { auto path = fml::paths::JoinPaths( {settings.aot_snapshot_path, settings.aot_vm_snapshot_instr_filename}); - if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( path.c_str(), true /* executable */)) { return source; } @@ -50,41 +50,41 @@ static std::unique_ptr ResolveVMInstructions( if (settings.application_library_path.size() > 0) { auto library = fml::NativeLibrary::Create(settings.application_library_path.c_str()); - if (auto source = DartSnapshotSource::CreateWithSymbolInLibrary( + if (auto source = DartSnapshotBuffer::CreateWithSymbolInLibrary( library, kVMInstructionsSymbol)) { return source; } } auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotSource::CreateWithSymbolInLibrary(loaded_process, + return DartSnapshotBuffer::CreateWithSymbolInLibrary(loaded_process, kVMInstructionsSymbol); } -static std::unique_ptr ResolveIsolateData( +static std::unique_ptr ResolveIsolateData( const Settings& settings) { if (settings.aot_snapshot_path.size() > 0) { auto path = fml::paths::JoinPaths({settings.aot_snapshot_path, settings.aot_isolate_snapshot_data_filename}); - if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( path.c_str(), false /* executable */)) { return source; } } auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotSource::CreateWithSymbolInLibrary(loaded_process, + return DartSnapshotBuffer::CreateWithSymbolInLibrary(loaded_process, kIsolateDataSymbol); } -static std::unique_ptr ResolveIsolateInstructions( +static std::unique_ptr ResolveIsolateInstructions( const Settings& settings) { if (settings.aot_snapshot_path.size() > 0) { auto path = fml::paths::JoinPaths({settings.aot_snapshot_path, settings.aot_isolate_snapshot_instr_filename}); - if (auto source = DartSnapshotSource::CreateWithContentsOfFile( + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( path.c_str(), true /* executable */)) { return source; } @@ -93,23 +93,23 @@ static std::unique_ptr ResolveIsolateInstructions( if (settings.application_library_path.size() > 0) { auto library = fml::NativeLibrary::Create(settings.application_library_path.c_str()); - if (auto source = DartSnapshotSource::CreateWithSymbolInLibrary( + if (auto source = DartSnapshotBuffer::CreateWithSymbolInLibrary( library, kIsolateInstructionsSymbol)) { return source; } } auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotSource::CreateWithSymbolInLibrary( + return DartSnapshotBuffer::CreateWithSymbolInLibrary( loaded_process, kIsolateInstructionsSymbol); } -std::unique_ptr DartSnapshot::VMSnapshotFromSettings( +fxl::RefPtr DartSnapshot::VMSnapshotFromSettings( const Settings& settings) { TRACE_EVENT0("flutter", "DartSnapshot::VMSnapshotFromSettings"); auto snapshot = - std::make_unique(ResolveVMData(settings), // - ResolveVMInstructions(settings) // + fxl::MakeRefCounted(ResolveVMData(settings), // + ResolveVMInstructions(settings) // ); if (snapshot->IsValid()) { return snapshot; @@ -117,12 +117,12 @@ std::unique_ptr DartSnapshot::VMSnapshotFromSettings( return nullptr; } -std::unique_ptr DartSnapshot::IsolateSnapshotFromSettings( +fxl::RefPtr DartSnapshot::IsolateSnapshotFromSettings( const Settings& settings) { TRACE_EVENT0("flutter", "DartSnapshot::IsolateSnapshotFromSettings"); auto snapshot = - std::make_unique(ResolveIsolateData(settings), // - ResolveIsolateInstructions(settings) // + fxl::MakeRefCounted(ResolveIsolateData(settings), // + ResolveIsolateInstructions(settings) // ); if (snapshot->IsValid()) { return snapshot; @@ -130,8 +130,8 @@ std::unique_ptr DartSnapshot::IsolateSnapshotFromSettings( return nullptr; } -DartSnapshot::DartSnapshot(std::unique_ptr data, - std::unique_ptr instructions) +DartSnapshot::DartSnapshot(std::unique_ptr data, + std::unique_ptr instructions) : data_(std::move(data)), instructions_(std::move(instructions)) {} DartSnapshot::~DartSnapshot() = default; @@ -144,11 +144,11 @@ bool DartSnapshot::IsValidForAOT() const { return data_ && instructions_; } -const DartSnapshotSource* DartSnapshot::GetData() const { +const DartSnapshotBuffer* DartSnapshot::GetData() const { return data_.get(); } -const DartSnapshotSource* DartSnapshot::GetInstructions() const { +const DartSnapshotBuffer* DartSnapshot::GetInstructions() const { return instructions_.get(); } diff --git a/runtime/dart_snapshot.h b/runtime/dart_snapshot.h index 0cf3c3ba31459..dd97e25722ff1 100644 --- a/runtime/dart_snapshot.h +++ b/runtime/dart_snapshot.h @@ -9,38 +9,41 @@ #include #include "flutter/common/settings.h" -#include "flutter/runtime/dart_snapshot_source.h" +#include "flutter/runtime/dart_snapshot_buffer.h" #include "lib/fxl/macros.h" +#include "lib/fxl/memory/ref_counted.h" namespace blink { -class DartSnapshot { +class DartSnapshot : public fxl::RefCountedThreadSafe { public: - static std::unique_ptr VMSnapshotFromSettings( + static fxl::RefPtr VMSnapshotFromSettings( const Settings& settings); - static std::unique_ptr IsolateSnapshotFromSettings( + static fxl::RefPtr IsolateSnapshotFromSettings( const Settings& settings); - DartSnapshot(std::unique_ptr data, - std::unique_ptr instructions); - - ~DartSnapshot(); - bool IsValid() const; bool IsValidForAOT() const; - const DartSnapshotSource* GetData() const; + const DartSnapshotBuffer* GetData() const; - const DartSnapshotSource* GetInstructions() const; + const DartSnapshotBuffer* GetInstructions() const; const uint8_t* GetInstructionsIfPresent() const; private: - std::unique_ptr data_; - std::unique_ptr instructions_; + std::unique_ptr data_; + std::unique_ptr instructions_; + + DartSnapshot(std::unique_ptr data, + std::unique_ptr instructions); + + ~DartSnapshot(); + FRIEND_REF_COUNTED_THREAD_SAFE(DartSnapshot); + FRIEND_MAKE_REF_COUNTED(DartSnapshot); FXL_DISALLOW_COPY_AND_ASSIGN(DartSnapshot); }; diff --git a/runtime/dart_snapshot_buffer.cc b/runtime/dart_snapshot_buffer.cc new file mode 100644 index 0000000000000..c39233ac8334a --- /dev/null +++ b/runtime/dart_snapshot_buffer.cc @@ -0,0 +1,72 @@ +// Copyright 2017 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/runtime/dart_snapshot_buffer.h" + +#include + +#include "flutter/fml/mapping.h" + +namespace blink { + +class NativeLibrarySnapshotBuffer final : public DartSnapshotBuffer { + public: + NativeLibrarySnapshotBuffer(fxl::RefPtr library, + const char* symbol_name) + : library_(std::move(library)) { + if (library_) { + symbol_ = library_->ResolveSymbol(symbol_name); + } + } + + const uint8_t* GetSnapshotPointer() const override { return symbol_; } + + size_t GetSnapshotSize() const override { return 0; } + + private: + fxl::RefPtr library_; + const uint8_t* symbol_ = nullptr; + + FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrarySnapshotBuffer); +}; + +class FileSnapshotBuffer final : public DartSnapshotBuffer { + public: + FileSnapshotBuffer(const char* path, bool executable) + : mapping_(path, executable) { + if (mapping_.GetSize() > 0) { + symbol_ = mapping_.GetMapping(); + } + } + + const uint8_t* GetSnapshotPointer() const override { return symbol_; } + + size_t GetSnapshotSize() const override { return mapping_.GetSize(); } + + private: + fml::FileMapping mapping_; + const uint8_t* symbol_ = nullptr; + + FXL_DISALLOW_COPY_AND_ASSIGN(FileSnapshotBuffer); +}; + +std::unique_ptr +DartSnapshotBuffer::CreateWithSymbolInLibrary( + fxl::RefPtr library, + const char* symbol_name) { + auto source = std::make_unique( + std::move(library), symbol_name); + return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); +} + +std::unique_ptr +DartSnapshotBuffer::CreateWithContentsOfFile(const char* file_path, + bool executable) { + auto source = std::make_unique(file_path, executable); + return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); +} + +DartSnapshotBuffer::~DartSnapshotBuffer() = default; + +} // namespace blink diff --git a/runtime/dart_snapshot_buffer.h b/runtime/dart_snapshot_buffer.h new file mode 100644 index 0000000000000..675946c0ca63f --- /dev/null +++ b/runtime/dart_snapshot_buffer.h @@ -0,0 +1,34 @@ +// Copyright 2017 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. + +#ifndef FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ +#define FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ + +#include + +#include "flutter/fml/native_library.h" +#include "lib/fxl/macros.h" + +namespace blink { + +class DartSnapshotBuffer { + public: + static std::unique_ptr CreateWithSymbolInLibrary( + fxl::RefPtr library, + const char* symbol_name); + + static std::unique_ptr CreateWithContentsOfFile( + const char* file_path, + bool executable); + + virtual ~DartSnapshotBuffer(); + + virtual const uint8_t* GetSnapshotPointer() const = 0; + + virtual size_t GetSnapshotSize() const = 0; +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc index b874bab199b8e..7f5a351f95a2b 100644 --- a/runtime/dart_vm.cc +++ b/runtime/dart_vm.cc @@ -188,16 +188,11 @@ static std::vector ProfilingFlags(bool enable_profiling) { // the VM enables the same by default. In either case, we have some profiling // flags. if (enable_profiling) { - return { - // Dart assumes ARM devices are insufficiently powerful and sets the - // default profile period to 100Hz. This number is suitable for older - // Raspberry Pi devices but quite low for current smartphones. - "--profile_period=1000", - // This is the default. But just be explicit. - "--profiler", - // This instructs the profiler to walk C++ frames, and to include - // them in the profile. - "--profile-vm"}; + return {// This is the default. But just be explicit. + "--profiler", + // This instructs the profiler to walk C++ frames, and to include + // them in the profile. + "--profile-vm"}; } else { return {"--no-profiler"}; } @@ -418,8 +413,8 @@ const DartSnapshot& DartVM::GetVMSnapshot() const { return *vm_snapshot_.get(); } -const DartSnapshot& DartVM::GetIsolateSnapshot() const { - return *isolate_snapshot_.get(); +fxl::RefPtr DartVM::GetIsolateSnapshot() const { + return isolate_snapshot_; } ServiceProtocol& DartVM::GetServiceProtocol() { diff --git a/runtime/dart_vm.h b/runtime/dart_vm.h index 53af941cf998c..163a1756a840b 100644 --- a/runtime/dart_vm.h +++ b/runtime/dart_vm.h @@ -40,7 +40,7 @@ class DartVM : public fxl::RefCountedThreadSafe { const DartSnapshot& GetVMSnapshot() const; - const DartSnapshot& GetIsolateSnapshot() const; + fxl::RefPtr GetIsolateSnapshot() const; fxl::WeakPtr GetWeakPtr(); @@ -48,8 +48,8 @@ class DartVM : public fxl::RefCountedThreadSafe { private: const Settings settings_; - const std::unique_ptr vm_snapshot_; - const std::unique_ptr isolate_snapshot_; + const fxl::RefPtr vm_snapshot_; + const fxl::RefPtr isolate_snapshot_; std::unique_ptr platform_kernel_mapping_; PlatformKernel* platform_kernel_ = nullptr; ServiceProtocol service_protocol_; diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 13761be935558..d3e138c937f60 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -42,6 +42,7 @@ RuntimeController::RuntimeController( window_data_(std::move(p_window_data)), root_isolate_( DartIsolate::CreateRootIsolate(vm_, + vm_->GetIsolateSnapshot(), task_runners_, std::make_unique(this), resource_context_, diff --git a/runtime/service_protocol.cc b/runtime/service_protocol.cc index e3b7cc423fc7a..90f07d745f070 100644 --- a/runtime/service_protocol.cc +++ b/runtime/service_protocol.cc @@ -193,7 +193,7 @@ bool ServiceProtocol::HandleMessage(fxl::StringView method, WriteServerErrorResponse( response, - "Service protocol could not not handle or find a handler for the " + "Service protocol could not handle or find a handler for the " "requested method."); return false; } From b22a5b60c871a1142c98b7a22b70643fd45c5eb0 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 27 Mar 2018 11:42:59 -0700 Subject: [PATCH 3/3] Make sure only the root isolate gets an associated message loop. --- runtime/dart_isolate.cc | 27 +++++++++++++++++++-------- runtime/dart_isolate.h | 3 ++- runtime/dart_vm.cc | 11 ++++++++--- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 6475a2dd655dd..dafb0f805be8e 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -63,6 +63,7 @@ fml::WeakPtr DartIsolate::CreateRootIsolate( nullptr, // package config flags, // flags root_embedder_data.get(), // parent embedder data + true, // is root isolate &error // error (out) ); @@ -121,7 +122,7 @@ const DartVM* DartIsolate::GetDartVM() const { return vm_; } -bool DartIsolate::Initialize(Dart_Isolate dart_isolate) { +bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) { TRACE_EVENT0("flutter", "DartIsolate::Initialize"); if (phase_ != Phase::Uninitialized) { return false; @@ -150,10 +151,12 @@ bool DartIsolate::Initialize(Dart_Isolate dart_isolate) { tonic::DartIsolateScope scope(isolate()); - if (auto task_runner = GetTaskRunners().GetUITaskRunner()) { - // Isolates may not have any particular thread affinity. Only initialize the - // message handler if a task runner is explicitly specified. - message_handler().Initialize(task_runner); + if (is_root_isolate) { + if (auto task_runner = GetTaskRunners().GetUITaskRunner()) { + // Isolates may not have any particular thread affinity. Only initialize + // the message handler if a task runner is explicitly specified. + message_handler().Initialize(task_runner); + } } if (tonic::LogIfError( @@ -584,8 +587,15 @@ Dart_Isolate DartIsolate::DartIsolateCreateCallback( } return CreateDartVMAndEmbedderObjectPair( - advisory_script_uri, advisory_script_entrypoint, package_root, - package_config, flags, parent_embedder_isolate, error) + advisory_script_uri, // URI + advisory_script_entrypoint, // entrypoint + package_root, // package root + package_config, // package config + flags, // isolate flags + parent_embedder_isolate, // embedder data + false, // is root isolate + error // error + ) .first; } @@ -597,6 +607,7 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( const char* package_config, Dart_IsolateFlags* flags, DartIsolate* parent_embedder_isolate, + bool is_root_isolate, char** error) { TRACE_EVENT0("flutter", "DartIsolate::CreateDartVMAndEmbedderObjectPair"); if (parent_embedder_isolate == nullptr || @@ -648,7 +659,7 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( return {nullptr, {}}; } - if (!embedder_isolate->Initialize(isolate)) { + if (!embedder_isolate->Initialize(isolate, is_root_isolate)) { *error = strdup("Embedder could not initialize the Dart isolate."); FXL_DLOG(ERROR) << *error; return {nullptr, {}}; diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h index ce06b56c54471..13d573ebe333f 100644 --- a/runtime/dart_isolate.h +++ b/runtime/dart_isolate.h @@ -107,7 +107,7 @@ class DartIsolate : public UIDartState { fml::WeakPtrFactory weak_factory_; FXL_WARN_UNUSED_RESULT - bool Initialize(Dart_Isolate isolate); + bool Initialize(Dart_Isolate isolate, bool is_root_isolate); FXL_WARN_UNUSED_RESULT bool LoadLibraries(); @@ -135,6 +135,7 @@ class DartIsolate : public UIDartState { const char* package_config, Dart_IsolateFlags* flags, DartIsolate* parent_embedder_isolate, + bool is_root_isolate, char** error); // |Dart_IsolateShutdownCallback| diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc index 7f5a351f95a2b..33308860187c4 100644 --- a/runtime/dart_vm.cc +++ b/runtime/dart_vm.cc @@ -299,14 +299,19 @@ DartVM::DartVM(const Settings& settings) arraysize(kDartWriteProtectCodeArgs)); #endif - const bool is_preview_dart2 = - platform_kernel_ != nullptr || + const bool isolate_snapshot_is_dart_2 = Dart_IsDart2Snapshot(isolate_snapshot_->GetData()->GetSnapshotPointer()); + const bool is_preview_dart2 = + platform_kernel_ != nullptr || isolate_snapshot_is_dart_2; + if (is_preview_dart2) { FXL_DLOG(INFO) << "Dart 2 is enabled."; } else { - FXL_DLOG(INFO) << "Dart 2 is NOT enabled."; + FXL_DLOG(INFO) << "Dart 2 is NOT enabled. Platform kernel: " + << static_cast(platform_kernel_) + << " Isolate Snapshot is Dart 2: " + << isolate_snapshot_is_dart_2; } if (is_preview_dart2) {