mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add Observatory to sky dart_controller
- Bump Dart and Observatory DEPS to 45576 and 45565 respectively. - Include 'dart:io' in snapshot - Add 'dart:io' native bindings to sky bindings. - Initialize 'dart:io' in sky dart_controller. - Include Observatory and service isolate resources in build. - Bring up service isolate. - Start handle watcher isolate from service isolate (hides handle watcher isolate from debugger and Observatory). - Hook up debugger. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/1107803002
This commit is contained in:
parent
04dec88f74
commit
76da439f44
@ -30,6 +30,9 @@ source_set("bindings") {
|
||||
"scheduled_action.cc",
|
||||
"scheduled_action.h",
|
||||
]
|
||||
|
||||
defines = [ "DART_IO_SECURE_SOCKET_DISABLED" ]
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//dart/runtime/bin:libdart_withcore",
|
||||
@ -38,12 +41,14 @@ source_set("bindings") {
|
||||
"//sky/engine/platform:platform",
|
||||
"//sky/engine/tonic",
|
||||
"//sky/engine/wtf",
|
||||
"//dart/runtime/bin:embedded_dart_io",
|
||||
":generated_bindings",
|
||||
":snapshot_cc",
|
||||
]
|
||||
include_dirs = [
|
||||
"..",
|
||||
"$root_build_dir",
|
||||
rebase_path("//dart/runtime"),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "sky/engine/bindings/builtin.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "bin/io_natives.h"
|
||||
#include "dart/runtime/include/dart_api.h"
|
||||
#include "gen/sky/bindings/DartGlobal.h"
|
||||
#include "sky/engine/bindings/builtin_natives.h"
|
||||
@ -31,6 +32,7 @@ const LibraryDescriptor kBuiltinLibraries[] = {
|
||||
BuiltinNatives::NativeLookup},
|
||||
{"dart:sky", true, skySnapshotSymbolizer, skySnapshotResolver},
|
||||
{"dart:mojo.internal", true, MojoNativeSymbol, MojoNativeLookup},
|
||||
{"dart:io", true, dart::bin::IONativeSymbol, dart::bin::IONativeLookup },
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -18,6 +18,7 @@ class Builtin {
|
||||
kBuiltinLibrary,
|
||||
kSkyLibrary,
|
||||
kMojoInternalLibrary,
|
||||
kIOLibrary,
|
||||
kInvalidLibrary,
|
||||
};
|
||||
|
||||
|
||||
@ -87,7 +87,8 @@ static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) {
|
||||
return closure;
|
||||
}
|
||||
|
||||
static void InitDartInternal(Dart_Handle builtin_library) {
|
||||
static void InitDartInternal(Dart_Handle builtin_library,
|
||||
BuiltinNatives::IsolateType isolate_type) {
|
||||
Dart_Handle print = GetClosure(builtin_library, "_getPrintClosure");
|
||||
Dart_Handle timer = GetClosure(builtin_library, "_getCreateTimerClosure");
|
||||
|
||||
@ -96,35 +97,55 @@ static void InitDartInternal(Dart_Handle builtin_library) {
|
||||
DART_CHECK_VALID(Dart_SetField(
|
||||
internal_library, ToDart("_printClosure"), print));
|
||||
|
||||
Dart_Handle vm_hooks_name = ToDart("VMLibraryHooks");
|
||||
Dart_Handle vm_hooks = Dart_GetClass(internal_library, vm_hooks_name);
|
||||
DART_CHECK_VALID(vm_hooks);
|
||||
Dart_Handle timer_name = ToDart("timerFactory");
|
||||
DART_CHECK_VALID(Dart_SetField(vm_hooks, timer_name, timer));
|
||||
if (isolate_type == BuiltinNatives::MainIsolate) {
|
||||
Dart_Handle vm_hooks_name = ToDart("VMLibraryHooks");
|
||||
Dart_Handle vm_hooks = Dart_GetClass(internal_library, vm_hooks_name);
|
||||
DART_CHECK_VALID(vm_hooks);
|
||||
Dart_Handle timer_name = ToDart("timerFactory");
|
||||
DART_CHECK_VALID(Dart_SetField(vm_hooks, timer_name, timer));
|
||||
} else {
|
||||
CHECK(isolate_type == BuiltinNatives::DartIOIsolate);
|
||||
Dart_Handle io_lib = DartBuiltin::LookupLibrary("dart:io");
|
||||
Dart_Handle setup_hooks = Dart_NewStringFromCString("_setupHooks");
|
||||
DART_CHECK_VALID(Dart_Invoke(io_lib, setup_hooks, 0, NULL));
|
||||
Dart_Handle isolate_lib = DartBuiltin::LookupLibrary("dart:isolate");
|
||||
DART_CHECK_VALID(Dart_Invoke(isolate_lib, setup_hooks, 0, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
static void InitDartCore(Dart_Handle builtin) {
|
||||
static void InitDartCore(Dart_Handle builtin,
|
||||
BuiltinNatives::IsolateType isolate_type) {
|
||||
Dart_Handle get_base_url = GetClosure(builtin, "_getGetBaseURLClosure");
|
||||
Dart_Handle core_library = DartBuiltin::LookupLibrary("dart:core");
|
||||
DART_CHECK_VALID(Dart_SetField(core_library,
|
||||
ToDart("_uriBaseClosure"), get_base_url));
|
||||
}
|
||||
|
||||
static void InitDartAsync(Dart_Handle builtin_library) {
|
||||
Dart_Handle schedule_microtask =
|
||||
GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
|
||||
static void InitDartAsync(Dart_Handle builtin_library,
|
||||
BuiltinNatives::IsolateType isolate_type) {
|
||||
Dart_Handle schedule_microtask;
|
||||
if (isolate_type == BuiltinNatives::MainIsolate) {
|
||||
schedule_microtask =
|
||||
GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
|
||||
} else {
|
||||
CHECK(isolate_type == BuiltinNatives::DartIOIsolate);
|
||||
Dart_Handle isolate_lib = DartBuiltin::LookupLibrary("dart:isolate");
|
||||
Dart_Handle method_name =
|
||||
Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure");
|
||||
schedule_microtask = Dart_Invoke(isolate_lib, method_name, 0, NULL);
|
||||
}
|
||||
Dart_Handle async_library = DartBuiltin::LookupLibrary("dart:async");
|
||||
Dart_Handle set_schedule_microtask = ToDart("_setScheduleImmediateClosure");
|
||||
DART_CHECK_VALID(Dart_Invoke(async_library, set_schedule_microtask, 1,
|
||||
&schedule_microtask));
|
||||
}
|
||||
|
||||
void BuiltinNatives::Init() {
|
||||
void BuiltinNatives::Init(IsolateType isolate_type) {
|
||||
Dart_Handle builtin = Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
|
||||
DART_CHECK_VALID(builtin);
|
||||
InitDartInternal(builtin);
|
||||
InitDartCore(builtin);
|
||||
InitDartAsync(builtin);
|
||||
InitDartInternal(builtin, isolate_type);
|
||||
InitDartCore(builtin, isolate_type);
|
||||
InitDartAsync(builtin, isolate_type);
|
||||
}
|
||||
|
||||
// Implementation of native functions which are used for some
|
||||
@ -163,6 +184,7 @@ void ScheduleMicrotask(Dart_NativeArguments args) {
|
||||
if (LogIfError(closure) || !Dart_IsClosure(closure))
|
||||
return;
|
||||
DartState* dart_state = DartState::Current();
|
||||
CHECK(dart_state);
|
||||
Microtask::enqueueMicrotask(base::Bind(&ExecuteMicrotask,
|
||||
dart_state->GetWeakPtr(), DartValue::Create(dart_state, closure)));
|
||||
}
|
||||
@ -182,6 +204,7 @@ void Timer_create(Dart_NativeArguments args) {
|
||||
DART_CHECK_VALID(Dart_GetNativeBooleanArgument(args, 2, &repeating));
|
||||
|
||||
DOMDartState* state = DOMDartState::Current();
|
||||
CHECK(state);
|
||||
int timer_id = DOMTimer::install(state->document(),
|
||||
ScheduledAction::Create(state, closure),
|
||||
milliseconds,
|
||||
@ -194,6 +217,7 @@ void Timer_cancel(Dart_NativeArguments args) {
|
||||
DART_CHECK_VALID(Dart_GetNativeIntegerArgument(args, 0, &timer_id));
|
||||
|
||||
DOMDartState* state = DOMDartState::Current();
|
||||
CHECK(state);
|
||||
DOMTimer::removeByID(state->document(), timer_id);
|
||||
}
|
||||
|
||||
|
||||
@ -12,12 +12,17 @@ namespace blink {
|
||||
|
||||
class BuiltinNatives {
|
||||
public:
|
||||
enum IsolateType {
|
||||
MainIsolate,
|
||||
DartIOIsolate,
|
||||
};
|
||||
|
||||
static Dart_NativeFunction NativeLookup(Dart_Handle name,
|
||||
int argument_count,
|
||||
bool* auto_setup_scope);
|
||||
static const uint8_t* NativeSymbol(Dart_NativeFunction native_function);
|
||||
|
||||
static void Init();
|
||||
static void Init(IsolateType isolate_type);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(BuiltinNatives);
|
||||
|
||||
@ -6,6 +6,7 @@ import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:core';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:math';
|
||||
import 'dart:mojo.internal';
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import("//sky/engine/build/scripts/scripts.gni")
|
||||
import("//sky/engine/core/core.gni")
|
||||
import("//mojo/dart/embedder/embedder.gni")
|
||||
|
||||
visibility = [ "//sky/engine/*" ]
|
||||
|
||||
@ -52,20 +53,40 @@ source_set("prerequisites") {
|
||||
]
|
||||
}
|
||||
|
||||
dart_embedder_resources("generate_sky_embedder_service_isolate_resources_cc") {
|
||||
deps = [
|
||||
"//mojo/dart/embedder:deploy_observatory",
|
||||
]
|
||||
inputs = [
|
||||
"//sky/engine/core/script/dart_service_isolate/loader.dart",
|
||||
"//sky/engine/core/script/dart_service_isolate/main.dart",
|
||||
"//sky/engine/core/script/dart_service_isolate/resources.dart",
|
||||
"//sky/engine/core/script/dart_service_isolate/server.dart",
|
||||
]
|
||||
root_prefix = "//sky/engine/core/script/"
|
||||
input_directory = "$root_out_dir/observatory/deployed/web/"
|
||||
output = "$target_gen_dir/sky_embedder_service_isolate_resources.cc"
|
||||
table_name = "sky_embedder_service_isolate"
|
||||
}
|
||||
|
||||
static_library("core") {
|
||||
output_name = "sky_core"
|
||||
|
||||
deps = [
|
||||
":core_generated",
|
||||
":generate_sky_embedder_service_isolate_resources_cc",
|
||||
":libraries",
|
||||
":prerequisites",
|
||||
"//sky/engine/platform",
|
||||
"//sky/engine/bindings",
|
||||
"//dart/runtime/bin:embedded_dart_io",
|
||||
"//dart/runtime/bin:libdart_withcore",
|
||||
]
|
||||
|
||||
sources = sky_core_files
|
||||
|
||||
sources += [ "$target_gen_dir/sky_embedder_service_isolate_resources.cc" ]
|
||||
|
||||
include_dirs = [
|
||||
# Needed for dart_mirrors_api.h in dart_controller.cc
|
||||
rebase_path("//dart/runtime"),
|
||||
|
||||
@ -1009,12 +1009,17 @@ sky_core_files = [
|
||||
"rendering/VerticalPositionCache.h",
|
||||
"script/dart_controller.cc",
|
||||
"script/dart_controller.h",
|
||||
"script/dart_debugger.cc",
|
||||
"script/dart_debugger.h",
|
||||
"script/dart_dependency_catcher.cc",
|
||||
"script/dart_dependency_catcher.h",
|
||||
"script/dart_loader.cc",
|
||||
"script/dart_loader.h",
|
||||
"script/dart_service_isolate.cc",
|
||||
"script/dart_service_isolate.h",
|
||||
"script/dom_dart_state.cc",
|
||||
"script/dom_dart_state.h",
|
||||
"script/monitor.h",
|
||||
]
|
||||
|
||||
core_idl_files = get_path_info([
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "dart/runtime/bin/embedded_dart_io.h"
|
||||
#include "dart/runtime/include/dart_mirrors_api.h"
|
||||
#include "sky/engine/bindings/builtin.h"
|
||||
#include "sky/engine/bindings/builtin_natives.h"
|
||||
@ -21,8 +22,10 @@
|
||||
#include "sky/engine/core/html/imports/HTMLImport.h"
|
||||
#include "sky/engine/core/html/imports/HTMLImportChild.h"
|
||||
#include "sky/engine/core/loader/FrameLoaderClient.h"
|
||||
#include "sky/engine/core/script/dart_debugger.h"
|
||||
#include "sky/engine/core/script/dart_dependency_catcher.h"
|
||||
#include "sky/engine/core/script/dart_loader.h"
|
||||
#include "sky/engine/core/script/dart_service_isolate.h"
|
||||
#include "sky/engine/core/script/dom_dart_state.h"
|
||||
#include "sky/engine/public/platform/Platform.h"
|
||||
#include "sky/engine/tonic/dart_api_scope.h"
|
||||
@ -176,9 +179,36 @@ static bool IsServiceIsolateURL(const char* url_name) {
|
||||
String(url_name) == DART_VM_SERVICE_ISOLATE_NAME;
|
||||
}
|
||||
|
||||
static void EnsureHandleWatcherStarted() {
|
||||
static bool handle_watcher_started = false;
|
||||
if (handle_watcher_started)
|
||||
return;
|
||||
|
||||
// TODO(dart): Call Dart_Cleanup (ensure the handle watcher isolate is closed)
|
||||
// during shutdown.
|
||||
Dart_Handle mojo_core_lib =
|
||||
Builtin::LoadAndCheckLibrary(Builtin::kMojoInternalLibrary);
|
||||
CHECK(!LogIfError((mojo_core_lib)));
|
||||
Dart_Handle handle_watcher_type = Dart_GetType(
|
||||
mojo_core_lib,
|
||||
Dart_NewStringFromCString("MojoHandleWatcher"),
|
||||
0,
|
||||
nullptr);
|
||||
CHECK(!LogIfError(handle_watcher_type));
|
||||
CHECK(!LogIfError(Dart_Invoke(
|
||||
handle_watcher_type,
|
||||
Dart_NewStringFromCString("_start"),
|
||||
0,
|
||||
nullptr)));
|
||||
|
||||
// RunLoop until the handle watcher isolate is spun-up.
|
||||
CHECK(!LogIfError(Dart_RunLoop()));
|
||||
handle_watcher_started = true;
|
||||
}
|
||||
|
||||
// TODO(rafaelw): Right now this only supports the creation of the handle
|
||||
// watcher isolate. Presumably, we'll want application isolates to spawn their
|
||||
// own isolates.
|
||||
// watcher isolate and the service isolate. Presumably, we'll want application
|
||||
// isolates to spawn their own isolates.
|
||||
static Dart_Isolate IsolateCreateCallback(const char* script_uri,
|
||||
const char* main,
|
||||
const char* package_root,
|
||||
@ -186,8 +216,34 @@ static Dart_Isolate IsolateCreateCallback(const char* script_uri,
|
||||
char** error) {
|
||||
|
||||
if (IsServiceIsolateURL(script_uri)) {
|
||||
return Dart_CreateIsolate(script_uri, "main", kDartIsolateSnapshotBuffer,
|
||||
nullptr, error);
|
||||
CHECK(kDartIsolateSnapshotBuffer);
|
||||
DartState* dart_state = new DartState();
|
||||
Dart_Isolate isolate = Dart_CreateIsolate(script_uri,
|
||||
"main",
|
||||
kDartIsolateSnapshotBuffer,
|
||||
nullptr,
|
||||
error);
|
||||
CHECK(isolate) << error;
|
||||
dart_state->set_isolate(isolate);
|
||||
CHECK(Dart_IsServiceIsolate(isolate));
|
||||
CHECK(!LogIfError(Dart_SetLibraryTagHandler(LibraryTagHandler)));
|
||||
{
|
||||
DartApiScope apiScope;
|
||||
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
|
||||
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
|
||||
Builtin::SetNativeResolver(Builtin::kIOLibrary);
|
||||
BuiltinNatives::Init(BuiltinNatives::DartIOIsolate);
|
||||
// Start the handle watcher from the service isolate so it isn't available
|
||||
// for debugging or general Observatory interaction.
|
||||
EnsureHandleWatcherStarted();
|
||||
std::string ip = "127.0.0.1";
|
||||
const intptr_t port = 0; // Automatic port assignment.
|
||||
const bool service_isolate_booted =
|
||||
DartServiceIsolate::Startup(ip, port, LibraryTagHandler, error);
|
||||
CHECK(service_isolate_booted) << error;
|
||||
}
|
||||
Dart_ExitIsolate();
|
||||
return isolate;
|
||||
}
|
||||
|
||||
// Create & start the handle watcher isolate
|
||||
@ -204,6 +260,7 @@ static Dart_Isolate IsolateCreateCallback(const char* script_uri,
|
||||
DartApiScope apiScope;
|
||||
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
|
||||
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
|
||||
Builtin::SetNativeResolver(Builtin::kIOLibrary);
|
||||
|
||||
// Ensure the isolate has a root library.
|
||||
Dart_LoadScript(Dart_NewStringFromCString("dart:empty"),
|
||||
@ -233,33 +290,6 @@ static void MessageNotifyCallback(Dart_Isolate dest_isolate) {
|
||||
base::Bind(&CallHandleMessage, DartState::From(dest_isolate)->GetWeakPtr()));
|
||||
}
|
||||
|
||||
static void EnsureHandleWatcherStarted() {
|
||||
static bool handle_watcher_started = false;
|
||||
if (handle_watcher_started)
|
||||
return;
|
||||
|
||||
// TODO(dart): Call Dart_Cleanup (ensure the handle watcher isolate is closed)
|
||||
// during shutdown.
|
||||
Dart_Handle mojo_core_lib =
|
||||
Builtin::LoadAndCheckLibrary(Builtin::kMojoInternalLibrary);
|
||||
CHECK(!LogIfError((mojo_core_lib)));
|
||||
Dart_Handle handle_watcher_type = Dart_GetType(
|
||||
mojo_core_lib,
|
||||
Dart_NewStringFromCString("MojoHandleWatcher"),
|
||||
0,
|
||||
nullptr);
|
||||
CHECK(!LogIfError(handle_watcher_type));
|
||||
CHECK(!LogIfError(Dart_Invoke(
|
||||
handle_watcher_type,
|
||||
Dart_NewStringFromCString("_start"),
|
||||
0,
|
||||
nullptr)));
|
||||
|
||||
// RunLoop until the handle watcher isolate is spun-up.
|
||||
CHECK(!LogIfError(Dart_RunLoop()));
|
||||
handle_watcher_started = true;
|
||||
}
|
||||
|
||||
void DartController::CreateIsolateFor(Document* document) {
|
||||
DCHECK(document);
|
||||
CHECK(kDartIsolateSnapshotBuffer);
|
||||
@ -283,7 +313,8 @@ void DartController::CreateIsolateFor(Document* document) {
|
||||
|
||||
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
|
||||
Builtin::SetNativeResolver(Builtin::kMojoInternalLibrary);
|
||||
BuiltinNatives::Init();
|
||||
Builtin::SetNativeResolver(Builtin::kIOLibrary);
|
||||
BuiltinNatives::Init(BuiltinNatives::MainIsolate);
|
||||
|
||||
builtin_sky_ = adoptPtr(new BuiltinSky(dart_state()));
|
||||
dart_state()->class_library().set_provider(builtin_sky_.get());
|
||||
@ -312,13 +343,20 @@ void DartController::InitVM() {
|
||||
argv = kCheckedModeArgs;
|
||||
#endif
|
||||
|
||||
dart::bin::BootstrapDartIo();
|
||||
|
||||
CHECK(Dart_SetVMFlags(argc, argv));
|
||||
// This should be called before calling Dart_Initialize.
|
||||
DartDebugger::InitDebugger();
|
||||
CHECK(Dart_Initialize(kDartVmIsolateSnapshotBuffer,
|
||||
IsolateCreateCallback,
|
||||
nullptr, // Isolate interrupt callback.
|
||||
UnhandledExceptionCallback, IsolateShutdownCallback,
|
||||
// File IO callbacks.
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr));
|
||||
// Wait for load port- ensures handle watcher and service isolates are
|
||||
// running.
|
||||
Dart_ServiceWaitForLoadPort();
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
|
||||
138
engine/core/script/dart_debugger.cc
Normal file
138
engine/core/script/dart_debugger.cc
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 "sky/engine/core/script/dart_debugger.h"
|
||||
|
||||
#include "dart/runtime/include/dart_api.h"
|
||||
#include "dart/runtime/include/dart_debugger_api.h"
|
||||
#include "dart/runtime/include/dart_native_api.h"
|
||||
|
||||
|
||||
namespace blink {
|
||||
|
||||
void DartDebuggerIsolate::MessageLoop() {
|
||||
MonitorLocker ml(&monitor_);
|
||||
// Request notification on isolate messages. This allows us to
|
||||
// respond to vm service messages while at breakpoint.
|
||||
Dart_SetMessageNotifyCallback(DartDebugger::NotifyIsolate);
|
||||
while (true) {
|
||||
// Handle all available vm service messages, up to a resume
|
||||
// request.
|
||||
bool resume = false;
|
||||
while (!resume && Dart_HasServiceMessages()) {
|
||||
monitor_.Exit();
|
||||
resume = Dart_HandleServiceMessages();
|
||||
monitor_.Enter();
|
||||
}
|
||||
if (resume) {
|
||||
break;
|
||||
}
|
||||
ml.Wait();
|
||||
}
|
||||
Dart_SetMessageNotifyCallback(nullptr);
|
||||
}
|
||||
|
||||
void DartDebugger::BptResolvedHandler(Dart_IsolateId isolate_id,
|
||||
intptr_t bp_id,
|
||||
const Dart_CodeLocation& location) {
|
||||
// Nothing to do here. Service event is dispatched to let Observatory know
|
||||
// that a breakpoint was resolved.
|
||||
}
|
||||
|
||||
void DartDebugger::PausedEventHandler(Dart_IsolateId isolate_id,
|
||||
intptr_t bp_id,
|
||||
const Dart_CodeLocation& loc) {
|
||||
Dart_EnterScope();
|
||||
intptr_t isolate_index = FindIsolateIndexById(isolate_id);
|
||||
CHECK(isolate_index != -1);
|
||||
(*isolates_)[isolate_index]->MessageLoop();
|
||||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
void DartDebugger::ExceptionThrownHandler(Dart_IsolateId isolate_id,
|
||||
Dart_Handle exception,
|
||||
Dart_StackTrace stack_trace) {
|
||||
Dart_EnterScope();
|
||||
intptr_t isolate_index = FindIsolateIndexById(isolate_id);
|
||||
CHECK(isolate_index != -1);
|
||||
(*isolates_)[isolate_index]->MessageLoop();
|
||||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
void DartDebugger::IsolateEventHandler(Dart_IsolateId isolate_id,
|
||||
Dart_IsolateEvent kind) {
|
||||
Dart_EnterScope();
|
||||
if (kind == Dart_IsolateEvent::kCreated) {
|
||||
AddIsolate(isolate_id);
|
||||
} else {
|
||||
intptr_t isolate_index = FindIsolateIndexById(isolate_id);
|
||||
CHECK(isolate_index != -1);
|
||||
if (kind == Dart_IsolateEvent::kInterrupted) {
|
||||
(*isolates_)[isolate_index]->MessageLoop();
|
||||
} else {
|
||||
CHECK(kind == Dart_IsolateEvent::kShutdown);
|
||||
RemoveIsolate(isolate_id);
|
||||
}
|
||||
}
|
||||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
void DartDebugger::NotifyIsolate(Dart_Isolate isolate) {
|
||||
base::AutoLock al(*lock_);
|
||||
Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate);
|
||||
intptr_t isolate_index = FindIsolateIndexByIdLocked(isolate_id);
|
||||
if (isolate_index >= 0) {
|
||||
(*isolates_)[isolate_index]->Notify();
|
||||
}
|
||||
}
|
||||
|
||||
void DartDebugger::InitDebugger() {
|
||||
Dart_SetIsolateEventHandler(IsolateEventHandler);
|
||||
Dart_SetPausedEventHandler(PausedEventHandler);
|
||||
Dart_SetBreakpointResolvedHandler(BptResolvedHandler);
|
||||
Dart_SetExceptionThrownHandler(ExceptionThrownHandler);
|
||||
lock_ = new base::Lock();
|
||||
isolates_ = new std::vector<std::unique_ptr<DartDebuggerIsolate>>();
|
||||
}
|
||||
|
||||
intptr_t DartDebugger::FindIsolateIndexById(Dart_IsolateId id) {
|
||||
base::AutoLock al(*lock_);
|
||||
return FindIsolateIndexByIdLocked(id);
|
||||
}
|
||||
|
||||
intptr_t DartDebugger::FindIsolateIndexByIdLocked(
|
||||
Dart_IsolateId id) {
|
||||
lock_->AssertAcquired();
|
||||
for (size_t i = 0; i < isolates_->size(); i++) {
|
||||
if ((*isolates_)[i]->id() == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DartDebugger::AddIsolate(Dart_IsolateId id) {
|
||||
base::AutoLock al(*lock_);
|
||||
CHECK(FindIsolateIndexByIdLocked(id) == -1);
|
||||
std::unique_ptr<DartDebuggerIsolate> debugger_isolate =
|
||||
std::unique_ptr<DartDebuggerIsolate>(new DartDebuggerIsolate(id));
|
||||
isolates_->push_back(std::move(debugger_isolate));
|
||||
}
|
||||
|
||||
void DartDebugger::RemoveIsolate(Dart_IsolateId id) {
|
||||
base::AutoLock al(*lock_);
|
||||
for (size_t i = 0; i < isolates_->size(); i++) {
|
||||
if (id == (*isolates_)[i]->id()) {
|
||||
isolates_->erase(isolates_->begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
base::Lock* DartDebugger::lock_ = nullptr;
|
||||
std::vector<std::unique_ptr<DartDebuggerIsolate>>* DartDebugger::isolates_ =
|
||||
nullptr;
|
||||
|
||||
} // namespace blink
|
||||
81
engine/core/script/dart_debugger.h
Normal file
81
engine/core/script/dart_debugger.h
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SKY_ENGINE_CORE_SCRIPT_DART_DEBUGGER_H_
|
||||
#define SKY_ENGINE_CORE_SCRIPT_DART_DEBUGGER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "dart/runtime/include/dart_api.h"
|
||||
#include "dart/runtime/include/dart_debugger_api.h"
|
||||
#include "dart/runtime/include/dart_native_api.h"
|
||||
#include "sky/engine/core/script/monitor.h"
|
||||
|
||||
namespace base {
|
||||
class Lock;
|
||||
}
|
||||
|
||||
namespace blink {
|
||||
|
||||
class DartDebuggerIsolate {
|
||||
public:
|
||||
DartDebuggerIsolate(Dart_IsolateId id)
|
||||
: id_(id) {
|
||||
}
|
||||
|
||||
Dart_IsolateId id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
monitor_.Notify();
|
||||
}
|
||||
|
||||
void MessageLoop();
|
||||
|
||||
private:
|
||||
const Dart_IsolateId id_;
|
||||
Monitor monitor_;
|
||||
};
|
||||
|
||||
class DartDebugger {
|
||||
public:
|
||||
static void InitDebugger();
|
||||
|
||||
private:
|
||||
static void BptResolvedHandler(Dart_IsolateId isolate_id,
|
||||
intptr_t bp_id,
|
||||
const Dart_CodeLocation& location);
|
||||
|
||||
static void PausedEventHandler(Dart_IsolateId isolate_id,
|
||||
intptr_t bp_id,
|
||||
const Dart_CodeLocation& loc);
|
||||
|
||||
static void ExceptionThrownHandler(Dart_IsolateId isolate_id,
|
||||
Dart_Handle exception,
|
||||
Dart_StackTrace stack_trace);
|
||||
|
||||
static void IsolateEventHandler(Dart_IsolateId isolate_id,
|
||||
Dart_IsolateEvent kind);
|
||||
|
||||
static void NotifyIsolate(Dart_Isolate isolate);
|
||||
|
||||
static intptr_t FindIsolateIndexById(Dart_IsolateId id);
|
||||
|
||||
static intptr_t FindIsolateIndexByIdLocked(Dart_IsolateId id);
|
||||
|
||||
static void AddIsolate(Dart_IsolateId id);
|
||||
|
||||
static void RemoveIsolate(Dart_IsolateId id);
|
||||
|
||||
static base::Lock* lock_;
|
||||
static std::vector<std::unique_ptr<DartDebuggerIsolate>>* isolates_;
|
||||
|
||||
friend class DartDebuggerIsolate;
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
|
||||
#endif // SKY_ENGINE_CORE_SCRIPT_DART_DEBUGGER_H_
|
||||
304
engine/core/script/dart_service_isolate.cc
Normal file
304
engine/core/script/dart_service_isolate.cc
Normal file
@ -0,0 +1,304 @@
|
||||
// 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 "dart_service_isolate.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "dart/runtime/include/dart_api.h"
|
||||
#include "sky/engine/tonic/dart_error.h"
|
||||
#include "sky/engine/tonic/dart_string.h"
|
||||
|
||||
#define RETURN_ERROR_HANDLE(handle) \
|
||||
if (Dart_IsError(handle)) { \
|
||||
return handle; \
|
||||
}
|
||||
|
||||
#define SHUTDOWN_ON_ERROR(handle) \
|
||||
if (Dart_IsError(handle)) { \
|
||||
*error = strdup(Dart_GetError(handle)); \
|
||||
Dart_ExitScope(); \
|
||||
Dart_ShutdownIsolate(); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define kLibrarySourceNamePrefix "/dart_service_isolate"
|
||||
static const char* kServiceIsolateScript = "main.dart";
|
||||
|
||||
struct ResourcesEntry {
|
||||
const char* path_;
|
||||
const char* resource_;
|
||||
int length_;
|
||||
};
|
||||
|
||||
namespace mojo {
|
||||
namespace dart {
|
||||
extern ResourcesEntry __sky_embedder_service_isolate_resources_[];
|
||||
}
|
||||
}
|
||||
|
||||
namespace blink {
|
||||
|
||||
class Resources {
|
||||
public:
|
||||
static const int kNoSuchInstance = -1;
|
||||
static int ResourceLookup(const char* path, const char** resource) {
|
||||
ResourcesEntry* table = ResourcesTable();
|
||||
for (int i = 0; table[i].path_ != NULL; i++) {
|
||||
const ResourcesEntry& entry = table[i];
|
||||
if (strcmp(path, entry.path_) == 0) {
|
||||
*resource = entry.resource_;
|
||||
DCHECK(entry.length_ > 0);
|
||||
return entry.length_;
|
||||
}
|
||||
}
|
||||
return kNoSuchInstance;
|
||||
}
|
||||
|
||||
static const char* Path(int idx) {
|
||||
DCHECK(idx >= 0);
|
||||
ResourcesEntry* entry = At(idx);
|
||||
if (entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
DCHECK(entry->path_ != NULL);
|
||||
return entry->path_;
|
||||
}
|
||||
|
||||
private:
|
||||
static ResourcesEntry* At(int idx) {
|
||||
DCHECK(idx >= 0);
|
||||
ResourcesEntry* table = ResourcesTable();
|
||||
for (int i = 0; table[i].path_ != NULL; i++) {
|
||||
if (idx == i) {
|
||||
return &table[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static ResourcesEntry* ResourcesTable() {
|
||||
return &mojo::dart::__sky_embedder_service_isolate_resources_[0];
|
||||
}
|
||||
};
|
||||
|
||||
void DartServiceIsolate::TriggerResourceLoad(Dart_NativeArguments args) {
|
||||
Dart_Handle library = Dart_RootLibrary();
|
||||
DCHECK(!Dart_IsError(library));
|
||||
Dart_Handle result = LoadResources(library);
|
||||
DCHECK(!Dart_IsError(result));
|
||||
}
|
||||
|
||||
void DartServiceIsolate::NotifyServerState(Dart_NativeArguments args) {
|
||||
// NO-OP.
|
||||
}
|
||||
|
||||
void DartServiceIsolate::Shutdown(Dart_NativeArguments args) {
|
||||
// NO-OP.
|
||||
}
|
||||
|
||||
DartBuiltin::Natives DartServiceIsolate::native_entries_[] = {
|
||||
{"ServiceIsolate_TriggerResourceLoad", TriggerResourceLoad, 0 },
|
||||
{"ServiceIsolate_NotifyServerState", NotifyServerState, 2 },
|
||||
{"ServiceIsolate_Shutdown", Shutdown, 0 },
|
||||
};
|
||||
|
||||
Dart_NativeFunction DartServiceIsolate::NativeResolver(Dart_Handle name,
|
||||
int argument_count,
|
||||
bool* auto_setup_scope) {
|
||||
CHECK(builtins_);
|
||||
return builtins_->Resolver(name, argument_count, auto_setup_scope);
|
||||
}
|
||||
|
||||
const uint8_t* DartServiceIsolate::NativeSymbolizer(
|
||||
Dart_NativeFunction native_function) {
|
||||
CHECK(builtins_);
|
||||
return builtins_->Symbolizer(native_function);
|
||||
}
|
||||
|
||||
Dart_LibraryTagHandler DartServiceIsolate::embedder_tag_handler_ = nullptr;
|
||||
DartBuiltin* DartServiceIsolate::builtins_ = nullptr;
|
||||
|
||||
bool DartServiceIsolate::Startup(std::string server_ip,
|
||||
intptr_t server_port,
|
||||
Dart_LibraryTagHandler embedder_tag_handler,
|
||||
char** error) {
|
||||
Dart_Isolate isolate = Dart_CurrentIsolate();
|
||||
CHECK(isolate);
|
||||
|
||||
// Remember the embedder's library tag handler.
|
||||
embedder_tag_handler_ = embedder_tag_handler;
|
||||
CHECK(embedder_tag_handler_);
|
||||
|
||||
// Setup native entries.
|
||||
builtins_ =
|
||||
new DartBuiltin(&DartServiceIsolate::native_entries_[0],
|
||||
arraysize(native_entries_));
|
||||
|
||||
Dart_Handle result;
|
||||
|
||||
// Use our own library tag handler when loading service isolate sources.
|
||||
Dart_SetLibraryTagHandler(DartServiceIsolate::LibraryTagHandler);
|
||||
// Load main script.
|
||||
Dart_Handle library = LoadScript(kServiceIsolateScript);
|
||||
DCHECK(library != Dart_Null());
|
||||
SHUTDOWN_ON_ERROR(library);
|
||||
// Setup native entry resolution.
|
||||
result = Dart_SetNativeResolver(library, NativeResolver, NativeSymbolizer);
|
||||
|
||||
SHUTDOWN_ON_ERROR(result);
|
||||
// Finalize loading.
|
||||
result = Dart_FinalizeLoading(false);
|
||||
SHUTDOWN_ON_ERROR(result);
|
||||
|
||||
// Make runnable.
|
||||
Dart_ExitScope();
|
||||
Dart_ExitIsolate();
|
||||
bool retval = Dart_IsolateMakeRunnable(isolate);
|
||||
if (!retval) {
|
||||
Dart_EnterIsolate(isolate);
|
||||
Dart_ShutdownIsolate();
|
||||
*error = strdup("Invalid isolate state - Unable to make it runnable.");
|
||||
return false;
|
||||
}
|
||||
Dart_EnterIsolate(isolate);
|
||||
Dart_EnterScope();
|
||||
|
||||
library = Dart_RootLibrary();
|
||||
SHUTDOWN_ON_ERROR(library);
|
||||
|
||||
// Set the HTTP server's ip.
|
||||
result = Dart_SetField(library,
|
||||
Dart_NewStringFromCString("_ip"),
|
||||
Dart_NewStringFromCString(server_ip.c_str()));
|
||||
SHUTDOWN_ON_ERROR(result);
|
||||
// If we have a port specified, start the server immediately.
|
||||
bool auto_start = server_port >= 0;
|
||||
if (server_port < 0) {
|
||||
// Adjust server_port to port 0 which will result in the first available
|
||||
// port when the HTTP server is started.
|
||||
server_port = 0;
|
||||
}
|
||||
// Set the HTTP's servers port.
|
||||
result = Dart_SetField(library,
|
||||
Dart_NewStringFromCString("_port"),
|
||||
Dart_NewInteger(server_port));
|
||||
SHUTDOWN_ON_ERROR(result);
|
||||
result = Dart_SetField(library,
|
||||
Dart_NewStringFromCString("_autoStart"),
|
||||
Dart_NewBoolean(auto_start));
|
||||
SHUTDOWN_ON_ERROR(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
Dart_Handle DartServiceIsolate::GetSource(const char* name) {
|
||||
const intptr_t kBufferSize = 512;
|
||||
char buffer[kBufferSize];
|
||||
snprintf(&buffer[0], kBufferSize-1, "%s/%s", kLibrarySourceNamePrefix, name);
|
||||
const char* vmservice_source = NULL;
|
||||
int r = Resources::ResourceLookup(buffer, &vmservice_source);
|
||||
DCHECK(r != Resources::kNoSuchInstance);
|
||||
return Dart_NewStringFromCString(vmservice_source);
|
||||
}
|
||||
|
||||
Dart_Handle DartServiceIsolate::LoadScript(const char* name) {
|
||||
Dart_Handle url = Dart_NewStringFromCString("dart:vmservice_sky");
|
||||
Dart_Handle source = GetSource(name);
|
||||
return Dart_LoadScript(url, source, 0, 0);
|
||||
}
|
||||
|
||||
Dart_Handle DartServiceIsolate::LoadSource(Dart_Handle library, const char* name) {
|
||||
Dart_Handle url = Dart_NewStringFromCString(name);
|
||||
Dart_Handle source = GetSource(name);
|
||||
return Dart_LoadSource(library, url, source, 0, 0);
|
||||
}
|
||||
|
||||
Dart_Handle DartServiceIsolate::LoadResource(Dart_Handle library,
|
||||
const char* resource_name) {
|
||||
// Prepare for invoke call.
|
||||
Dart_Handle name = Dart_NewStringFromCString(resource_name);
|
||||
RETURN_ERROR_HANDLE(name);
|
||||
const char* data_buffer = NULL;
|
||||
int data_buffer_length = Resources::ResourceLookup(resource_name,
|
||||
&data_buffer);
|
||||
DCHECK(data_buffer_length != Resources::kNoSuchInstance);
|
||||
Dart_Handle data_list = Dart_NewTypedData(Dart_TypedData_kUint8,
|
||||
data_buffer_length);
|
||||
RETURN_ERROR_HANDLE(data_list);
|
||||
Dart_TypedData_Type type = Dart_TypedData_kInvalid;
|
||||
void* data_list_buffer = NULL;
|
||||
intptr_t data_list_buffer_length = 0;
|
||||
Dart_Handle result = Dart_TypedDataAcquireData(data_list, &type,
|
||||
&data_list_buffer,
|
||||
&data_list_buffer_length);
|
||||
RETURN_ERROR_HANDLE(result);
|
||||
DCHECK(data_buffer_length == data_list_buffer_length);
|
||||
DCHECK(data_list_buffer != NULL);
|
||||
DCHECK(type = Dart_TypedData_kUint8);
|
||||
memmove(data_list_buffer, &data_buffer[0], data_buffer_length);
|
||||
result = Dart_TypedDataReleaseData(data_list);
|
||||
RETURN_ERROR_HANDLE(result);
|
||||
|
||||
// Make invoke call.
|
||||
const intptr_t kNumArgs = 2;
|
||||
Dart_Handle args[kNumArgs] = { name, data_list };
|
||||
result = Dart_Invoke(library, Dart_NewStringFromCString("_addResource"),
|
||||
kNumArgs, args);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dart_Handle DartServiceIsolate::LoadResources(Dart_Handle library) {
|
||||
Dart_Handle result = Dart_Null();
|
||||
intptr_t prefixLen = strlen(kLibrarySourceNamePrefix);
|
||||
for (intptr_t i = 0; Resources::Path(i) != NULL; i++) {
|
||||
const char* path = Resources::Path(i);
|
||||
// If it doesn't begin with kLibrarySourceNamePrefix it is a frontend
|
||||
// resource.
|
||||
if (strncmp(path, kLibrarySourceNamePrefix, prefixLen) != 0) {
|
||||
result = LoadResource(library, path);
|
||||
if (Dart_IsError(result)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Dart_Handle DartServiceIsolate::LibraryTagHandler(Dart_LibraryTag tag,
|
||||
Dart_Handle library,
|
||||
Dart_Handle url) {
|
||||
if (!Dart_IsLibrary(library)) {
|
||||
return Dart_NewApiError("not a library");
|
||||
}
|
||||
if (!Dart_IsString(url)) {
|
||||
return Dart_NewApiError("url is not a string");
|
||||
}
|
||||
const char* url_string = NULL;
|
||||
Dart_Handle result = Dart_StringToCString(url, &url_string);
|
||||
if (Dart_IsError(result)) {
|
||||
return result;
|
||||
}
|
||||
Dart_Handle library_url = Dart_LibraryUrl(library);
|
||||
const char* library_url_string = NULL;
|
||||
result = Dart_StringToCString(library_url, &library_url_string);
|
||||
if (Dart_IsError(result)) {
|
||||
return result;
|
||||
}
|
||||
if (tag == Dart_kImportTag) {
|
||||
// Embedder handles all requests for external libraries.
|
||||
return embedder_tag_handler_(tag, library, url);
|
||||
}
|
||||
DCHECK((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl));
|
||||
if (tag == Dart_kCanonicalizeUrl) {
|
||||
// url is already canonicalized.
|
||||
return url;
|
||||
}
|
||||
// Get source from builtin resources.
|
||||
Dart_Handle source = GetSource(url_string);
|
||||
if (Dart_IsError(source)) {
|
||||
return source;
|
||||
}
|
||||
return Dart_LoadSource(library, url, source, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
} // namespace blink
|
||||
55
engine/core/script/dart_service_isolate.h
Normal file
55
engine/core/script/dart_service_isolate.h
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SKY_ENGINE_CORE_SCRIPT_DART_SERVICE_ISOLATE_H_
|
||||
#define SKY_ENGINE_CORE_SCRIPT_DART_SERVICE_ISOLATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "include/dart_api.h"
|
||||
#include "sky/engine/config.h"
|
||||
#include "sky/engine/tonic/dart_builtin.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
class DartServiceIsolate {
|
||||
public:
|
||||
static bool Bootstrap();
|
||||
|
||||
static bool Startup(std::string server_ip,
|
||||
intptr_t server_port,
|
||||
Dart_LibraryTagHandler embedder_tag_handler,
|
||||
char** error);
|
||||
|
||||
private:
|
||||
// Native entries.
|
||||
static void TriggerResourceLoad(Dart_NativeArguments args);
|
||||
static void NotifyServerState(Dart_NativeArguments args);
|
||||
static void Shutdown(Dart_NativeArguments args);
|
||||
// Native entry resolution.
|
||||
static Dart_NativeFunction NativeResolver(Dart_Handle name,
|
||||
int argument_count,
|
||||
bool* auto_setup_scope);
|
||||
static const uint8_t* NativeSymbolizer(Dart_NativeFunction native_function);
|
||||
static DartBuiltin::Natives native_entries_[];
|
||||
static DartBuiltin* builtins_;
|
||||
|
||||
// Script loading.
|
||||
static Dart_Handle GetSource(const char* name);
|
||||
static Dart_Handle LoadScript(const char* name);
|
||||
static Dart_Handle LoadSource(Dart_Handle library, const char* name);
|
||||
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library,
|
||||
Dart_Handle url);
|
||||
|
||||
// Observatory resource loading.
|
||||
static Dart_Handle LoadResources(Dart_Handle library);
|
||||
static Dart_Handle LoadResource(Dart_Handle library, const char* name);
|
||||
|
||||
static Dart_LibraryTagHandler embedder_tag_handler_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace blink
|
||||
|
||||
#endif // SKY_ENGINE_CORE_SCRIPT_DART_SERVICE_ISOLATE_H_
|
||||
11
engine/core/script/dart_service_isolate/loader.dart
Normal file
11
engine/core/script/dart_service_isolate/loader.dart
Normal file
@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
part of dart_controller_service_isolate;
|
||||
|
||||
_processLoadRequest(request) {
|
||||
var sp = request[0];
|
||||
var uri = Uri.parse(request[1]);
|
||||
sp.send('Service isolate loading not supported by embedder (uri = $uri).');
|
||||
}
|
||||
60
engine/core/script/dart_service_isolate/main.dart
Normal file
60
engine/core/script/dart_service_isolate/main.dart
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library sky_shell_dart_controller_service_isolate;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:vmservice';
|
||||
|
||||
part 'loader.dart';
|
||||
part 'resources.dart';
|
||||
part 'server.dart';
|
||||
|
||||
// The TCP ip/port that the HTTP server listens on.
|
||||
int _port;
|
||||
String _ip;
|
||||
// Should the HTTP server auto start?
|
||||
bool _autoStart;
|
||||
|
||||
// HTTP server.
|
||||
Server server;
|
||||
|
||||
_onShutdown() {
|
||||
if (server != null) {
|
||||
server.close(true).catchError((e, st) {
|
||||
print(e);
|
||||
}).whenComplete(_shutdown);
|
||||
} else {
|
||||
_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void _bootServer() {
|
||||
// Load resources.
|
||||
_triggerResourceLoad();
|
||||
// Lazily create service.
|
||||
var service = new VMService();
|
||||
service.onShutdown = _onShutdown;
|
||||
// Lazily create server.
|
||||
server = new Server(service, _ip, _port);
|
||||
}
|
||||
|
||||
main() {
|
||||
if (_autoStart) {
|
||||
_bootServer();
|
||||
if (server != null) {
|
||||
server.startup();
|
||||
}
|
||||
}
|
||||
scriptLoadPort.handler = _processLoadRequest;
|
||||
// It's just here to push an event on the event loop so that we invoke the
|
||||
// scheduled microtasks.
|
||||
Timer.run(() {});
|
||||
return scriptLoadPort;
|
||||
}
|
||||
|
||||
_shutdown() native "ServiceIsolate_Shutdown";
|
||||
50
engine/core/script/dart_service_isolate/resources.dart
Normal file
50
engine/core/script/dart_service_isolate/resources.dart
Normal file
@ -0,0 +1,50 @@
|
||||
// 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.
|
||||
|
||||
part of dart_controller_service_isolate;
|
||||
|
||||
String detectMimeType(String name) {
|
||||
var extensionStart = name.lastIndexOf('.');
|
||||
var extension = name.substring(extensionStart+1);
|
||||
switch (extension) {
|
||||
case 'html':
|
||||
return 'text/html; charset=UTF-8';
|
||||
case 'dart':
|
||||
return 'application/dart; charset=UTF-8';
|
||||
case 'js':
|
||||
return 'application/javascript; charset=UTF-8';
|
||||
case 'css':
|
||||
return 'text/css; charset=UTF-8';
|
||||
case 'gif':
|
||||
return 'image/gif';
|
||||
case 'png':
|
||||
return 'image/png';
|
||||
case 'jpg':
|
||||
return 'image/jpeg';
|
||||
case 'jpeg':
|
||||
return 'image/jpeg';
|
||||
case 'svg':
|
||||
return 'image/svg+xml';
|
||||
default:
|
||||
return 'text/plain';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Resource {
|
||||
final String name;
|
||||
final String mimeType;
|
||||
final List<int> data;
|
||||
Resource(this.name, this.mimeType, this.data);
|
||||
static final Map<String, Resource> resources = new Map<String, Resource>();
|
||||
}
|
||||
|
||||
|
||||
_addResource(String name, List<int> data) {
|
||||
var mimeType = detectMimeType(name);
|
||||
Resource resource = new Resource(name, mimeType, data);
|
||||
Resource.resources[name] = resource;
|
||||
}
|
||||
|
||||
_triggerResourceLoad() native "ServiceIsolate_TriggerResourceLoad";
|
||||
225
engine/core/script/dart_service_isolate/server.dart
Normal file
225
engine/core/script/dart_service_isolate/server.dart
Normal file
@ -0,0 +1,225 @@
|
||||
// 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.
|
||||
|
||||
part of dart_controller_service_isolate;
|
||||
|
||||
class WebSocketClient extends Client {
|
||||
static const int PARSE_ERROR_CODE = 4000;
|
||||
static const int BINARY_MESSAGE_ERROR_CODE = 4001;
|
||||
static const int NOT_MAP_ERROR_CODE = 4002;
|
||||
final WebSocket socket;
|
||||
|
||||
WebSocketClient(this.socket, VMService service) : super(service) {
|
||||
socket.listen((message) => onWebSocketMessage(message));
|
||||
socket.done.then((_) => close());
|
||||
}
|
||||
|
||||
onWebSocketMessage(message) {
|
||||
if (message is String) {
|
||||
var map;
|
||||
try {
|
||||
map = JSON.decode(message);
|
||||
} catch (e) {
|
||||
socket.close(PARSE_ERROR_CODE, 'Message parse error: $e');
|
||||
return;
|
||||
}
|
||||
if (map is! Map) {
|
||||
socket.close(NOT_MAP_ERROR_CODE, 'Message must be a JSON map.');
|
||||
return;
|
||||
}
|
||||
var serial = map['id'];
|
||||
onMessage(serial, new Message.fromJsonRpc(map));
|
||||
} else {
|
||||
socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
|
||||
}
|
||||
}
|
||||
|
||||
post(dynamic result) {
|
||||
try {
|
||||
socket.add(result);
|
||||
} catch (_) {
|
||||
print("Ignoring error posting over WebSocket.");
|
||||
}
|
||||
}
|
||||
|
||||
dynamic toJson() {
|
||||
Map map = super.toJson();
|
||||
map['type'] = 'WebSocketClient';
|
||||
map['socket'] = '$socket';
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HttpRequestClient extends Client {
|
||||
static ContentType jsonContentType =
|
||||
new ContentType("application", "json", charset: "utf-8");
|
||||
final HttpRequest request;
|
||||
|
||||
HttpRequestClient(this.request, VMService service) : super(service);
|
||||
|
||||
post(String result) {
|
||||
request.response..headers.contentType = jsonContentType
|
||||
..write(result)
|
||||
..close();
|
||||
close();
|
||||
}
|
||||
|
||||
dynamic toJson() {
|
||||
Map map = super.toJson();
|
||||
map['type'] = 'HttpRequestClient';
|
||||
map['request'] = '$request';
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class Server {
|
||||
static const WEBSOCKET_PATH = '/ws';
|
||||
static const ROOT_REDIRECT_PATH = '/index.html';
|
||||
|
||||
final VMService _service;
|
||||
final String _ip;
|
||||
final int _port;
|
||||
|
||||
HttpServer _server;
|
||||
bool get running => _server != null;
|
||||
bool _displayMessages = false;
|
||||
|
||||
Server(this._service, this._ip, this._port) {
|
||||
_displayMessages = (_ip != '127.0.0.1' || _port != 8181);
|
||||
}
|
||||
|
||||
bool _shouldServeObservatory(HttpRequest request) {
|
||||
if (request.headers['Observatory-Version'] != null) {
|
||||
// Request is already coming from Observatory.
|
||||
return false;
|
||||
}
|
||||
// TODO(johnmccutchan): Test with obscure browsers.
|
||||
if (request.headers.value(HttpHeaders.USER_AGENT).contains('Mozilla')) {
|
||||
// Request is coming from a browser but not Observatory application.
|
||||
// Serve Observatory and let the Observatory make the real request.
|
||||
return true;
|
||||
}
|
||||
// All other user agents are assumed to be textual.
|
||||
return false;
|
||||
}
|
||||
|
||||
_onServerShutdown() {
|
||||
}
|
||||
|
||||
_serverError(error, stackTrace) {
|
||||
_onServerShutdown();
|
||||
}
|
||||
|
||||
_serverDone() {
|
||||
_onServerShutdown();
|
||||
}
|
||||
|
||||
_requestHandler(HttpRequest request) {
|
||||
// Allow cross origin requests with 'observatory' header.
|
||||
request.response.headers.add('Access-Control-Allow-Origin', '*');
|
||||
request.response.headers.add('Access-Control-Allow-Headers',
|
||||
'Observatory-Version');
|
||||
|
||||
if (request.method != 'GET') {
|
||||
// Not a GET request. Do nothing.
|
||||
request.response.close();
|
||||
return;
|
||||
}
|
||||
|
||||
final String path =
|
||||
request.uri.path == '/' ? ROOT_REDIRECT_PATH : request.uri.path;
|
||||
|
||||
if (path == WEBSOCKET_PATH) {
|
||||
WebSocketTransformer.upgrade(request).then((WebSocket webSocket) {
|
||||
new WebSocketClient(webSocket, _service);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var resource = Resource.resources[path];
|
||||
if (resource == null && _shouldServeObservatory(request)) {
|
||||
resource = Resource.resources[ROOT_REDIRECT_PATH];
|
||||
assert(resource != null);
|
||||
}
|
||||
if (resource != null) {
|
||||
// Serving up a static resource (e.g. .css, .html, .png).
|
||||
request.response.headers.contentType =
|
||||
ContentType.parse(resource.mimeType);
|
||||
request.response.add(resource.data);
|
||||
request.response.close();
|
||||
return;
|
||||
}
|
||||
var message = new Message.fromUri(request.uri);
|
||||
var client = new HttpRequestClient(request, _service);
|
||||
client.onMessage(null, message);
|
||||
}
|
||||
|
||||
Future startup() {
|
||||
if (_server != null) {
|
||||
// Already running.
|
||||
return new Future.value(this);
|
||||
}
|
||||
|
||||
// Startup HTTP server.
|
||||
var address = new InternetAddress('127.0.0.1');
|
||||
return HttpServer.bind(address, _port).then((s) {
|
||||
_server = s;
|
||||
_server.listen(_requestHandler,
|
||||
onError: _serverError,
|
||||
onDone: _serverDone,
|
||||
cancelOnError: true);
|
||||
var ip = _server.address.address.toString();
|
||||
if (_displayMessages) {
|
||||
var port = _server.port.toString();
|
||||
print('Observatory listening on http://$ip:$port');
|
||||
}
|
||||
// Server is up and running.
|
||||
_notifyServerState(ip, _server.port);
|
||||
return this;
|
||||
}).catchError((e, st) {
|
||||
print('Could not start Observatory HTTP server:\n$e\n$st\n');
|
||||
_notifyServerState("", 0);
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
close(bool force) {
|
||||
if (_server == null) {
|
||||
return new Future.value(null);
|
||||
}
|
||||
return _server.close(force: force);
|
||||
}
|
||||
|
||||
Future shutdown(bool forced) {
|
||||
if (_server == null) {
|
||||
// Not started.
|
||||
return new Future.value(this);
|
||||
}
|
||||
|
||||
// Force displaying of status messages if we are forcibly shutdown.
|
||||
_displayMessages = _displayMessages || forced;
|
||||
|
||||
// Shutdown HTTP server and subscription.
|
||||
var ip = _server.address.address.toString();
|
||||
var port = _server.port.toString();
|
||||
return close(forced).then((_) {
|
||||
if (_displayMessages) {
|
||||
print('Observatory no longer listening on http://$ip:$port');
|
||||
}
|
||||
_server = null;
|
||||
_notifyServerState("", 0);
|
||||
return this;
|
||||
}).catchError((e, st) {
|
||||
_server = null;
|
||||
print('Could not shutdown Observatory HTTP server:\n$e\n$st\n');
|
||||
_notifyServerState("", 0);
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_notifyServerState(String ip, int port)
|
||||
native "ServiceIsolate_NotifyServerState";
|
||||
75
engine/core/script/monitor.h
Normal file
75
engine/core/script/monitor.h
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SKY_ENGINE_CORE_SCRIPT_MONITOR_H_
|
||||
#define SKY_ENGINE_CORE_SCRIPT_MONITOR_H_
|
||||
|
||||
#include "base/synchronization/condition_variable.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
Monitor() {
|
||||
lock_ = new base::Lock();
|
||||
condition_variable_ = new base::ConditionVariable(lock_);
|
||||
}
|
||||
|
||||
~Monitor() {
|
||||
delete condition_variable_;
|
||||
delete lock_;
|
||||
}
|
||||
|
||||
void Enter() {
|
||||
lock_->Acquire();
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
lock_->Release();
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
condition_variable_->Signal();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
condition_variable_->Wait();
|
||||
}
|
||||
|
||||
private:
|
||||
base::Lock* lock_;
|
||||
base::ConditionVariable* condition_variable_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Monitor);
|
||||
};
|
||||
|
||||
class MonitorLocker {
|
||||
public:
|
||||
explicit MonitorLocker(Monitor* monitor) : monitor_(monitor) {
|
||||
CHECK(monitor_);
|
||||
monitor_->Enter();
|
||||
}
|
||||
|
||||
virtual ~MonitorLocker() {
|
||||
monitor_->Exit();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
return monitor_->Wait();
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
monitor_->Notify();
|
||||
}
|
||||
|
||||
private:
|
||||
Monitor* const monitor_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
|
||||
|
||||
#endif // SKY_ENGINE_CORE_SCRIPT_MONITOR_H_
|
||||
@ -307,6 +307,10 @@ class SingleTestRunner(object):
|
||||
failures.append(test_failures.FailureMissingAudio())
|
||||
return failures
|
||||
|
||||
# FIXME: This won't be needed once we have flags for Sky that suppress the
|
||||
# Observatory messages.
|
||||
_filter_observatory_messages = re.compile(r"^CONSOLE: Observatory listening on.*\n", re.MULTILINE)
|
||||
|
||||
def _get_normalized_output_text(self, output):
|
||||
"""Returns the normalized text output, i.e. the output in which
|
||||
the end-of-line characters are normalized to "\n"."""
|
||||
@ -314,7 +318,9 @@ class SingleTestRunner(object):
|
||||
# changed to "\r\n" by our system (Python/Cygwin), resulting in
|
||||
# "\r\r\n", when, in fact, we wanted to compare the text output with
|
||||
# the normalized text expectation files.
|
||||
return output.replace("\r\r\n", "\r\n").replace("\r\n", "\n")
|
||||
normalized_lines = output.replace("\r\r\n", "\r\n").replace("\r\n", "\n")
|
||||
normalized_lines = re.sub(self._filter_observatory_messages, r"", normalized_lines)
|
||||
return normalized_lines
|
||||
|
||||
# FIXME: This function also creates the image diff. Maybe that work should
|
||||
# be handled elsewhere?
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user