blob: 6c7ca066c673ba0286e4480d007cea1750c702b2 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "service_isolate.h"
#include "runtime/dart/utils/inlines.h"
#include "third_party/dart/runtime/include/bin/dart_io_api.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_library_natives.h"
#include "third_party/tonic/dart_microtask_queue.h"
#include "third_party/tonic/dart_state.h"
#include "third_party/tonic/typed_data/typed_list.h"
#include "builtin_libraries.h"
#include "dart_component_controller.h"
#include "logging.h"
namespace dart_runner {
namespace {
dart_utils::ElfSnapshot elf_snapshot; // AOT snapshot
dart_utils::MappedResource mapped_isolate_snapshot_data; // JIT snapshot
dart_utils::MappedResource
mapped_isolate_snapshot_instructions; // JIT snapshot
tonic::DartLibraryNatives* service_natives = nullptr;
Dart_NativeFunction GetNativeFunction(Dart_Handle name,
int argument_count,
bool* auto_setup_scope) {
dart_utils::Check(service_natives, LOG_TAG);
return service_natives->GetNativeFunction(name, argument_count,
auto_setup_scope);
}
const uint8_t* GetSymbol(Dart_NativeFunction native_function) {
dart_utils::Check(service_natives, LOG_TAG);
return service_natives->GetSymbol(native_function);
}
#define SHUTDOWN_ON_ERROR(handle) \
if (Dart_IsError(handle)) { \
*error = strdup(Dart_GetError(handle)); \
FX_LOG(ERROR, LOG_TAG, *error); \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
return nullptr; \
}
void NotifyServerState(Dart_NativeArguments args) {
// NOP.
}
void Shutdown(Dart_NativeArguments args) {
// NOP.
}
void EmbedderInformationCallback(Dart_EmbedderInformation* info) {
info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION;
info->name = "dart_runner";
info->current_rss = -1;
info->max_rss = -1;
zx_info_task_stats_t task_stats;
zx_handle_t process = zx_process_self();
zx_status_t status = zx_object_get_info(
process, ZX_INFO_TASK_STATS, &task_stats, sizeof(task_stats), NULL, NULL);
if (status == ZX_OK) {
info->current_rss =
task_stats.mem_private_bytes + task_stats.mem_shared_bytes;
}
}
} // namespace
Dart_Isolate CreateServiceIsolate(
const char* uri,
Dart_IsolateFlags* flags_unused, // These flags are currently unused
char** error) {
Dart_SetEmbedderInformationCallback(EmbedderInformationCallback);
const uint8_t *vmservice_data = nullptr, *vmservice_instructions = nullptr;
#if defined(AOT_RUNTIME)
// The VM service was compiled as a separate app.
const char* snapshot_path = "/pkg/data/vmservice_snapshot.so";
if (elf_snapshot.Load(nullptr, snapshot_path)) {
vmservice_data = elf_snapshot.IsolateData();
vmservice_instructions = elf_snapshot.IsolateInstrs();
if (vmservice_data == nullptr || vmservice_instructions == nullptr) {
return nullptr;
}
} else {
// The VM service was compiled as a separate app.
const char* snapshot_data_path =
"/pkg/data/vmservice_isolate_snapshot_data.bin";
const char* snapshot_instructions_path =
"/pkg/data/vmservice_isolate_snapshot_instructions.bin";
#else
// The VM service is embedded in the core snapshot.
const char* snapshot_data_path = "/pkg/data/isolate_core_snapshot_data.bin";
const char* snapshot_instructions_path =
"/pkg/data/isolate_core_snapshot_instructions.bin";
#endif
if (!dart_utils::MappedResource::LoadFromNamespace(
nullptr, snapshot_data_path, mapped_isolate_snapshot_data)) {
*error = strdup("Failed to load snapshot for service isolate");
FX_LOG(ERROR, LOG_TAG, *error);
return nullptr;
}
if (!dart_utils::MappedResource::LoadFromNamespace(
nullptr, snapshot_instructions_path,
mapped_isolate_snapshot_instructions, true /* executable */)) {
*error = strdup("Failed to load snapshot for service isolate");
FX_LOG(ERROR, LOG_TAG, *error);
return nullptr;
}
vmservice_data = mapped_isolate_snapshot_data.address();
vmservice_instructions = mapped_isolate_snapshot_instructions.address();
#if defined(AOT_RUNTIME)
}
#endif
bool is_null_safe =
Dart_DetectNullSafety(nullptr, // script_uri
nullptr, // package_config
nullptr, // original_working_directory
vmservice_data, // snapshot_data
vmservice_instructions, // snapshot_instructions
nullptr, // kernel_buffer
0u // kernel_buffer_size
);
Dart_IsolateFlags flags;
Dart_IsolateFlagsInitialize(&flags);
flags.null_safety = is_null_safe;
auto state = new std::shared_ptr<tonic::DartState>(new tonic::DartState());
Dart_Isolate isolate = Dart_CreateIsolateGroup(
uri, DART_VM_SERVICE_ISOLATE_NAME, vmservice_data, vmservice_instructions,
&flags, state, state, error);
if (!isolate) {
FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolateGroup failed: %s", *error);
return nullptr;
}
state->get()->SetIsolate(isolate);
// Setup native entries.
service_natives = new tonic::DartLibraryNatives();
service_natives->Register({
{"VMServiceIO_NotifyServerState", NotifyServerState, 1, true},
{"VMServiceIO_Shutdown", Shutdown, 0, true},
});
Dart_EnterScope();
Dart_Handle library =
Dart_LookupLibrary(Dart_NewStringFromCString("dart:vmservice_io"));
SHUTDOWN_ON_ERROR(library);
Dart_Handle result = Dart_SetRootLibrary(library);
SHUTDOWN_ON_ERROR(result);
result = Dart_SetNativeResolver(library, GetNativeFunction, GetSymbol);
SHUTDOWN_ON_ERROR(result);
// _ip = '127.0.0.1'
result = Dart_SetField(library, Dart_NewStringFromCString("_ip"),
Dart_NewStringFromCString("127.0.0.1"));
SHUTDOWN_ON_ERROR(result);
// _port = 0
result = Dart_SetField(library, Dart_NewStringFromCString("_port"),
Dart_NewInteger(0));
SHUTDOWN_ON_ERROR(result);
// _autoStart = true
result = Dart_SetField(library, Dart_NewStringFromCString("_autoStart"),
Dart_NewBoolean(true));
SHUTDOWN_ON_ERROR(result);
// _originCheckDisabled = false
result =
Dart_SetField(library, Dart_NewStringFromCString("_originCheckDisabled"),
Dart_NewBoolean(false));
SHUTDOWN_ON_ERROR(result);
// _authCodesDisabled = false
result =
Dart_SetField(library, Dart_NewStringFromCString("_authCodesDisabled"),
Dart_NewBoolean(false));
SHUTDOWN_ON_ERROR(result);
InitBuiltinLibrariesForIsolate(std::string(uri), nullptr, fileno(stdout),
fileno(stderr), nullptr, zx::channel(), true);
// Make runnable.
Dart_ExitScope();
Dart_ExitIsolate();
*error = Dart_IsolateMakeRunnable(isolate);
if (*error != nullptr) {
FX_LOG(ERROR, LOG_TAG, *error);
Dart_EnterIsolate(isolate);
Dart_ShutdownIsolate();
return nullptr;
}
return isolate;
} // namespace dart_runner
Dart_Handle GetVMServiceAssetsArchiveCallback() {
dart_utils::MappedResource observatory_tar;
if (!dart_utils::MappedResource::LoadFromNamespace(
nullptr, "/pkg/data/observatory.tar", observatory_tar)) {
FX_LOG(ERROR, LOG_TAG, "Failed to load Observatory assets");
return nullptr;
}
// TODO(rmacnak): Should we avoid copying the tar? Or does the service
// library not hold onto it anyway?
return tonic::DartConverter<tonic::Uint8List>::ToDart(
reinterpret_cast<const uint8_t*>(observatory_tar.address()),
observatory_tar.size());
}
} // namespace dart_runner