mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
* Roll src/third_party/dart 67ab3be10d...b5aeaa6796 dart-lang/sdk@b5aeaa6796 Revert "Reland "[vm/ffi] SimDBC on Arm64 Android"" dart-lang/sdk@02fe07bbd3 [dart2js] new-rti: Set Array instance type dart-lang/sdk@bae5bdefd5 [dart2js] Add '--golem-x' command-line flag dart-lang/sdk@ac30ab12ab [dartdevc] Bump pedantic to v1.8.0 and apply new lints dart-lang/sdk@4b0c5c166a fix field name dart-lang/sdk@327f5eb826 Fix for issue 37429 dart-lang/sdk@43891316ca [ VM / Observatory ] Emit IsolateReload event after reload completes dart-lang/sdk@2ea7e5513b Perform type promotion when NNBD, using flow analysis. dart-lang/sdk@766e542e53 handle return in async function dart-lang/sdk@51cf8f218a Add entension support to the summary idl dart-lang/sdk@0e9957c7b1 [dartdevc] Adding support for analyzer dep pruning dart-lang/sdk@c100308ba6 Repro for inferring arrays with out of range lengths dart-lang/sdk@5d77657e7a Prepare to publish analyzer version 0.37.0. dart-lang/sdk@86ce74caaa update NodeBuilder for default value type arguments dart-lang/sdk@439692c9e2 Mark the name in an extension as being in a declaration context dart-lang/sdk@372bcae536 [gardening] Fix 3xHEAD Flutter build after revert dart-lang/sdk@052874e93e Avoid non-web integer literal in corelib_2/int_round_test dart-lang/sdk@480337106e Implementation of extension override AST node dart-lang/sdk@4f78ad90df An initial and partial implementation of an element model for extensions dart-lang/sdk@744bb47361 [infra] Remove custom timeouts for dart2js compiler config dart-lang/sdk@9b53686ffb update NodeBuilder for declared identifier implicit type dart-lang/sdk@3d14b75f97 Revert "Reland "[vm/concurrency] Introduce concept of Isolate Groups"" dart-lang/sdk@527238e008 [vm] Cleanup C99 header includes dart-lang/sdk@9f32f9b87e [cfe] Store the initializer tokens in constructor builders dart-lang/sdk@bbbeb8b509 Pull in latest pub dart-lang/sdk@851958ee54 update NodeBuilder to handle for loop dart-lang/sdk@7a73682c6a update NodeBuilder to handle catch clause dart-lang/sdk@fc6cb0ac21 [vm/ffi] Revamp struct representation in FFI. dart-lang/sdk@5fd51b9fd2 Cleanup remnants of ignoring Dart v1.x subtype checks dart-lang/sdk@45172f0690 Revert "Reland "[llvm] Add initial scaffolding"" dart-lang/sdk@b9a6630367 [ Observatory ] _getVMTimeline -> getVMTimeline in timeline.js dart-lang/sdk@1f02c10b9a Update language_2/const_map4_test for type inference dart-lang/sdk@99ed4871b3 Fix a hint in analysis server dart-lang/sdk@c3c43689d5 [vm] Remove platform/math.h dart-lang/sdk@524fdc13a9 Reland "[llvm] Add initial scaffolding" dart-lang/sdk@45a9815aff [vm/debugger] break on asyncfunction entry dart-lang/sdk@e0eeffaf9b update NodeBuilder parameter tracking when visiting executable declarations dart-lang/sdk@182a59cebb Skip all tests that use spawnUri when running in simulator mode as it makes no sense to run the CFE on the simulator. dart-lang/sdk@1427a218f3 update DecoratedType asserts dart-lang/sdk@f4dc001729 Migration: begin adding support for LUB computations in conditional expressions. dart-lang/sdk@585794ab75 Fix status file line. dart-lang/sdk@4a69ef4a50 Skip all spawnURI tests for the simulator architectures as these tests involve invoking the front end for compilation which would mean the front end has to run in simulated mode. dart-lang/sdk@26f369eb8e Fix doc comment for NullabilityNode.forLUB dart-lang/sdk@9ed728ec7a Add: Example usage to fillRange method. dart-lang/sdk@fc7049ae7d Migration: implement support for user-definable prefix expressions. dart-lang/sdk@77aa5f0c02 Migration: Add support for function-typed formal parameters. dart-lang/sdk@326e970b81 Migration: handle method invocations that resolve to a getter. dart-lang/sdk@822de210b5 fix branch_canonicalization_test dart-lang/sdk@a2e1434603 Breaking changes for analyzer version 0.37 dart-lang/sdk@6694aa821d [dart2js] new-rti: Temporary work-around for timeouts dart-lang/sdk@18ff5ce893 [dart2js] new-rti: Implement general As/Check methods dart-lang/sdk@90c88d984e Fix large integer literals in dart2js_extra/round_constant_folding_test dart-lang/sdk@9349f71721 bump linter to 0.1.93 dart-lang/sdk@c384212f9e [vm] Remove vestigial verified_memory_test.cc file dart-lang/sdk@f4824d332d [vm] Drop support for MSVC older than 2013 dart-lang/sdk@bbb027aa2a [vm] Fix offset that was breaking bare_instructions_trampolines_test dart-lang/sdk@1db0b4436c [dart2js] new-rti: Implement type bounds check dart-lang/sdk@686742585a Migration: add a more robust assertion to the DecoratedType constructor dart-lang/sdk@2fd4ca570b set DecoratedType.returnType for FunctionType dart-lang/sdk@ca4b6e533a [dart2js] new-rti: Implement basic is-test dart-lang/sdk@39b71253ce Fix for curly_braces_in_flow_control_structures lint. dart-lang/sdk@b6c3b2c98c Enable 'Surround with XYZ' only for Statement(s) in Block(s). dart-lang/sdk@79e478e50e Fixed some links dart-lang/sdk@279c1da42d Use absolute paths as canonical paths for inputs digest maps dart-lang/sdk@cbf9cff19f Infer types of field formals before all fields. dart-lang/sdk@0c6b3d1277 Migration: do better function type formatting in DecoratedType.toString. dart-lang/sdk@a76c459239 Migration: Remove unnecessary duplicate type test dart-lang/sdk@a515a0c256 Reland "[vm/ffi] SimDBC on Arm64 Android" dart-lang/sdk@0baf81e7d6 Tests for Never and potential nullable / non-nullable. dart-lang/sdk@26d308aad3 Use flow analysis for reporting use sites of not assigned locals during resolution. dart-lang/sdk@79f276e07d Migration: handle field formal parameters. dart-lang/sdk@c8c3572ca9 Migration: standardize method names in EdgeBuilderTest. dart-lang/sdk@c0c15c1283 Migration: build nullability node for default type parameter bounds directly. dart-lang/sdk@b57ff85906 Migration: clean up and test implicit dynamic return type of Function() syntax. dart-lang/sdk@0f2eda8644 Migration: add support for function expression invocations. dart-lang/sdk@a200980da0 Migration: add support for variable and field type inference. dart-lang/sdk@ca25f56883 Migration: add support for type inference of function types. dart-lang/sdk@a436c0621f Migration: fix DecoratedType.toString to support named function parameters. dart-lang/sdk@9dee307bdb Migration: update nullability graph debug dump to support union edges. dart-lang/sdk@b60dcdbf73 Migration: Remove the `create` parameter from Variables.decoratedElementType. dart-lang/sdk@18c21ee9d1 Migration: add support for generic instance creation. dart-lang/sdk@f7ddfdf6ca Migration: don't forget to visit variable initializers in NodeBuilder. dart-lang/sdk@a39e4fabfb Add information about the deprecated ParameterElement.parameterKind dart-lang/sdk@f6dfad02f4 [analyzer] add a space to the quick for for REPLACE_COLON_WITH_EQUALS * Update license.
532 lines
16 KiB
C++
532 lines
16 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 "dart_component_controller.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <lib/async-loop/loop.h>
|
|
#include <lib/async/cpp/task.h>
|
|
#include <lib/async/default.h>
|
|
#include <lib/fdio/directory.h>
|
|
#include <lib/fdio/fd.h>
|
|
#include <lib/fdio/namespace.h>
|
|
#include <lib/fidl/cpp/optional.h>
|
|
#include <lib/fidl/cpp/string.h>
|
|
#include <lib/sys/cpp/service_directory.h>
|
|
#include <lib/syslog/global.h>
|
|
#include <lib/zx/thread.h>
|
|
#include <lib/zx/time.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <zircon/status.h>
|
|
#include <regex>
|
|
#include <utility>
|
|
|
|
#include "runtime/dart/utils/handle_exception.h"
|
|
#include "runtime/dart/utils/inlines.h"
|
|
#include "runtime/dart/utils/tempfs.h"
|
|
#include "third_party/dart/runtime/include/dart_tools_api.h"
|
|
#include "third_party/tonic/converter/dart_converter.h"
|
|
#include "third_party/tonic/dart_message_handler.h"
|
|
#include "third_party/tonic/dart_microtask_queue.h"
|
|
#include "third_party/tonic/dart_state.h"
|
|
#include "third_party/tonic/logging/dart_error.h"
|
|
|
|
#include "builtin_libraries.h"
|
|
#include "logging.h"
|
|
|
|
using tonic::ToDart;
|
|
|
|
namespace dart_runner {
|
|
|
|
constexpr char kDataKey[] = "data";
|
|
|
|
namespace {
|
|
|
|
void AfterTask(async_loop_t*, void*) {
|
|
tonic::DartMicrotaskQueue* queue =
|
|
tonic::DartMicrotaskQueue::GetForCurrentThread();
|
|
// Verify that the queue exists, as this method could have been called back as
|
|
// part of the exit routine, after the destruction of the microtask queue.
|
|
if (queue) {
|
|
queue->RunMicrotasks();
|
|
}
|
|
}
|
|
|
|
constexpr async_loop_config_t kLoopConfig = {
|
|
.make_default_for_current_thread = true,
|
|
.epilogue = &AfterTask,
|
|
};
|
|
|
|
// Find the last path component.
|
|
// fuchsia-pkg://fuchsia.com/hello_dart#meta/hello_dart.cmx -> hello_dart.cmx
|
|
std::string GetLabelFromURL(const std::string& url) {
|
|
for (size_t i = url.length() - 1; i > 0; i--) {
|
|
if (url[i] == '/') {
|
|
return url.substr(i + 1, url.length() - 1);
|
|
}
|
|
}
|
|
return url;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DartComponentController::DartComponentController(
|
|
fuchsia::sys::Package package,
|
|
fuchsia::sys::StartupInfo startup_info,
|
|
std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
|
|
fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller)
|
|
: loop_(new async::Loop(&kLoopConfig)),
|
|
label_(GetLabelFromURL(package.resolved_url)),
|
|
url_(std::move(package.resolved_url)),
|
|
package_(std::move(package)),
|
|
startup_info_(std::move(startup_info)),
|
|
runner_incoming_services_(runner_incoming_services),
|
|
binding_(this) {
|
|
for (size_t i = 0; i < startup_info_.program_metadata->size(); ++i) {
|
|
auto pg = startup_info_.program_metadata->at(i);
|
|
if (pg.key.compare(kDataKey) == 0) {
|
|
data_path_ = "pkg/" + pg.value;
|
|
}
|
|
}
|
|
if (data_path_.empty()) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Could not find a /pkg/data directory for %s",
|
|
url_.c_str());
|
|
return;
|
|
}
|
|
if (controller.is_valid()) {
|
|
binding_.Bind(std::move(controller));
|
|
binding_.set_error_handler([this](zx_status_t status) { Kill(); });
|
|
}
|
|
|
|
zx_status_t status =
|
|
zx::timer::create(ZX_TIMER_SLACK_LATE, ZX_CLOCK_MONOTONIC, &idle_timer_);
|
|
if (status != ZX_OK) {
|
|
FX_LOGF(INFO, LOG_TAG, "Idle timer creation failed: %s",
|
|
zx_status_get_string(status));
|
|
} else {
|
|
idle_wait_.set_object(idle_timer_.get());
|
|
idle_wait_.set_trigger(ZX_TIMER_SIGNALED);
|
|
idle_wait_.Begin(async_get_default_dispatcher());
|
|
}
|
|
}
|
|
|
|
DartComponentController::~DartComponentController() {
|
|
if (namespace_) {
|
|
fdio_ns_destroy(namespace_);
|
|
namespace_ = nullptr;
|
|
}
|
|
close(stdoutfd_);
|
|
close(stderrfd_);
|
|
}
|
|
|
|
bool DartComponentController::Setup() {
|
|
// Name the thread after the url of the component being launched.
|
|
zx::thread::self()->set_property(ZX_PROP_NAME, label_.c_str(), label_.size());
|
|
Dart_SetThreadName(label_.c_str());
|
|
|
|
if (!SetupNamespace()) {
|
|
return false;
|
|
}
|
|
|
|
if (SetupFromAppSnapshot()) {
|
|
FX_LOGF(INFO, LOG_TAG, "%s is running from an app snapshot", url_.c_str());
|
|
} else if (SetupFromKernel()) {
|
|
FX_LOGF(INFO, LOG_TAG, "%s is running from kernel", url_.c_str());
|
|
} else {
|
|
FX_LOGF(ERROR, LOG_TAG,
|
|
"Could not find a program in %s. Was data specified"
|
|
" correctly in the component manifest?",
|
|
url_.c_str());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
constexpr char kTmpPath[] = "/tmp";
|
|
constexpr char kServiceRootPath[] = "/svc";
|
|
|
|
bool DartComponentController::SetupNamespace() {
|
|
fuchsia::sys::FlatNamespace* flat = &startup_info_.flat_namespace;
|
|
zx_status_t status = fdio_ns_create(&namespace_);
|
|
if (status != ZX_OK) {
|
|
FX_LOG(ERROR, LOG_TAG, "Failed to create namespace");
|
|
return false;
|
|
}
|
|
|
|
dart_utils::SetupComponentTemp(namespace_);
|
|
|
|
for (size_t i = 0; i < flat->paths.size(); ++i) {
|
|
if (flat->paths.at(i) == kTmpPath) {
|
|
// /tmp is covered by the local memfs.
|
|
continue;
|
|
}
|
|
|
|
zx::channel dir;
|
|
if (flat->paths.at(i) == kServiceRootPath) {
|
|
// clone /svc so component_context can still use it below
|
|
dir = zx::channel(fdio_service_clone(flat->directories.at(i).get()));
|
|
} else {
|
|
dir = std::move(flat->directories.at(i));
|
|
}
|
|
|
|
zx_handle_t dir_handle = dir.release();
|
|
const char* path = flat->paths.at(i).data();
|
|
status = fdio_ns_bind(namespace_, path, dir_handle);
|
|
if (status != ZX_OK) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Failed to bind %s to namespace: %s",
|
|
flat->paths.at(i).c_str(), zx_status_get_string(status));
|
|
zx_handle_close(dir_handle);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DartComponentController::SetupFromKernel() {
|
|
MappedResource manifest;
|
|
if (!MappedResource::LoadFromNamespace(
|
|
namespace_, data_path_ + "/app.dilplist", manifest)) {
|
|
return false;
|
|
}
|
|
|
|
if (!MappedResource::LoadFromNamespace(
|
|
nullptr, "pkg/data/isolate_core_snapshot_data.bin",
|
|
isolate_snapshot_data_)) {
|
|
return false;
|
|
}
|
|
if (!MappedResource::LoadFromNamespace(
|
|
nullptr, "pkg/data/isolate_core_snapshot_instructions.bin",
|
|
isolate_snapshot_instructions_, true /* executable */)) {
|
|
return false;
|
|
}
|
|
|
|
if (!CreateIsolate(isolate_snapshot_data_.address(),
|
|
isolate_snapshot_instructions_.address(), nullptr,
|
|
nullptr)) {
|
|
return false;
|
|
}
|
|
|
|
Dart_EnterScope();
|
|
|
|
std::string str(reinterpret_cast<const char*>(manifest.address()),
|
|
manifest.size());
|
|
Dart_Handle library = Dart_Null();
|
|
for (size_t start = 0; start < manifest.size();) {
|
|
size_t end = str.find("\n", start);
|
|
if (end == std::string::npos) {
|
|
FX_LOG(ERROR, LOG_TAG, "Malformed manifest");
|
|
Dart_ExitScope();
|
|
return false;
|
|
}
|
|
|
|
std::string path = data_path_ + "/" + str.substr(start, end - start);
|
|
start = end + 1;
|
|
|
|
MappedResource kernel;
|
|
if (!MappedResource::LoadFromNamespace(namespace_, path, kernel)) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Failed to find kernel: %s", path.c_str());
|
|
Dart_ExitScope();
|
|
return false;
|
|
}
|
|
library = Dart_LoadLibraryFromKernel(kernel.address(), kernel.size());
|
|
if (Dart_IsError(library)) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Failed to load kernel: %s",
|
|
Dart_GetError(library));
|
|
Dart_ExitScope();
|
|
return false;
|
|
}
|
|
|
|
kernel_peices_.emplace_back(std::move(kernel));
|
|
}
|
|
Dart_SetRootLibrary(library);
|
|
|
|
Dart_Handle result = Dart_FinalizeLoading(false);
|
|
if (Dart_IsError(result)) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Failed to FinalizeLoading: %s",
|
|
Dart_GetError(result));
|
|
Dart_ExitScope();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DartComponentController::SetupFromAppSnapshot() {
|
|
#if !defined(AOT_RUNTIME)
|
|
// If we start generating app-jit snapshots, the code below should be able
|
|
// handle that case without modification.
|
|
return false;
|
|
#else
|
|
|
|
if (!MappedResource::LoadFromNamespace(
|
|
namespace_, data_path_ + "/isolate_snapshot_data.bin",
|
|
isolate_snapshot_data_)) {
|
|
return false;
|
|
}
|
|
|
|
if (!MappedResource::LoadFromNamespace(
|
|
namespace_, data_path_ + "/isolate_snapshot_instructions.bin",
|
|
isolate_snapshot_instructions_, true /* executable */)) {
|
|
return false;
|
|
}
|
|
|
|
if (!MappedResource::LoadFromNamespace(
|
|
namespace_, data_path_ + "/shared_snapshot_data.bin",
|
|
shared_snapshot_data_)) {
|
|
return false;
|
|
}
|
|
|
|
if (!MappedResource::LoadFromNamespace(
|
|
namespace_, data_path_ + "/shared_snapshot_instructions.bin",
|
|
shared_snapshot_instructions_, true /* executable */)) {
|
|
return false;
|
|
}
|
|
|
|
return CreateIsolate(isolate_snapshot_data_.address(),
|
|
isolate_snapshot_instructions_.address(),
|
|
shared_snapshot_data_.address(),
|
|
shared_snapshot_instructions_.address());
|
|
#endif // defined(AOT_RUNTIME)
|
|
}
|
|
|
|
int DartComponentController::SetupFileDescriptor(
|
|
fuchsia::sys::FileDescriptorPtr fd) {
|
|
if (!fd) {
|
|
return -1;
|
|
}
|
|
// fd->handle1 and fd->handle2 are no longer used.
|
|
int outfd = -1;
|
|
zx_status_t status = fdio_fd_create(fd->handle0.release(), &outfd);
|
|
if (status != ZX_OK) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Failed to extract output fd: %s",
|
|
zx_status_get_string(status));
|
|
return -1;
|
|
}
|
|
return outfd;
|
|
}
|
|
|
|
bool DartComponentController::CreateIsolate(
|
|
const uint8_t* isolate_snapshot_data,
|
|
const uint8_t* isolate_snapshot_instructions,
|
|
const uint8_t* shared_snapshot_data,
|
|
const uint8_t* shared_snapshot_instructions) {
|
|
// Create the isolate from the snapshot.
|
|
char* error = nullptr;
|
|
|
|
// TODO(dart_runner): Pass if we start using tonic's loader.
|
|
intptr_t namespace_fd = -1;
|
|
// Freed in IsolateShutdownCallback.
|
|
auto state = new std::shared_ptr<tonic::DartState>(new tonic::DartState(
|
|
namespace_fd, [this](Dart_Handle result) { MessageEpilogue(result); }));
|
|
|
|
isolate_ = Dart_CreateIsolate(
|
|
url_.c_str(), label_.c_str(), isolate_snapshot_data,
|
|
isolate_snapshot_instructions, shared_snapshot_data,
|
|
shared_snapshot_instructions, nullptr /* flags */, state, &error);
|
|
if (!isolate_) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolate failed: %s", error);
|
|
return false;
|
|
}
|
|
|
|
state->get()->SetIsolate(isolate_);
|
|
|
|
tonic::DartMessageHandler::TaskDispatcher dispatcher =
|
|
[loop = loop_.get()](auto callback) {
|
|
async::PostTask(loop->dispatcher(), std::move(callback));
|
|
};
|
|
state->get()->message_handler().Initialize(dispatcher);
|
|
|
|
state->get()->SetReturnCodeCallback(
|
|
[this](uint32_t return_code) { return_code_ = return_code; });
|
|
|
|
return true;
|
|
}
|
|
|
|
void DartComponentController::Run() {
|
|
async::PostTask(loop_->dispatcher(), [loop = loop_.get(), app = this] {
|
|
if (!app->Main()) {
|
|
loop->Quit();
|
|
}
|
|
});
|
|
loop_->Run();
|
|
SendReturnCode();
|
|
}
|
|
|
|
bool DartComponentController::Main() {
|
|
Dart_EnterScope();
|
|
|
|
tonic::DartMicrotaskQueue::StartForCurrentThread();
|
|
|
|
std::vector<std::string> arguments =
|
|
std::move(startup_info_.launch_info.arguments);
|
|
|
|
stdoutfd_ = SetupFileDescriptor(std::move(startup_info_.launch_info.out));
|
|
stderrfd_ = SetupFileDescriptor(std::move(startup_info_.launch_info.err));
|
|
auto directory_request =
|
|
std::move(startup_info_.launch_info.directory_request);
|
|
|
|
auto* flat = &startup_info_.flat_namespace;
|
|
std::unique_ptr<sys::ServiceDirectory> svc;
|
|
for (size_t i = 0; i < flat->paths.size(); ++i) {
|
|
zx::channel dir;
|
|
if (flat->paths.at(i) == kServiceRootPath) {
|
|
svc = std::make_unique<sys::ServiceDirectory>(
|
|
std::move(flat->directories.at(i)));
|
|
break;
|
|
}
|
|
}
|
|
if (!svc) {
|
|
FX_LOG(ERROR, LOG_TAG, "Unable to get /svc for dart component");
|
|
return false;
|
|
}
|
|
|
|
fidl::InterfaceHandle<fuchsia::sys::Environment> environment;
|
|
svc->Connect(environment.NewRequest());
|
|
|
|
InitBuiltinLibrariesForIsolate(
|
|
url_, namespace_, stdoutfd_, stderrfd_, std::move(environment),
|
|
std::move(directory_request), false /* service_isolate */);
|
|
namespace_ = nullptr;
|
|
|
|
Dart_ExitScope();
|
|
Dart_ExitIsolate();
|
|
char* error = Dart_IsolateMakeRunnable(isolate_);
|
|
if (error != nullptr) {
|
|
Dart_EnterIsolate(isolate_);
|
|
Dart_ShutdownIsolate();
|
|
FX_LOGF(ERROR, LOG_TAG, "Unable to make isolate runnable: %s", error);
|
|
free(error);
|
|
return false;
|
|
}
|
|
Dart_EnterIsolate(isolate_);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle dart_arguments =
|
|
Dart_NewListOf(Dart_CoreType_String, arguments.size());
|
|
if (Dart_IsError(dart_arguments)) {
|
|
FX_LOGF(ERROR, LOG_TAG, "Failed to allocate Dart arguments list: %s",
|
|
Dart_GetError(dart_arguments));
|
|
Dart_ExitScope();
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < arguments.size(); i++) {
|
|
tonic::LogIfError(
|
|
Dart_ListSetAt(dart_arguments, i, ToDart(arguments.at(i))));
|
|
}
|
|
|
|
Dart_Handle argv[] = {
|
|
dart_arguments,
|
|
};
|
|
|
|
Dart_Handle main_result = Dart_Invoke(Dart_RootLibrary(), ToDart("main"),
|
|
dart_utils::ArraySize(argv), argv);
|
|
if (Dart_IsError(main_result)) {
|
|
auto dart_state = tonic::DartState::Current();
|
|
if (!dart_state->has_set_return_code()) {
|
|
// The program hasn't set a return code meaning this exit is unexpected.
|
|
FX_LOG(ERROR, LOG_TAG, Dart_GetError(main_result));
|
|
return_code_ = tonic::GetErrorExitCode(main_result);
|
|
|
|
dart_utils::HandleIfException(runner_incoming_services_, url_,
|
|
main_result);
|
|
}
|
|
Dart_ExitScope();
|
|
return false;
|
|
}
|
|
|
|
Dart_ExitScope();
|
|
return true;
|
|
}
|
|
|
|
void DartComponentController::Kill() {
|
|
if (Dart_CurrentIsolate()) {
|
|
tonic::DartMicrotaskQueue::GetForCurrentThread()->Destroy();
|
|
|
|
loop_->Quit();
|
|
|
|
// TODO(rosswang): The docs warn of threading issues if doing this again,
|
|
// but without this, attempting to shut down the isolate finalizes app
|
|
// contexts that can't tell a shutdown is in progress and so fatal.
|
|
Dart_SetMessageNotifyCallback(nullptr);
|
|
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
}
|
|
|
|
void DartComponentController::Detach() {
|
|
binding_.set_error_handler([](zx_status_t status) {});
|
|
}
|
|
|
|
void DartComponentController::SendReturnCode() {
|
|
binding_.events().OnTerminated(return_code_,
|
|
fuchsia::sys::TerminationReason::EXITED);
|
|
}
|
|
|
|
const zx::duration kIdleWaitDuration = zx::sec(2);
|
|
const zx::duration kIdleNotifyDuration = zx::msec(500);
|
|
const zx::duration kIdleSlack = zx::sec(1);
|
|
|
|
void DartComponentController::MessageEpilogue(Dart_Handle result) {
|
|
auto dart_state = tonic::DartState::Current();
|
|
// If the Dart program has set a return code, then it is intending to shut
|
|
// down by way of a fatal error, and so there is no need to override
|
|
// return_code_.
|
|
if (dart_state->has_set_return_code()) {
|
|
Dart_ShutdownIsolate();
|
|
return;
|
|
}
|
|
|
|
dart_utils::HandleIfException(runner_incoming_services_, url_, result);
|
|
|
|
// Otherwise, see if there was any other error.
|
|
return_code_ = tonic::GetErrorExitCode(result);
|
|
if (return_code_ != 0) {
|
|
Dart_ShutdownIsolate();
|
|
return;
|
|
}
|
|
|
|
idle_start_ = zx::clock::get_monotonic();
|
|
zx_status_t status =
|
|
idle_timer_.set(idle_start_ + kIdleWaitDuration, kIdleSlack);
|
|
if (status != ZX_OK) {
|
|
FX_LOGF(INFO, LOG_TAG, "Idle timer set failed: %s",
|
|
zx_status_get_string(status));
|
|
}
|
|
}
|
|
|
|
void DartComponentController::OnIdleTimer(async_dispatcher_t* dispatcher,
|
|
async::WaitBase* wait,
|
|
zx_status_t status,
|
|
const zx_packet_signal* signal) {
|
|
if ((status != ZX_OK) || !(signal->observed & ZX_TIMER_SIGNALED) ||
|
|
!Dart_CurrentIsolate()) {
|
|
// Timer closed or isolate shutdown.
|
|
return;
|
|
}
|
|
|
|
zx::time deadline = idle_start_ + kIdleWaitDuration;
|
|
zx::time now = zx::clock::get_monotonic();
|
|
if (now >= deadline) {
|
|
// No Dart message has been processed for kIdleWaitDuration: assume we'll
|
|
// stay idle for kIdleNotifyDuration.
|
|
Dart_NotifyIdle((now + kIdleNotifyDuration).get());
|
|
idle_start_ = zx::time(0);
|
|
idle_timer_.cancel(); // De-assert signal.
|
|
} else {
|
|
// Early wakeup or message pushed idle time forward: reschedule.
|
|
zx_status_t status = idle_timer_.set(deadline, kIdleSlack);
|
|
if (status != ZX_OK) {
|
|
FX_LOGF(INFO, LOG_TAG, "Idle timer set failed: %s",
|
|
zx_status_get_string(status));
|
|
}
|
|
}
|
|
wait->Begin(dispatcher); // ignore errors
|
|
}
|
|
|
|
} // namespace dart_runner
|