Drew Fisher fb841071c2
fuchsia: remove use of replace_as_executable (second try) (#17313)
On Fuchsia, we can now get executable VMOs from trusted backing
filesystems.  This allows us to remove the use of replace_as_executable
in favor of opening files with `fdio_open_fd_at` with the
`OPEN_RIGHT_EXECUTABLE` flag and getting VMOs by calling
`fdio_get_vmo_exec`.

By moving the responsibility for executability into the filesystem, we
are able to remove `deprecated-ambient-replace-as-executable` from
component manifests for non-JIT runners (the JIT runners still call
replace_as_executable in Dart's allocator).  It wasn't abundantly clear
whether .cmx files for tests were used purely in AOT runtime
environments or also saw JIT usage, so I left those as-is.

For context: this is a second attempt at #16690, which was reverted
because it broke the Dart JIT runner.  The primary difference is that
this time around, we correctly handle absolute vs relative paths,
depending on whether library loading bottoms out in `fdio_open_fd` or
`fdio_open_fd_at`.  I've added additional assertions to help ensure any
new usages use the correct shape of path.

Testing: I verified locally that the flutter product runner works on
Astro, and also successfully ran the Dart JIT example test (which was
the thing blocking the google3 roll with the previous attempt at this
patchset).

Co-authored-by: Drew Fisher <zarvox@google.com>
2020-03-25 13:17:28 -07:00

211 lines
7.3 KiB
C++

// 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,
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
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,
nullptr /* 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