// 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/main_options.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) #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; \ } static constexpr const char* kVMServiceIOLibraryUri = "dart:vmservice_io"; 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[] = { {"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(entry.function) == nf) { return reinterpret_cast(entry.name); } } return nullptr; } const char* VmService::error_msg_ = nullptr; char VmService::server_uri_[kServerUriStringBufferSize]; void VmService::SetNativeResolver() { Dart_Handle url = DartUtils::NewString(kVMServiceIOLibraryUri); Dart_Handle library = Dart_LookupLibrary(url); if (!Dart_IsError(library)) { Dart_SetNativeResolver(library, VmServiceIONativeResolver, VmServiceIONativeSymbol); } } 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 builtin and its dependent libraries for use to resolve URIs. // Set up various closures, e.g: printing, timers etc. // Set up 'package root' for URI resolution. result = DartUtils::PrepareForScriptLoading( /*is_service_isolate=*/true, trace_loading, /*flag_profile_microtasks=*/false); SHUTDOWN_ON_ERROR(result); 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(); 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("_serveObservatory"), serve_observatory ? 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