mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This updates to mojo commit d259eb58aa59 and limits the roll script to only pull in the parts of //mojo that are currently being used. More stuff will be dropped in the future.
730 lines
25 KiB
C++
730 lines
25 KiB
C++
// Copyright 2014 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 "base/bind.h"
|
|
#include "base/callback.h"
|
|
#include "base/files/file_util.h"
|
|
#include "base/logging.h"
|
|
#include "base/path_service.h"
|
|
#include "base/rand_util.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/sys_info.h"
|
|
#include "dart/runtime/include/dart_api.h"
|
|
#include "dart/runtime/include/dart_native_api.h"
|
|
#include "mojo/dart/embedder/builtin.h"
|
|
#include "mojo/dart/embedder/dart_controller.h"
|
|
#include "mojo/dart/embedder/mojo_dart_state.h"
|
|
#include "mojo/dart/embedder/vmservice.h"
|
|
#include "mojo/message_pump/message_pump_mojo.h"
|
|
#include "mojo/public/c/system/core.h"
|
|
#include "tonic/dart_converter.h"
|
|
#include "tonic/dart_debugger.h"
|
|
#include "tonic/dart_dependency_catcher.h"
|
|
#include "tonic/dart_error.h"
|
|
#include "tonic/dart_library_loader.h"
|
|
#include "tonic/dart_library_provider.h"
|
|
#include "tonic/dart_library_provider_files.h"
|
|
#include "tonic/dart_library_provider_network.h"
|
|
#include "tonic/dart_script_loader_sync.h"
|
|
|
|
namespace mojo {
|
|
namespace dart {
|
|
|
|
extern const uint8_t* vm_isolate_snapshot_buffer;
|
|
extern const uint8_t* isolate_snapshot_buffer;
|
|
|
|
static const char* kAsyncLibURL = "dart:async";
|
|
static const char* kInternalLibURL = "dart:_internal";
|
|
static const char* kIsolateLibURL = "dart:isolate";
|
|
static const char* kCoreLibURL = "dart:core";
|
|
|
|
static uint8_t snapshot_magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
|
|
|
|
static Dart_Handle SetWorkingDirectory(Dart_Handle builtin_lib) {
|
|
base::FilePath current_dir;
|
|
PathService::Get(base::DIR_CURRENT, ¤t_dir);
|
|
|
|
const int kNumArgs = 1;
|
|
Dart_Handle dart_args[kNumArgs];
|
|
std::string current_dir_string = current_dir.AsUTF8Unsafe();
|
|
dart_args[0] = Dart_NewStringFromUTF8(
|
|
reinterpret_cast<const uint8_t*>(current_dir_string.data()),
|
|
current_dir_string.length());
|
|
return Dart_Invoke(builtin_lib,
|
|
Dart_NewStringFromCString("_setWorkingDirectory"),
|
|
kNumArgs,
|
|
dart_args);
|
|
}
|
|
|
|
static Dart_Handle ResolveScriptUri(Dart_Handle builtin_lib, Dart_Handle uri) {
|
|
const int kNumArgs = 1;
|
|
Dart_Handle dart_args[kNumArgs];
|
|
dart_args[0] = uri;
|
|
return Dart_Invoke(builtin_lib,
|
|
Dart_NewStringFromCString("_resolveScriptUri"),
|
|
kNumArgs,
|
|
dart_args);
|
|
}
|
|
|
|
static Dart_Handle PrepareIsolateLibraries(const std::string& package_root,
|
|
const std::string& script_uri) {
|
|
// First ensure all required libraries are available.
|
|
Dart_Handle builtin_lib = Builtin::GetLibrary(Builtin::kBuiltinLibrary);
|
|
Dart_Handle url = Dart_NewStringFromCString(kInternalLibURL);
|
|
DART_CHECK_VALID(url);
|
|
Dart_Handle internal_lib = Dart_LookupLibrary(url);
|
|
DART_CHECK_VALID(internal_lib);
|
|
url = Dart_NewStringFromCString(kCoreLibURL);
|
|
DART_CHECK_VALID(url);
|
|
Dart_Handle core_lib = Dart_LookupLibrary(url);
|
|
DART_CHECK_VALID(internal_lib);
|
|
url = Dart_NewStringFromCString(kAsyncLibURL);
|
|
DART_CHECK_VALID(url);
|
|
Dart_Handle async_lib = Dart_LookupLibrary(url);
|
|
DART_CHECK_VALID(async_lib);
|
|
url = Dart_NewStringFromCString(kIsolateLibURL);
|
|
DART_CHECK_VALID(url);
|
|
Dart_Handle isolate_lib = Dart_LookupLibrary(url);
|
|
DART_CHECK_VALID(isolate_lib);
|
|
Dart_Handle mojo_internal_lib =
|
|
Builtin::GetLibrary(Builtin::kMojoInternalLibrary);
|
|
DART_CHECK_VALID(mojo_internal_lib);
|
|
|
|
// We need to ensure that all the scripts loaded so far are finalized
|
|
// as we are about to invoke some Dart code below to setup closures.
|
|
Dart_Handle result = Dart_FinalizeLoading(false);
|
|
DART_CHECK_VALID(result);
|
|
|
|
// Import dart:_internal into dart:mojo.builtin for setting up hooks.
|
|
result = Dart_LibraryImportLibrary(builtin_lib, internal_lib, Dart_Null());
|
|
DART_CHECK_VALID(result);
|
|
|
|
// Setup the internal library's 'internalPrint' function.
|
|
Dart_Handle print = Dart_Invoke(builtin_lib,
|
|
Dart_NewStringFromCString("_getPrintClosure"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(print);
|
|
result = Dart_SetField(internal_lib,
|
|
Dart_NewStringFromCString("_printClosure"),
|
|
print);
|
|
DART_CHECK_VALID(result);
|
|
|
|
DART_CHECK_VALID(Dart_Invoke(
|
|
builtin_lib, Dart_NewStringFromCString("_setupHooks"), 0, nullptr));
|
|
DART_CHECK_VALID(Dart_Invoke(
|
|
isolate_lib, Dart_NewStringFromCString("_setupHooks"), 0, nullptr));
|
|
|
|
// Setup the 'scheduleImmediate' closure.
|
|
Dart_Handle schedule_immediate_closure = Dart_Invoke(
|
|
isolate_lib,
|
|
Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure"),
|
|
0,
|
|
nullptr);
|
|
Dart_Handle schedule_args[1];
|
|
schedule_args[0] = schedule_immediate_closure;
|
|
result = Dart_Invoke(
|
|
async_lib,
|
|
Dart_NewStringFromCString("_setScheduleImmediateClosure"),
|
|
1,
|
|
schedule_args);
|
|
DART_CHECK_VALID(result);
|
|
|
|
// Set current working directory.
|
|
result = SetWorkingDirectory(builtin_lib);
|
|
if (Dart_IsError(result)) {
|
|
return result;
|
|
}
|
|
|
|
// Set script entry uri.
|
|
Dart_Handle uri = Dart_NewStringFromUTF8(
|
|
reinterpret_cast<const uint8_t*>(script_uri.c_str()),
|
|
script_uri.length());
|
|
DART_CHECK_VALID(uri);
|
|
result = ResolveScriptUri(builtin_lib, uri);
|
|
|
|
// Set up package root.
|
|
result = Dart_NewStringFromUTF8(
|
|
reinterpret_cast<const uint8_t*>(package_root.c_str()),
|
|
package_root.length());
|
|
DART_CHECK_VALID(result);
|
|
|
|
const int kNumArgs = 1;
|
|
Dart_Handle dart_args[kNumArgs];
|
|
dart_args[0] = result;
|
|
result = Dart_Invoke(builtin_lib,
|
|
Dart_NewStringFromCString("_setPackageRoot"),
|
|
kNumArgs,
|
|
dart_args);
|
|
DART_CHECK_VALID(result);
|
|
|
|
// Setup the uriBase with the base uri of the mojo app.
|
|
Dart_Handle uri_base = Dart_Invoke(
|
|
builtin_lib,
|
|
Dart_NewStringFromCString("_getUriBaseClosure"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(uri_base);
|
|
result = Dart_SetField(core_lib,
|
|
Dart_NewStringFromCString("_uriBaseClosure"),
|
|
uri_base);
|
|
DART_CHECK_VALID(result);
|
|
return result;
|
|
}
|
|
|
|
static const intptr_t kStartIsolateArgumentsLength = 2;
|
|
|
|
static void SetupStartIsolateArguments(
|
|
const DartControllerConfig& config,
|
|
Dart_Handle main_closure,
|
|
Dart_Handle* start_isolate_args) {
|
|
// start_isolate_args:
|
|
// [0] -> main closure
|
|
// [1] -> args list.
|
|
// args list:
|
|
// [0] -> mojo handle.
|
|
// [1] -> script uri
|
|
// [2] -> list of script arguments in config.
|
|
start_isolate_args[0] = main_closure; // entryPoint
|
|
DART_CHECK_VALID(start_isolate_args[0]);
|
|
start_isolate_args[1] = Dart_NewList(3); // args
|
|
DART_CHECK_VALID(start_isolate_args[1]);
|
|
Dart_Handle script_uri = Dart_NewStringFromUTF8(
|
|
reinterpret_cast<const uint8_t*>(config.script_uri.data()),
|
|
config.script_uri.length());
|
|
Dart_ListSetAt(start_isolate_args[1], 0, Dart_NewInteger(config.handle));
|
|
Dart_ListSetAt(start_isolate_args[1], 1, script_uri);
|
|
Dart_Handle script_args = Dart_NewList(config.script_flags_count);
|
|
DART_CHECK_VALID(script_args);
|
|
Dart_ListSetAt(start_isolate_args[1], 2, script_args);
|
|
for (intptr_t i = 0; i < config.script_flags_count; i++) {
|
|
Dart_ListSetAt(script_args, i,
|
|
Dart_NewStringFromCString(config.script_flags[i]));
|
|
}
|
|
}
|
|
|
|
static void RunIsolate(Dart_Isolate isolate,
|
|
const DartControllerConfig& config) {
|
|
tonic::DartIsolateScope isolate_scope(isolate);
|
|
tonic::DartApiScope api_scope;
|
|
|
|
Dart_Handle result;
|
|
|
|
// Load the root library into the builtin library so that main can be found.
|
|
Dart_Handle builtin_lib =
|
|
Builtin::GetLibrary(Builtin::kBuiltinLibrary);
|
|
DART_CHECK_VALID(builtin_lib);
|
|
Dart_Handle root_lib = Dart_RootLibrary();
|
|
DART_CHECK_VALID(root_lib);
|
|
result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
|
|
DART_CHECK_VALID(result);
|
|
|
|
if (config.compile_all) {
|
|
result = Dart_CompileAll();
|
|
DART_CHECK_VALID(result);
|
|
}
|
|
|
|
Dart_Handle main_closure = Dart_Invoke(
|
|
builtin_lib,
|
|
Dart_NewStringFromCString("_getMainClosure"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(main_closure);
|
|
|
|
Dart_Handle start_isolate_args[kStartIsolateArgumentsLength];
|
|
SetupStartIsolateArguments(config, main_closure, &start_isolate_args[0]);
|
|
Dart_Handle isolate_lib =
|
|
Dart_LookupLibrary(Dart_NewStringFromCString(kIsolateLibURL));
|
|
DART_CHECK_VALID(isolate_lib);
|
|
|
|
result = Dart_Invoke(isolate_lib,
|
|
Dart_NewStringFromCString("_startMainIsolate"),
|
|
kStartIsolateArgumentsLength,
|
|
start_isolate_args);
|
|
DART_CHECK_VALID(result);
|
|
|
|
result = Dart_RunLoop();
|
|
tonic::LogIfError(result);
|
|
DART_CHECK_VALID(result);
|
|
}
|
|
|
|
Dart_Handle DartController::LibraryTagHandler(Dart_LibraryTag tag,
|
|
Dart_Handle library,
|
|
Dart_Handle url) {
|
|
if (tag == Dart_kCanonicalizeUrl) {
|
|
std::string string = tonic::StdStringFromDart(url);
|
|
if (StartsWithASCII(string, "dart:", true))
|
|
return url;
|
|
}
|
|
return tonic::DartLibraryLoader::HandleLibraryTag(tag, library, url);
|
|
}
|
|
|
|
Dart_Isolate DartController::CreateIsolateHelper(
|
|
void* dart_app,
|
|
bool strict_compilation,
|
|
IsolateCallbacks callbacks,
|
|
const std::string& script_uri,
|
|
const std::string& package_root,
|
|
char** error,
|
|
bool use_network_loader) {
|
|
auto isolate_data = new MojoDartState(dart_app,
|
|
strict_compilation,
|
|
callbacks,
|
|
script_uri,
|
|
package_root);
|
|
Dart_Isolate isolate =
|
|
Dart_CreateIsolate(script_uri.c_str(), "main", isolate_snapshot_buffer,
|
|
nullptr, isolate_data, error);
|
|
if (isolate == nullptr) {
|
|
delete isolate_data;
|
|
return nullptr;
|
|
}
|
|
Dart_ExitIsolate();
|
|
|
|
isolate_data->SetIsolate(isolate);
|
|
if (service_connector_ != nullptr) {
|
|
// This is not supported in the unit test harness.
|
|
isolate_data->BindNetworkService(
|
|
service_connector_->ConnectToService(
|
|
DartControllerServiceConnector::kNetworkServiceId));
|
|
}
|
|
|
|
// Setup isolate and load script.
|
|
{
|
|
tonic::DartIsolateScope isolate_scope(isolate);
|
|
tonic::DartApiScope api_scope;
|
|
// Setup loader.
|
|
const char* package_root_str = nullptr;
|
|
if (package_root.empty()) {
|
|
package_root_str = "/";
|
|
} else {
|
|
package_root_str = package_root.c_str();
|
|
}
|
|
isolate_data->library_loader().set_magic_number(
|
|
snapshot_magic_number, sizeof(snapshot_magic_number));
|
|
if (use_network_loader) {
|
|
mojo::NetworkService* network_service = isolate_data->network_service();
|
|
isolate_data->set_library_provider(
|
|
new tonic::DartLibraryProviderNetwork(network_service));
|
|
} else {
|
|
isolate_data->set_library_provider(
|
|
new tonic::DartLibraryProviderFiles(
|
|
base::FilePath(package_root_str)));
|
|
}
|
|
Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler);
|
|
DART_CHECK_VALID(result);
|
|
// Toggle checked mode.
|
|
Dart_IsolateSetStrictCompilation(strict_compilation);
|
|
// Setup the native resolvers for the builtin libraries as they are not set
|
|
// up when the snapshot is read.
|
|
CHECK(isolate_snapshot_buffer != nullptr);
|
|
Builtin::PrepareLibrary(Builtin::kBuiltinLibrary);
|
|
Builtin::PrepareLibrary(Builtin::kMojoInternalLibrary);
|
|
Builtin::PrepareLibrary(Builtin::kDartMojoIoLibrary);
|
|
|
|
// TODO(johnmccutchan): Remove?
|
|
if (!callbacks.create.is_null()) {
|
|
DCHECK(false);
|
|
callbacks.create.Run(script_uri.c_str(),
|
|
"main",
|
|
package_root.c_str(),
|
|
isolate_data,
|
|
error);
|
|
}
|
|
|
|
// Prepare builtin and its dependent libraries.
|
|
result = PrepareIsolateLibraries(package_root, script_uri);
|
|
DART_CHECK_VALID(result);
|
|
|
|
// The VM is creating the service isolate.
|
|
if (Dart_IsServiceIsolate(isolate)) {
|
|
const intptr_t port = SupportDartMojoIo() ? 0 : -1;
|
|
InitializeDartMojoIo();
|
|
StartHandleWatcherIsolate();
|
|
if (!VmService::Setup("127.0.0.1", port)) {
|
|
*error = strdup(VmService::GetErrorMessage());
|
|
return nullptr;
|
|
}
|
|
return isolate;
|
|
}
|
|
|
|
if ((script_uri == "vm-service") || (script_uri == "stop-handle-watcher")) {
|
|
// Special case for starting and stopping the the handle watcher isolate.
|
|
LoadEmptyScript(script_uri);
|
|
} else {
|
|
tonic::DartScriptLoaderSync::LoadScript(
|
|
script_uri,
|
|
isolate_data->library_provider());
|
|
}
|
|
|
|
InitializeDartMojoIo();
|
|
}
|
|
|
|
if (isolate_data->library_loader().error_during_loading()) {
|
|
*error = strdup("Library loader reported error during loading. See log.");
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
return nullptr;
|
|
}
|
|
|
|
// Make the isolate runnable so that it is ready to handle messages.
|
|
bool retval = Dart_IsolateMakeRunnable(isolate);
|
|
if (!retval) {
|
|
*error = strdup("Invalid isolate state - Unable to make it runnable");
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
return nullptr;
|
|
}
|
|
|
|
DCHECK(Dart_CurrentIsolate() == nullptr);
|
|
|
|
return isolate;
|
|
}
|
|
|
|
Dart_Isolate DartController::IsolateCreateCallback(const char* script_uri,
|
|
const char* main,
|
|
const char* package_root,
|
|
Dart_IsolateFlags* flags,
|
|
void* callback_data,
|
|
char** error) {
|
|
auto parent_isolate_data = MojoDartState::Cast(callback_data);
|
|
std::string script_uri_string;
|
|
std::string package_root_string;
|
|
|
|
if (script_uri == nullptr) {
|
|
if (callback_data == nullptr) {
|
|
*error = strdup("Invalid 'callback_data' - Unable to spawn new isolate");
|
|
return nullptr;
|
|
}
|
|
script_uri_string = parent_isolate_data->script_uri();
|
|
} else {
|
|
script_uri_string = std::string(script_uri);
|
|
}
|
|
if (package_root == nullptr) {
|
|
if (parent_isolate_data != nullptr) {
|
|
package_root_string = parent_isolate_data->package_root();
|
|
}
|
|
} else {
|
|
package_root_string = std::string(package_root);
|
|
}
|
|
// Inherit parameters from parent isolate (if any).
|
|
void* dart_app = nullptr;
|
|
bool strict_compilation = true;
|
|
// TODO(johnmccutchan): Use parent's setting?
|
|
bool use_network_loader = false;
|
|
IsolateCallbacks callbacks;
|
|
if (parent_isolate_data != nullptr) {
|
|
dart_app = parent_isolate_data->application_data();
|
|
strict_compilation = parent_isolate_data->strict_compilation();
|
|
callbacks = parent_isolate_data->callbacks();
|
|
}
|
|
return CreateIsolateHelper(dart_app,
|
|
strict_compilation,
|
|
callbacks,
|
|
script_uri_string,
|
|
package_root_string,
|
|
error,
|
|
use_network_loader);
|
|
}
|
|
|
|
void DartController::IsolateShutdownCallback(void* callback_data) {
|
|
{
|
|
tonic::DartApiScope api_scope;
|
|
ShutdownDartMojoIo();
|
|
}
|
|
|
|
auto isolate_data = MojoDartState::Cast(callback_data);
|
|
if (!isolate_data->callbacks().shutdown.is_null()) {
|
|
isolate_data->callbacks().shutdown.Run(callback_data);
|
|
}
|
|
delete isolate_data;
|
|
}
|
|
|
|
void DartController::UnhandledExceptionCallback(Dart_Handle error) {
|
|
auto isolate_data = MojoDartState::Current();
|
|
if (!isolate_data->callbacks().exception.is_null()) {
|
|
// TODO(zra): Instead of passing an error handle, it may make life easier
|
|
// for clients if we pass any error string here instead.
|
|
isolate_data->callbacks().exception.Run(error);
|
|
}
|
|
|
|
// Close handles generated by the isolate.
|
|
std::set<MojoHandle>& handles = isolate_data->unclosed_handles();
|
|
for (auto it = handles.begin(); it != handles.end(); ++it) {
|
|
MojoClose((*it));
|
|
}
|
|
handles.clear();
|
|
}
|
|
|
|
|
|
bool DartController::initialized_ = false;
|
|
bool DartController::service_isolate_running_ = false;
|
|
bool DartController::strict_compilation_ = false;
|
|
DartControllerServiceConnector* DartController::service_connector_ = nullptr;
|
|
base::Lock DartController::lock_;
|
|
|
|
bool DartController::SupportDartMojoIo() {
|
|
return service_connector_ != nullptr;
|
|
}
|
|
|
|
void DartController::InitializeDartMojoIo() {
|
|
Dart_Isolate current_isolate = Dart_CurrentIsolate();
|
|
CHECK(current_isolate != nullptr);
|
|
if (!SupportDartMojoIo()) {
|
|
return;
|
|
}
|
|
CHECK(service_connector_ != nullptr);
|
|
MojoHandle network_service_mojo_handle = MOJO_HANDLE_INVALID;
|
|
network_service_mojo_handle =
|
|
service_connector_->ConnectToService(
|
|
DartControllerServiceConnector::kNetworkServiceId);
|
|
if (network_service_mojo_handle == MOJO_HANDLE_INVALID) {
|
|
// Not supported.
|
|
return;
|
|
}
|
|
// Pass handle into 'dart:io' library.
|
|
Dart_Handle mojo_io_library =
|
|
Builtin::GetLibrary(Builtin::kDartMojoIoLibrary);
|
|
CHECK(!Dart_IsError(mojo_io_library));
|
|
Dart_Handle method_name = Dart_NewStringFromCString("_initialize");
|
|
CHECK(!Dart_IsError(method_name));
|
|
Dart_Handle network_service_handle =
|
|
Dart_NewInteger(network_service_mojo_handle);
|
|
CHECK(!Dart_IsError(network_service_handle));
|
|
Dart_Handle result = Dart_Invoke(mojo_io_library,
|
|
method_name,
|
|
1,
|
|
&network_service_handle);
|
|
CHECK(!Dart_IsError(result));
|
|
}
|
|
|
|
void DartController::ShutdownDartMojoIo() {
|
|
Dart_Isolate current_isolate = Dart_CurrentIsolate();
|
|
CHECK(current_isolate != nullptr);
|
|
if (!SupportDartMojoIo()) {
|
|
return;
|
|
}
|
|
Dart_Handle mojo_io_library =
|
|
Builtin::GetLibrary(Builtin::kDartMojoIoLibrary);
|
|
CHECK(!Dart_IsError(mojo_io_library));
|
|
Dart_Handle method_name = Dart_NewStringFromCString("_shutdown");
|
|
CHECK(!Dart_IsError(method_name));
|
|
Dart_Handle result = Dart_Invoke(mojo_io_library,
|
|
method_name,
|
|
0,
|
|
nullptr);
|
|
if (Dart_IsError(result)) {
|
|
Dart_PropagateError(result);
|
|
}
|
|
}
|
|
|
|
void DartController::StartHandleWatcherIsolate() {
|
|
Dart_Handle result;
|
|
|
|
// Start the Mojo handle watcher isolate.
|
|
Dart_Handle mojo_core_lib =
|
|
Builtin::GetLibrary(Builtin::kMojoInternalLibrary);
|
|
DART_CHECK_VALID(mojo_core_lib);
|
|
Dart_Handle handle_watcher_type = Dart_GetType(
|
|
mojo_core_lib,
|
|
Dart_NewStringFromCString("MojoHandleWatcher"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(handle_watcher_type);
|
|
result = Dart_Invoke(
|
|
handle_watcher_type,
|
|
Dart_NewStringFromCString("_start"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(result);
|
|
}
|
|
|
|
// TODO(johnmccutchan): Move handle watcher shutdown into the service isolate
|
|
// once the VM can shutdown cleanly.
|
|
void DartController::StopHandleWatcherIsolate() {
|
|
// Spin up an isolate to initiate the handle watcher shutdown.
|
|
IsolateCallbacks callbacks;
|
|
char* error;
|
|
Dart_Isolate shutdown_isolate = CreateIsolateHelper(
|
|
nullptr, false, callbacks, "stop-handle-watcher", "", &error, false);
|
|
CHECK(shutdown_isolate);
|
|
|
|
Dart_EnterIsolate(shutdown_isolate);
|
|
Dart_EnterScope();
|
|
Dart_Handle result;
|
|
|
|
// Stop the Mojo handle watcher isolate.
|
|
Dart_Handle mojo_core_lib =
|
|
Builtin::GetLibrary(Builtin::kMojoInternalLibrary);
|
|
DART_CHECK_VALID(mojo_core_lib);
|
|
Dart_Handle handle_watcher_type = Dart_GetType(
|
|
mojo_core_lib,
|
|
Dart_NewStringFromCString("MojoHandleWatcher"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(handle_watcher_type);
|
|
result = Dart_Invoke(
|
|
handle_watcher_type,
|
|
Dart_NewStringFromCString("_stop"),
|
|
0,
|
|
nullptr);
|
|
DART_CHECK_VALID(result);
|
|
|
|
// Run until the handle watcher isolate has exited.
|
|
result = Dart_RunLoop();
|
|
tonic::LogIfError(result);
|
|
DART_CHECK_VALID(result);
|
|
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
void DartController::InitVmIfNeeded(Dart_EntropySource entropy,
|
|
const char** vm_flags,
|
|
int vm_flags_count) {
|
|
base::AutoLock al(lock_);
|
|
if (initialized_) {
|
|
return;
|
|
}
|
|
|
|
const int kNumFlags = vm_flags_count + 1;
|
|
const char* flags[kNumFlags];
|
|
|
|
// TODO(zra): Fix Dart VM Shutdown race.
|
|
// There is a bug in Dart VM shutdown which causes its thread pool threads
|
|
// to potentially fail to exit when the rest of the VM is going down. This
|
|
// results in a segfault if they begin running again after the Dart
|
|
// embedder has been unloaded. Setting this flag to 0 ensures that these
|
|
// threads sleep forever instead of waking up and trying to run code
|
|
// that isn't there anymore.
|
|
flags[0] = "--worker-timeout-millis=0";
|
|
|
|
for (int i = 0; i < vm_flags_count; ++i) {
|
|
flags[i + 1] = vm_flags[i];
|
|
}
|
|
|
|
bool result = Dart_SetVMFlags(kNumFlags, flags);
|
|
CHECK(result);
|
|
|
|
// This should be called before calling Dart_Initialize.
|
|
tonic::DartDebugger::InitDebugger();
|
|
|
|
result = Dart_Initialize(vm_isolate_snapshot_buffer,
|
|
IsolateCreateCallback,
|
|
nullptr, // Isolate interrupt callback.
|
|
UnhandledExceptionCallback,
|
|
IsolateShutdownCallback,
|
|
// File IO callbacks.
|
|
nullptr, nullptr, nullptr, nullptr,
|
|
entropy);
|
|
CHECK(result);
|
|
initialized_ = true;
|
|
}
|
|
|
|
void DartController::BlockForServiceIsolate() {
|
|
base::AutoLock al(lock_);
|
|
BlockForServiceIsolateLocked();
|
|
}
|
|
|
|
void DartController::BlockForServiceIsolateLocked() {
|
|
if (service_isolate_running_) {
|
|
return;
|
|
}
|
|
// By waiting for the load port, we ensure that the service isolate is fully
|
|
// running before returning.
|
|
Dart_ServiceWaitForLoadPort();
|
|
service_isolate_running_ = true;
|
|
}
|
|
|
|
void DartController::LoadEmptyScript(const std::string& script_uri) {
|
|
Dart_Handle uri = Dart_NewStringFromUTF8(
|
|
reinterpret_cast<const uint8_t*>(script_uri.c_str()),
|
|
script_uri.length());
|
|
DART_CHECK_VALID(uri);
|
|
Dart_Handle script_source = Dart_NewStringFromCString("");
|
|
DART_CHECK_VALID(script_source);
|
|
Dart_Handle result = Dart_LoadScript(uri, script_source, 0, 0);
|
|
DART_CHECK_VALID(result);
|
|
tonic::LogIfError(Dart_FinalizeLoading(true));
|
|
}
|
|
|
|
bool DartController::RunSingleDartScript(const DartControllerConfig& config) {
|
|
InitVmIfNeeded(config.entropy,
|
|
config.vm_flags,
|
|
config.vm_flags_count);
|
|
BlockForServiceIsolate();
|
|
Dart_Isolate isolate = CreateIsolateHelper(config.application_data,
|
|
config.strict_compilation,
|
|
config.callbacks,
|
|
config.script_uri,
|
|
config.package_root,
|
|
config.error,
|
|
config.use_network_loader);
|
|
if (isolate == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
RunIsolate(isolate, config);
|
|
|
|
// Cleanup.
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
Dart_Cleanup();
|
|
return true;
|
|
}
|
|
|
|
static bool generateEntropy(uint8_t* buffer, intptr_t length) {
|
|
base::RandBytes(reinterpret_cast<void*>(buffer), length);
|
|
return true;
|
|
}
|
|
|
|
bool DartController::Initialize(
|
|
DartControllerServiceConnector* service_connector,
|
|
bool strict_compilation) {
|
|
service_connector_ = service_connector;
|
|
strict_compilation_ = strict_compilation;
|
|
InitVmIfNeeded(generateEntropy, nullptr, 0);
|
|
return true;
|
|
}
|
|
|
|
bool DartController::RunDartScript(const DartControllerConfig& config) {
|
|
BlockForServiceIsolate();
|
|
CHECK(service_isolate_running_);
|
|
const bool strict = strict_compilation_ || config.strict_compilation;
|
|
Dart_Isolate isolate = CreateIsolateHelper(config.application_data,
|
|
strict,
|
|
config.callbacks,
|
|
config.script_uri,
|
|
config.package_root,
|
|
config.error,
|
|
config.use_network_loader);
|
|
if (isolate == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
RunIsolate(isolate, config);
|
|
|
|
// Cleanup.
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
|
|
return true;
|
|
}
|
|
|
|
void DartController::Shutdown() {
|
|
base::AutoLock al(lock_);
|
|
if (!initialized_) {
|
|
return;
|
|
}
|
|
BlockForServiceIsolateLocked();
|
|
StopHandleWatcherIsolate();
|
|
Dart_Cleanup();
|
|
service_isolate_running_ = false;
|
|
initialized_ = false;
|
|
}
|
|
|
|
} // namespace apps
|
|
} // namespace mojo
|