ae1b83869a
The DartRuntimeService based VM service implementation now has support for launching DDS instances and responding to _yieldControlToDDS RPC invocations from DDS instances. package:vm_service test suite is ~97% passing with this change. TEST=Local testing. Change-Id: I2f2f1b0926845134578f08d073ed7606f1fc4173 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/490320 Reviewed-by: Jessy Yameogo <yjessy@google.com> Reviewed-by: Nicholas Shahan <nshahan@google.com>
307 lines
11 KiB
C++
307 lines
11 KiB
C++
// 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.
|
|
|
|
#include "bin/vmservice_impl.h"
|
|
|
|
#include "include/dart_api.h"
|
|
|
|
#include "bin/builtin.h"
|
|
#include "bin/dartutils.h"
|
|
#include "bin/isolate_data.h"
|
|
#include "bin/platform.h"
|
|
#include "bin/thread.h"
|
|
#include "bin/utils.h"
|
|
#include "platform/text_buffer.h"
|
|
#include "platform/utils.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
#if !defined(PRODUCT)
|
|
|
|
bool VmService::enable_experimental_vm_service = false;
|
|
|
|
#define RETURN_ERROR_HANDLE(handle) \
|
|
if (Dart_IsError(handle)) { \
|
|
return handle; \
|
|
}
|
|
|
|
#define SHUTDOWN_ON_ERROR(handle) \
|
|
if (Dart_IsError(handle)) { \
|
|
error_msg_ = Utils::StrDup(Dart_GetError(handle)); \
|
|
Dart_ExitScope(); \
|
|
Dart_ShutdownIsolate(); \
|
|
return false; \
|
|
}
|
|
|
|
void NotifyServerState(Dart_NativeArguments args) {
|
|
Dart_EnterScope();
|
|
const char* uri_chars;
|
|
Dart_Handle uri_arg = Dart_GetNativeArgument(args, 0);
|
|
if (Dart_IsError(uri_arg)) {
|
|
VmService::SetServerAddress("");
|
|
Dart_ExitScope();
|
|
return;
|
|
}
|
|
Dart_Handle result = Dart_StringToCString(uri_arg, &uri_chars);
|
|
if (Dart_IsError(result)) {
|
|
VmService::SetServerAddress("");
|
|
Dart_ExitScope();
|
|
return;
|
|
}
|
|
VmService::SetServerAddress(uri_chars);
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
static void Shutdown(Dart_NativeArguments args) {
|
|
// NO-OP.
|
|
}
|
|
|
|
struct VmServiceIONativeEntry {
|
|
const char* name;
|
|
int num_arguments;
|
|
Dart_NativeFunction function;
|
|
};
|
|
|
|
static VmServiceIONativeEntry _VmServiceIONativeEntries[] = {
|
|
// TODO(bkonyi): these aren't used by any known embedders and can be
|
|
// removed.
|
|
{"VMServiceIO_NotifyServerState", 1, NotifyServerState},
|
|
{"VMServiceIO_Shutdown", 0, Shutdown},
|
|
};
|
|
|
|
static Dart_NativeFunction VmServiceIONativeResolver(Dart_Handle name,
|
|
int num_arguments,
|
|
bool* auto_setup_scope) {
|
|
const char* function_name = nullptr;
|
|
Dart_Handle result = Dart_StringToCString(name, &function_name);
|
|
ASSERT(!Dart_IsError(result));
|
|
ASSERT(function_name != nullptr);
|
|
*auto_setup_scope = true;
|
|
intptr_t n =
|
|
sizeof(_VmServiceIONativeEntries) / sizeof(_VmServiceIONativeEntries[0]);
|
|
for (intptr_t i = 0; i < n; i++) {
|
|
VmServiceIONativeEntry entry = _VmServiceIONativeEntries[i];
|
|
if ((strcmp(function_name, entry.name) == 0) &&
|
|
(num_arguments == entry.num_arguments)) {
|
|
return entry.function;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const uint8_t* VmServiceIONativeSymbol(Dart_NativeFunction nf) {
|
|
intptr_t n =
|
|
sizeof(_VmServiceIONativeEntries) / sizeof(_VmServiceIONativeEntries[0]);
|
|
for (intptr_t i = 0; i < n; i++) {
|
|
VmServiceIONativeEntry entry = _VmServiceIONativeEntries[i];
|
|
if (reinterpret_cast<Dart_NativeFunction>(entry.function) == nf) {
|
|
return reinterpret_cast<const uint8_t*>(entry.name);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const char* VmService::error_msg_ = nullptr;
|
|
char VmService::server_uri_[kServerUriStringBufferSize];
|
|
|
|
static constexpr const char* kVMServiceIOLibraryUri = "dart:vmservice_io";
|
|
|
|
void VmService::SetNativeResolver() {
|
|
if (enable_experimental_vm_service) {
|
|
return;
|
|
}
|
|
Dart_Handle url = DartUtils::NewString(kVMServiceIOLibraryUri);
|
|
Dart_Handle library = Dart_LookupLibrary(url);
|
|
if (!Dart_IsError(library)) {
|
|
Dart_SetNativeResolver(library, VmServiceIONativeResolver,
|
|
VmServiceIONativeSymbol);
|
|
}
|
|
}
|
|
|
|
static constexpr const char* DEFAULT_VM_SERVICE_SERVER_IP = "localhost";
|
|
|
|
bool VmService::Setup(const char* server_ip,
|
|
intptr_t server_port,
|
|
bool dev_mode_server,
|
|
bool auth_codes_disabled,
|
|
const char* write_service_info_filename,
|
|
bool trace_loading,
|
|
bool deterministic,
|
|
bool enable_service_port_fallback,
|
|
bool wait_for_dds_to_advertise_service,
|
|
bool serve_devtools,
|
|
bool serve_observatory,
|
|
bool print_dtd,
|
|
bool should_use_resident_compiler,
|
|
const char* resident_compiler_info_file_path) {
|
|
Dart_Isolate isolate = Dart_CurrentIsolate();
|
|
ASSERT(isolate != nullptr);
|
|
SetServerAddress("");
|
|
|
|
Dart_Handle result;
|
|
|
|
// Prepare all core libraries for execution of Dart code.
|
|
result = DartUtils::SetupCoreLibraries(
|
|
/*is_service_isolate=*/true, trace_loading,
|
|
/*flag_profile_microtasks=*/false, DartIoSettings{});
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
if (!enable_experimental_vm_service) {
|
|
Dart_Handle url = DartUtils::NewString(kVMServiceIOLibraryUri);
|
|
Dart_Handle library = Dart_LookupLibrary(url);
|
|
SHUTDOWN_ON_ERROR(library);
|
|
result = Dart_SetRootLibrary(library);
|
|
SHUTDOWN_ON_ERROR(library);
|
|
result = Dart_SetNativeResolver(library, VmServiceIONativeResolver,
|
|
VmServiceIONativeSymbol);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
}
|
|
|
|
// Make runnable.
|
|
Dart_ExitScope();
|
|
Dart_ExitIsolate();
|
|
error_msg_ = Dart_IsolateMakeRunnable(isolate);
|
|
if (error_msg_ != nullptr) {
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
return false;
|
|
}
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle library = Dart_RootLibrary();
|
|
SHUTDOWN_ON_ERROR(library);
|
|
|
|
// Set HTTP server state.
|
|
// 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;
|
|
}
|
|
if (wait_for_dds_to_advertise_service) {
|
|
result = DartUtils::SetStringField(library, "_ddsIP", server_ip);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
result = DartUtils::SetIntegerField(library, "_ddsPort", server_port);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
result =
|
|
DartUtils::SetStringField(library, "_ip", DEFAULT_VM_SERVICE_SERVER_IP);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
result = DartUtils::SetIntegerField(library, "_port", 0);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
} else {
|
|
result = DartUtils::SetStringField(library, "_ip", server_ip);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
result = DartUtils::SetIntegerField(library, "_port", server_port);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
}
|
|
result = Dart_SetField(library, DartUtils::NewString("_autoStart"),
|
|
Dart_NewBoolean(auto_start));
|
|
SHUTDOWN_ON_ERROR(result);
|
|
result = Dart_SetField(library, DartUtils::NewString("_originCheckDisabled"),
|
|
Dart_NewBoolean(dev_mode_server));
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
result = Dart_SetField(library, DartUtils::NewString("_authCodesDisabled"),
|
|
Dart_NewBoolean(auth_codes_disabled));
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
result =
|
|
Dart_SetField(library, DartUtils::NewString("_enableServicePortFallback"),
|
|
Dart_NewBoolean(enable_service_port_fallback));
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
if (write_service_info_filename != nullptr) {
|
|
result = DartUtils::SetStringField(library, "_serviceInfoFilename",
|
|
write_service_info_filename);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
}
|
|
|
|
result = Dart_SetField(library,
|
|
DartUtils::NewString("_waitForDdsToAdvertiseService"),
|
|
Dart_NewBoolean(wait_for_dds_to_advertise_service));
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
result = Dart_SetField(library, DartUtils::NewString("_serveDevtools"),
|
|
serve_devtools ? Dart_True() : Dart_False());
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
result = Dart_SetField(library, DartUtils::NewString("_printDtd"),
|
|
print_dtd ? Dart_True() : Dart_False());
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
if (should_use_resident_compiler) {
|
|
Dart_Handle resident_compiler_info_file_path_dart_string = nullptr;
|
|
if (resident_compiler_info_file_path == nullptr) {
|
|
resident_compiler_info_file_path_dart_string = Dart_Null();
|
|
} else {
|
|
resident_compiler_info_file_path_dart_string =
|
|
DartUtils::NewString(resident_compiler_info_file_path);
|
|
}
|
|
result = Dart_Invoke(
|
|
library, DartUtils::NewString("_populateResidentCompilerInfoFile"), 1,
|
|
&resident_compiler_info_file_path_dart_string);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
}
|
|
|
|
// Are we running on Windows?
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
Dart_Handle is_windows = Dart_True();
|
|
#else
|
|
Dart_Handle is_windows = Dart_False();
|
|
#endif
|
|
result =
|
|
Dart_SetField(library, DartUtils::NewString("_isWindows"), is_windows);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
// Are we running on Fuchsia?
|
|
#if defined(DART_HOST_OS_FUCHSIA)
|
|
Dart_Handle is_fuchsia = Dart_True();
|
|
#else
|
|
Dart_Handle is_fuchsia = Dart_False();
|
|
#endif
|
|
result =
|
|
Dart_SetField(library, DartUtils::NewString("_isFuchsia"), is_fuchsia);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
// Get _getWatchSignalInternal from dart:io.
|
|
Dart_Handle dart_io_str = Dart_NewStringFromCString(DartUtils::kIOLibURL);
|
|
SHUTDOWN_ON_ERROR(dart_io_str);
|
|
Dart_Handle io_lib = Dart_LookupLibrary(dart_io_str);
|
|
SHUTDOWN_ON_ERROR(io_lib);
|
|
Dart_Handle function_name =
|
|
Dart_NewStringFromCString("_getWatchSignalInternal");
|
|
SHUTDOWN_ON_ERROR(function_name);
|
|
Dart_Handle signal_watch = Dart_Invoke(io_lib, function_name, 0, nullptr);
|
|
SHUTDOWN_ON_ERROR(signal_watch);
|
|
Dart_Handle field_name = Dart_NewStringFromCString("_signalWatch");
|
|
SHUTDOWN_ON_ERROR(field_name);
|
|
result = Dart_SetField(library, field_name, signal_watch);
|
|
SHUTDOWN_ON_ERROR(field_name);
|
|
return true;
|
|
}
|
|
|
|
const char* VmService::GetErrorMessage() {
|
|
return (error_msg_ == nullptr) ? "No error." : error_msg_;
|
|
}
|
|
|
|
void VmService::SetServerAddress(const char* server_uri) {
|
|
if (server_uri == nullptr) {
|
|
server_uri = "";
|
|
}
|
|
const intptr_t server_uri_len = strlen(server_uri);
|
|
if (server_uri_len >= (kServerUriStringBufferSize - 1)) {
|
|
FATAL("vm-service: Server URI exceeded length: %s\n", server_uri);
|
|
}
|
|
strncpy(server_uri_, server_uri, kServerUriStringBufferSize);
|
|
server_uri_[kServerUriStringBufferSize - 1] = '\0';
|
|
}
|
|
|
|
#endif // !defined(PRODUCT)
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|