提交 76da439f 编写于 作者: J John McCutchan

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
上级 04dec88f
......@@ -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
// 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
// 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_
\ No newline at end of file
// 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
// 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_
// 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).');
}
\ No newline at end of file
// 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";
// 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";
// 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";
// 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_
\ No newline at end of file
......@@ -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?
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册