diff --git a/engine/src/flutter/BUILD.gn b/engine/src/flutter/BUILD.gn index b613016c80..6e48015b1d 100644 --- a/engine/src/flutter/BUILD.gn +++ b/engine/src/flutter/BUILD.gn @@ -29,7 +29,7 @@ group("flutter") { } if (is_fuchsia && using_fuchsia_sdk) { - public_deps += [ "$flutter_root/shell/platform/fuchsia/flutter" ] + public_deps += [ "$flutter_root/shell/platform/fuchsia" ] } if (!is_fuchsia && !is_fuchsia_host) { diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 26c0817bfa..f3cdba51fc 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -785,6 +785,54 @@ FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.cc FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.h FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.cc FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/builtin_libraries.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart/builtin_libraries.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/dart_component_controller.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart/dart_component_controller.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/dart_runner.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart/dart_runner.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/embedder/builtin.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/embedder/script_runner_snapshot.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/embedder/shim.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/embedder/snapshot.cc.tmpl +FILE: ../../../flutter/shell/platform/fuchsia/dart/embedder/snapshot.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/embedder/snapshot.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart_test +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_aot.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_jit.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/greeting/greeting.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/hello.fidl +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/main.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_aot.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_jit.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_dart/bin/hello_dart.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot_product.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_debug.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit_product.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/integration/main.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/integration/meta/dart_aot_runner_test.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/integration/meta/dart_jit_runner_test.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/kernel/libraries.json +FILE: ../../../flutter/shell/platform/fuchsia/dart/logging.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/main.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart/mapped_resource.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart/mapped_resource.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/aot_product_runtime +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/aot_runtime +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/dart_aot_product_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/dart_aot_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/dart_jit_product_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/dart_jit_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/dart_zircon_test.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/jit_product_runtime +FILE: ../../../flutter/shell/platform/fuchsia/dart/meta/jit_runtime +FILE: ../../../flutter/shell/platform/fuchsia/dart/service_isolate.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart/service_isolate.h +FILE: ../../../flutter/shell/platform/fuchsia/dart/vmservice/empty.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart/vmservice/meta/vmservice.cmx FILE: ../../../flutter/shell/platform/fuchsia/flutter/collect_traces.dart FILE: ../../../flutter/shell/platform/fuchsia/flutter/component.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/component.h diff --git a/engine/src/flutter/shell/platform/BUILD.gn b/engine/src/flutter/shell/platform/BUILD.gn index 683da43fe1..4b881909d1 100644 --- a/engine/src/flutter/shell/platform/BUILD.gn +++ b/engine/src/flutter/shell/platform/BUILD.gn @@ -27,10 +27,9 @@ group("platform") { "windows", ] } else if (is_fuchsia) { - # Fuchsia has its own runner implementation. if (using_fuchsia_sdk) { deps = [ - "fuchsia/flutter", + "fuchsia", ] } } else { diff --git a/engine/src/flutter/shell/platform/fuchsia/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/BUILD.gn new file mode 100644 index 0000000000..57401b0ca0 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/BUILD.gn @@ -0,0 +1,14 @@ +# 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. + +import("//build/fuchsia/sdk.gni") + +if (using_fuchsia_sdk) { + group("fuchsia") { + deps = [ + "dart", + "flutter", + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/.gitignore b/engine/src/flutter/shell/platform/fuchsia/dart/.gitignore new file mode 100644 index 0000000000..8d17d4044a --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/.gitignore @@ -0,0 +1,2 @@ +.clang_complete +.packages diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/BUILD.gn new file mode 100644 index 0000000000..1af9c23f91 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/BUILD.gn @@ -0,0 +1,61 @@ +# 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. + +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") + +if (using_fuchsia_sdk) { + import("//flutter/common/config.gni") + + group("dart_io_api") { + visibility = [ ":*" ] + public_deps = [] + + if (flutter_runtime_mode == "debug") { + public_deps += [ "//third_party/dart/runtime/bin:dart_io_api" ] + } else { + public_deps += [ "//third_party/dart/runtime/bin:dart_io_api_product" ] + } + } + + executable("dart") { + output_name = "dt_rush" + + public = [] + + sources = [ + "builtin_libraries.cc", + "builtin_libraries.h", + "dart_component_controller.cc", + "dart_component_controller.h", + "dart_runner.cc", + "dart_runner.h", + "logging.h", + "main.cc", + "mapped_resource.cc", + "mapped_resource.h", + "service_isolate.cc", + "service_isolate.h", + ] + + deps = [ + ":dart_io_api", + "$flutter_root/common", + "$flutter_root/fml", + "$flutter_root/runtime:libdart", + "$flutter_root/shell/platform/fuchsia/dart-pkg/fuchsia", + "$flutter_root/shell/platform/fuchsia/dart-pkg/zircon", + "$flutter_root/shell/platform/fuchsia/runtime/dart/utils", + "$fuchsia_sdk_root/pkg:async-cpp", + "$fuchsia_sdk_root/pkg:async-loop", + "$fuchsia_sdk_root/pkg:async-loop-cpp", + "$fuchsia_sdk_root/pkg:fidl_cpp", + "$fuchsia_sdk_root/pkg:syslog", + "$fuchsia_sdk_root/pkg/lib/sys/cpp", + "$fuchsia_sdk_root/pkg/lib/vfs/cpp", + "//third_party/tonic", + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/README.md b/engine/src/flutter/shell/platform/fuchsia/dart/README.md new file mode 100644 index 0000000000..6013f353aa --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/README.md @@ -0,0 +1,3 @@ +# Dart Application Runner + +An Runner that runs Dart programs. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/builtin_libraries.cc b/engine/src/flutter/shell/platform/fuchsia/dart/builtin_libraries.cc new file mode 100644 index 0000000000..54f4f9a10a --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/builtin_libraries.cc @@ -0,0 +1,240 @@ +// 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 "builtin_libraries.h" + +#include +#include + +#include "dart-pkg/fuchsia/sdk_ext/fuchsia.h" +#include "flutter/fml/logging.h" +#include "runtime/dart/utils/inlines.h" +#include "third_party/dart/runtime/bin/io_natives.h" +#include "third_party/dart/runtime/include/dart_api.h" +#include "third_party/tonic/converter/dart_converter.h" +#include "third_party/tonic/dart_microtask_queue.h" +#include "third_party/tonic/logging/dart_error.h" + +#include "logging.h" + +using tonic::ToDart; + +namespace dart_runner { +namespace { + +#define REGISTER_FUNCTION(name, count) {#name, name, count}, +#define DECLARE_FUNCTION(name, count) \ + extern void name(Dart_NativeArguments args); + +#define BUILTIN_NATIVE_LIST(V) \ + V(Logger_PrintString, 1) \ + V(ScheduleMicrotask, 1) + +BUILTIN_NATIVE_LIST(DECLARE_FUNCTION); + +const struct NativeEntry { + const char* name; + Dart_NativeFunction function; + int argument_count; +} kBuiltinEntries[] = {BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)}; + +Dart_NativeFunction BuiltinNativeLookup(Dart_Handle name, + int argument_count, + bool* auto_setup_scope) { + const char* function_name = nullptr; + Dart_Handle result = Dart_StringToCString(name, &function_name); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + } + FML_DCHECK(function_name != nullptr); + FML_DCHECK(auto_setup_scope != nullptr); + *auto_setup_scope = true; + size_t num_entries = dart_utils::ArraySize(kBuiltinEntries); + for (size_t i = 0; i < num_entries; i++) { + const NativeEntry& entry = kBuiltinEntries[i]; + if (!strcmp(function_name, entry.name) && + (entry.argument_count == argument_count)) { + return entry.function; + } + } + return nullptr; +} + +const uint8_t* BuiltinNativeSymbol(Dart_NativeFunction native_function) { + size_t num_entries = dart_utils::ArraySize(kBuiltinEntries); + for (size_t i = 0; i < num_entries; i++) { + const NativeEntry& entry = kBuiltinEntries[i]; + if (entry.function == native_function) + return reinterpret_cast(entry.name); + } + return nullptr; +} + +void Logger_PrintString(Dart_NativeArguments args) { + intptr_t length = 0; + uint8_t* chars = nullptr; + Dart_Handle str = Dart_GetNativeArgument(args, 0); + Dart_Handle result = Dart_StringToUTF8(str, &chars, &length); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + } else { + fwrite(chars, 1, length, stdout); + fputc('\n', stdout); + fflush(stdout); + } +} + +void ScheduleMicrotask(Dart_NativeArguments args) { + Dart_Handle closure = Dart_GetNativeArgument(args, 0); + if (tonic::LogIfError(closure) || !Dart_IsClosure(closure)) + return; + tonic::DartMicrotaskQueue::GetForCurrentThread()->ScheduleMicrotask(closure); +} + +} // namespace + +void InitBuiltinLibrariesForIsolate( + const std::string& script_uri, + fdio_ns_t* namespc, + int stdoutfd, + int stderrfd, + fidl::InterfaceHandle environment, + zx::channel directory_request, + bool service_isolate) { + // dart:fuchsia -------------------------------------------------------------- + if (!service_isolate) { + fuchsia::dart::Initialize(std::move(environment), + std::move(directory_request)); + } + + // dart:fuchsia.builtin ------------------------------------------------------ + + Dart_Handle builtin_lib = Dart_LookupLibrary(ToDart("dart:fuchsia.builtin")); + FML_CHECK(!tonic::LogIfError(builtin_lib)); + Dart_Handle result = Dart_SetNativeResolver(builtin_lib, BuiltinNativeLookup, + BuiltinNativeSymbol); + FML_CHECK(!tonic::LogIfError(result)); + + // dart:io ------------------------------------------------------------------- + + Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io")); + FML_CHECK(!tonic::LogIfError(io_lib)); + result = Dart_SetNativeResolver(io_lib, dart::bin::IONativeLookup, + dart::bin::IONativeSymbol); + FML_CHECK(!tonic::LogIfError(result)); + + // dart:zircon --------------------------------------------------------------- + + Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon")); + FML_CHECK(!tonic::LogIfError(zircon_lib)); + // NativeResolver already set by fuchsia::dart::Initialize(). + + // Core libraries ------------------------------------------------------------ + + Dart_Handle async_lib = Dart_LookupLibrary(ToDart("dart:async")); + FML_CHECK(!tonic::LogIfError(async_lib)); + + Dart_Handle core_lib = Dart_LookupLibrary(ToDart("dart:core")); + FML_CHECK(!tonic::LogIfError(core_lib)); + + Dart_Handle internal_lib = Dart_LookupLibrary(ToDart("dart:_internal")); + FML_CHECK(!tonic::LogIfError(internal_lib)); + + Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); + FML_CHECK(!tonic::LogIfError(isolate_lib)); + +#if !defined(AOT_RUNTIME) + // AOT: These steps already happened at compile time in gen_snapshot. + + // 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. + result = Dart_FinalizeLoading(false); + FML_CHECK(!tonic::LogIfError(result)); +#endif + + // Setup the internal library's 'internalPrint' function. + Dart_Handle print = + Dart_Invoke(builtin_lib, ToDart("_getPrintClosure"), 0, nullptr); + FML_CHECK(!tonic::LogIfError(print)); + + result = Dart_SetField(internal_lib, ToDart("_printClosure"), print); + FML_CHECK(!tonic::LogIfError(result)); + + // Set up the 'scheduleImmediate' closure. + Dart_Handle schedule_immediate_closure; + if (service_isolate) { + // Running on dart::ThreadPool. + schedule_immediate_closure = Dart_Invoke( + isolate_lib, ToDart("_getIsolateScheduleImmediateClosure"), 0, nullptr); + } else { + // Running on async::Loop. + schedule_immediate_closure = Dart_Invoke( + builtin_lib, ToDart("_getScheduleMicrotaskClosure"), 0, nullptr); + } + FML_CHECK(!tonic::LogIfError(schedule_immediate_closure)); + + Dart_Handle schedule_args[1]; + schedule_args[0] = schedule_immediate_closure; + result = Dart_Invoke(async_lib, ToDart("_setScheduleImmediateClosure"), 1, + schedule_args); + FML_CHECK(!tonic::LogIfError(result)); + + // Set up the namespace in dart:io. + Dart_Handle namespace_type = + Dart_GetType(io_lib, ToDart("_Namespace"), 0, nullptr); + FML_CHECK(!tonic::LogIfError(namespace_type)); + + Dart_Handle namespace_args[1]; + namespace_args[0] = ToDart(reinterpret_cast(namespc)); + result = + Dart_Invoke(namespace_type, ToDart("_setupNamespace"), 1, namespace_args); + FML_CHECK(!tonic::LogIfError(result)); + + // Set up the namespace in dart:zircon. + namespace_type = Dart_GetType(zircon_lib, ToDart("_Namespace"), 0, nullptr); + FML_CHECK(!tonic::LogIfError(namespace_type)); + + result = Dart_SetField(namespace_type, ToDart("_namespace"), + ToDart(reinterpret_cast(namespc))); + FML_CHECK(!tonic::LogIfError(result)); + + // Set up stdout and stderr. + Dart_Handle stdio_args[3]; + stdio_args[0] = Dart_NewInteger(0); + stdio_args[1] = Dart_NewInteger(stdoutfd); + stdio_args[2] = Dart_NewInteger(stderrfd); + result = Dart_Invoke(io_lib, ToDart("_setStdioFDs"), 3, stdio_args); + FML_CHECK(!tonic::LogIfError(result)); + + // Disable some dart:io operations. + Dart_Handle embedder_config_type = + Dart_GetType(io_lib, ToDart("_EmbedderConfig"), 0, nullptr); + FML_CHECK(!tonic::LogIfError(embedder_config_type)); + + result = + Dart_SetField(embedder_config_type, ToDart("_mayExit"), Dart_False()); + FML_CHECK(!tonic::LogIfError(result)); + + // Set the script location. + result = Dart_SetField(builtin_lib, ToDart("_rawScript"), ToDart(script_uri)); + FML_CHECK(!tonic::LogIfError(result)); + + // Setup the uriBase with the base uri of the fidl app. + Dart_Handle uri_base = + Dart_Invoke(io_lib, ToDart("_getUriBaseClosure"), 0, nullptr); + FML_CHECK(!tonic::LogIfError(uri_base)); + + result = Dart_SetField(core_lib, ToDart("_uriBaseClosure"), uri_base); + FML_CHECK(!tonic::LogIfError(result)); + + Dart_Handle setup_hooks = ToDart("_setupHooks"); + result = Dart_Invoke(builtin_lib, setup_hooks, 0, nullptr); + FML_CHECK(!tonic::LogIfError(result)); + result = Dart_Invoke(io_lib, setup_hooks, 0, nullptr); + FML_CHECK(!tonic::LogIfError(result)); + result = Dart_Invoke(isolate_lib, setup_hooks, 0, nullptr); + FML_CHECK(!tonic::LogIfError(result)); +} + +} // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/builtin_libraries.h b/engine/src/flutter/shell/platform/fuchsia/dart/builtin_libraries.h new file mode 100644 index 0000000000..4f5df5472f --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/builtin_libraries.h @@ -0,0 +1,28 @@ +// 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. + +#ifndef TOPAZ_RUNTIME_DART_RUNNER_BUILTIN_LIBRARIES_H_ +#define TOPAZ_RUNTIME_DART_RUNNER_BUILTIN_LIBRARIES_H_ + +#include +#include + +#include + +#include + +namespace dart_runner { + +void InitBuiltinLibrariesForIsolate( + const std::string& script_uri, + fdio_ns_t* namespc, + int stdoutfd, + int stderrfd, + fidl::InterfaceHandle environment, + zx::channel directory_request, + bool service_isolate); + +} // namespace dart_runner + +#endif // TOPAZ_RUNTIME_DART_RUNNER_BUILTIN_LIBRARIES_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/dart_app.gni b/engine/src/flutter/shell/platform/fuchsia/dart/dart_app.gni new file mode 100644 index 0000000000..c955eb81b0 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/dart_app.gni @@ -0,0 +1,251 @@ +# 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. + +import("//build/package.gni") +import("//build/tools/json_merge/json_merge.gni") +import("//third_party/dart/build/dart/dart_action.gni") +import("//topaz/runtime/dart/config.gni") +import("//topaz/runtime/dart/dart_component.gni") +import("//topaz/runtime/dart/dart_kernel.gni") + +# Defines JIT runtime components to be further distributed in one package. +# +# Takes a set of dart components and puts them into one fuchsia package with +# the dart_jit_runner as its runtime. Also supports legacy calls where the +# components parameter isn't specified, in which we will create one default +# component for the package. +# +# Parameters +# +# components (required) +# [list of scopes] Defines the components in the package. Either main_dart +# or components must be defined, but not both. +# +# Entries in a scope in the resources list: +# +# component_name (required) +# Name of the component. +# +# main_dart (required) +# File containing the main function of the component. +# +# dart_package_name (optional) +# Name of the dart package for the component. If not provided, it will +# be inferred from the component name. +# +# package_root (optional) +# Path to the dart package for the component. If not provided, it will +# be assumed as ".". +# +# sources (optional) +# Relative path of source files to be included in the dart package for +# the component at $package_root/lib. +# +# main_dart (required) +# File containing the main function of the application. Either main_dart or +# components must be defined, but not both. +# +# package_name (optional) +# Name of the Dart package. This is used as an identifier in code that +# depends on the dart library that the *one and only* component generates. +# Only compatible when components is not specified (use +# components.dart_package_name). +# +template("_dart_jit_component") { + legacy_component = false + pkg_name = target_name + if (!defined(invoker.components)) { + # If components is not specified, we are fitting main_dart into a component + # scope, and using that for the package. + # + # TODO(CP-141): Remove support for legacy_component once all existing calls + # to dart_app() have a components parameter. + legacy_component = true + if (defined(invoker.fuchsia_package_name)) { + legacy_component_name = invoker.fuchsia_package_name + } else { + legacy_component_name = target_name + } + pkg_name = legacy_component_name + pkg_sources = [] + if (defined(invoker.sources)) { + pkg_sources = invoker.sources + } + components = [ + { + main_dart = invoker.main_dart + component_name = legacy_component_name + component_type = "dart" + package_root = "." + deps = invoker.deps + sources = pkg_sources + }, + ] + } + + flutter_dart_jit_component(target_name) { + forward_variables_from(invoker, "*") + } +} + +# Defines AOT runtime components to be further distributed in one package. +# +# Takes a set of dart components and puts them into one fuchsia package with +# the dart_aot_runner as its runtime. Also supports legacy calls where the +# components parameter isn't specified, in which we will create one default +# component for the package. +# +# Parameters +# +# components (required) +# [list of scopes] Defines the components in the package. Either main_dart +# or components must be defined, but not both. +# +# Entries in a scope in the resources list: +# +# component_name (required) +# Name of the component. +# +# main_dart (required) +# File containing the main function of the component. +# +# dart_package_name (optional) +# Name of the dart package for the component. If not provided, it will +# be inferred from the component name. +# +# package_root (optional) +# Path to the dart package for the component. If not provided, it will +# be assumed as ".". +# +# sources (optional) +# Relative path of source files to be included in the dart package for +# the component at $package_root/lib. +# +# main_dart (required) +# File containing the main function of the application. Either main_dart or +# components must be defined, but not both. +# +# package_name (optional) +# Name of the Dart package. This is used as an identifier in code that +# depends on the dart library that the *one and only* component generates. +# Only compatible when components is not specified (use +# components.dart_package_name). +# +template("_dart_aot_component") { + legacy_component = false + pkg_name = target_name + if (!defined(invoker.components)) { + # If components is not specified, we are fitting main_dart into a component + # scope, and using that for the package. + # + # TODO(CP-141): Remove support for legacy_component once all existing calls + # to dart_app() have a components parameter. + legacy_component = true + if (defined(invoker.fuchsia_package_name)) { + legacy_component_name = invoker.fuchsia_package_name + } else { + legacy_component_name = target_name + } + pkg_name = legacy_component_name + pkg_sources = [] + if (defined(invoker.sources)) { + pkg_sources = invoker.sources + } + components = [ + { + main_dart = invoker.main_dart + component_name = legacy_component_name + component_type = "dart" + package_root = "." + deps = invoker.deps + sources = pkg_sources + }, + ] + } + + flutter_dart_aot_component(target_name) { + forward_variables_from(invoker, "*") + } +} + +template("dart_jit_app") { + template_name = "_dart_jit_component" + if (dart_force_product) { + template_name = dart_product_app + } + + target(template_name, target_name) { + forward_variables_from(invoker, "*") + } +} + +template("dart_aot_app") { + template_name = "_dart_aot_component" + if (dart_force_product) { + template_name = dart_product_app + } + + target(template_name, target_name) { + forward_variables_from(invoker, "*") + } +} + +# Defines a Dart application that can be run in the Dart content handler +# +# Parameters +# +# main_dart (required) +# Name of the Dart file containing the main function. Either main_dart or +# components must be defined, but not both. +# +# package_name (optional) +# Name of the Dart package. +# +# fuchsia_package_name (optional) +# Name of the Fuchsia package. +# +# deps (optional) +# List of Dart packages the application depends on. +# +# disable_analysis (optional) +# Prevents analysis from being run on this target. +# +# product (optional) +# A boolean. Whether to build/run the app in a stripped-down Dart VM. +# Defaults to !is_debug. +# +# resources (optional) +# Resources for the package (see //build/package.gni) +# +# tests (optional) +# List of tests forwarded for the package. See the definition in //build/package.gni. +# +# components (required) +# [list of scopes] Defines the components in the package. Either main_dart +# or components must be defined, but not both. +# +# Entries in a scope in the resources list: +# +# component_name (required) +# Name of the component. +# +# main_dart (required) +# File containing the main function of the component. +# +# package_root (optional) +# Path to the dart package for the component. If not provided, it will +# be assumed as ".". +# +# sources (optional) +# Relative path of source files to be included in the dart package for +# the component at $package_root/lib. +# +template("dart_app") { + assert((defined(invoker.components) && !defined(invoker.main_dart)) || + (!defined(invoker.components) && defined(invoker.main_dart)), + "Only one of components or main_dart should be defined") + target(dart_default_app, target_name) { + forward_variables_from(invoker, "*") + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/dart_component_controller.cc b/engine/src/flutter/shell/platform/fuchsia/dart/dart_component_controller.cc new file mode 100644 index 0000000000..1c4f710505 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/dart_component_controller.cc @@ -0,0 +1,531 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 runner_incoming_services, + fidl::InterfaceRequest 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(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(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 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 svc; + for (size_t i = 0; i < flat->paths.size(); ++i) { + zx::channel dir; + if (flat->paths.at(i) == kServiceRootPath) { + svc = std::make_unique( + 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 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 diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/dart_component_controller.h b/engine/src/flutter/shell/platform/fuchsia/dart/dart_component_controller.h new file mode 100644 index 0000000000..72352caf92 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/dart_component_controller.h @@ -0,0 +1,99 @@ +// 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. + +#ifndef TOPAZ_RUNTIME_DART_RUNNER_DART_COMPONENT_CONTROLLER_H_ +#define TOPAZ_RUNTIME_DART_RUNNER_DART_COMPONENT_CONTROLLER_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "lib/fidl/cpp/binding.h" +#include "mapped_resource.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace dart_runner { + +class DartComponentController : public fuchsia::sys::ComponentController { + public: + DartComponentController( + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest controller); + ~DartComponentController() override; + + bool Setup(); + void Run(); + bool Main(); + void SendReturnCode(); + + private: + bool SetupNamespace(); + + bool SetupFromKernel(); + bool SetupFromAppSnapshot(); + + bool 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); + + int SetupFileDescriptor(fuchsia::sys::FileDescriptorPtr fd); + + // |ComponentController| + void Kill() override; + void Detach() override; + + // Idle notification. + void MessageEpilogue(Dart_Handle result); + void OnIdleTimer(async_dispatcher_t* dispatcher, + async::WaitBase* wait, + zx_status_t status, + const zx_packet_signal* signal); + + // The loop must be the first declared member so that it gets destroyed after + // binding_ which expects the existence of a loop. + std::unique_ptr loop_; + std::string label_; + std::string url_; + fuchsia::sys::Package package_; + fuchsia::sys::StartupInfo startup_info_; + std::shared_ptr runner_incoming_services_; + std::string data_path_; + fidl::Binding binding_; + std::unique_ptr context_; + + fdio_ns_t* namespace_ = nullptr; + int stdoutfd_ = -1; + int stderrfd_ = -1; + MappedResource isolate_snapshot_data_; + MappedResource isolate_snapshot_instructions_; + MappedResource shared_snapshot_data_; + MappedResource shared_snapshot_instructions_; + std::vector kernel_peices_; + + Dart_Isolate isolate_; + int32_t return_code_ = 0; + + zx::time idle_start_{0}; + zx::timer idle_timer_; + async::WaitMethod + idle_wait_{this}; + + // Disallow copy and assignment. + DartComponentController(const DartComponentController&) = delete; + DartComponentController& operator=(const DartComponentController&) = delete; +}; + +} // namespace dart_runner + +#endif // TOPAZ_RUNTIME_DART_RUNNER_DART_COMPONENT_CONTROLLER_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/dart_runner.cc b/engine/src/flutter/shell/platform/fuchsia/dart/dart_runner.cc new file mode 100644 index 0000000000..670cb90923 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/dart_runner.cc @@ -0,0 +1,199 @@ +// 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_runner.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dart_component_controller.h" +#include "flutter/fml/trace_event.h" +#include "logging.h" +#include "runtime/dart/utils/inlines.h" +#include "runtime/dart/utils/vmservice_object.h" +#include "service_isolate.h" +#include "third_party/dart/runtime/include/bin/dart_io_api.h" +#include "third_party/tonic/dart_microtask_queue.h" +#include "third_party/tonic/dart_state.h" + +#if defined(AOT_RUNTIME) +extern "C" uint8_t _kDartVmSnapshotData[]; +extern "C" uint8_t _kDartVmSnapshotInstructions[]; +#endif + +namespace dart_runner { +namespace { + +const char* kDartVMArgs[] = { + // clang-format off + // TODO(FL-117): Re-enable causal async stack traces when this issue is + // addressed. + "--no_causal_async_stacks", + + "--systrace_timeline", + "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", + +#if defined(AOT_RUNTIME) + "--precompilation", +#else + "--enable_mirrors=false", + + // The interpreter is enabled unconditionally. If an app is built for + // debugging (that is, with no bytecode), the VM will fall back on ASTs. + "--enable_interpreter", +#endif + + // No asserts in debug or release product. + // No asserts in release with flutter_profile=true (non-product) + // Yes asserts in non-product debug. +#if !defined(DART_PRODUCT) && (!defined(FLUTTER_PROFILE) || !defined(NDEBUG)) + "--enable_asserts", +#endif + // clang-format on +}; + +Dart_Isolate IsolateCreateCallback(const char* uri, + const char* name, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* callback_data, + char** error) { + if (std::string(uri) == DART_VM_SERVICE_ISOLATE_NAME) { +#if defined(DART_PRODUCT) + *error = strdup("The service isolate is not implemented in product mode"); + return NULL; +#else + return CreateServiceIsolate(uri, flags, error); +#endif + } + + *error = strdup("Isolate spawning is not implemented in dart_runner"); + return NULL; +} + +void IsolateShutdownCallback(void* callback_data) { + // The service isolate (and maybe later the kernel isolate) doesn't have an + // async loop. + auto dispatcher = async_get_default_dispatcher(); + auto loop = async_loop_from_dispatcher(dispatcher); + if (loop) { + tonic::DartMicrotaskQueue::GetForCurrentThread()->Destroy(); + async_loop_quit(loop); + } +} + +void IsolateCleanupCallback(void* callback_data) { + delete static_cast*>(callback_data); +} + +void RunApplication( + DartRunner* runner, + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + std::shared_ptr runner_incoming_services, + ::fidl::InterfaceRequest controller) { + int64_t start = Dart_TimelineGetMicros(); + DartComponentController app(std::move(package), std::move(startup_info), + runner_incoming_services, std::move(controller)); + bool success = app.Setup(); + int64_t end = Dart_TimelineGetMicros(); + Dart_TimelineEvent("DartComponentController::Setup", start, end, + Dart_Timeline_Event_Duration, 0, NULL, NULL); + if (success) { + app.Run(); + } + + if (Dart_CurrentIsolate()) { + Dart_ShutdownIsolate(); + } +} + +bool EntropySource(uint8_t* buffer, intptr_t count) { + zx_cprng_draw(buffer, count); + return true; +} + +} // namespace + +DartRunner::DartRunner() : context_(sys::ComponentContext::Create()) { + context_->outgoing()->AddPublicService( + [this](fidl::InterfaceRequest request) { + bindings_.AddBinding(this, std::move(request)); + }); + +#if !defined(DART_PRODUCT) + // The VM service isolate uses the process-wide namespace. It writes the + // vm service protocol port under /tmp. The VMServiceObject exposes that + // port number to The Hub. + context_->outgoing()->debug_dir()->AddEntry( + dart_utils::VMServiceObject::kPortDirName, + std::make_unique()); + +#endif // !defined(DART_PRODUCT) + + dart::bin::BootstrapDartIo(); + + char* error = + Dart_SetVMFlags(dart_utils::ArraySize(kDartVMArgs), kDartVMArgs); + if (error) { + FX_LOGF(FATAL, LOG_TAG, "Dart_SetVMFlags failed: %s", error); + } + + Dart_InitializeParams params = {}; + params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; +#if defined(AOT_RUNTIME) + params.vm_snapshot_data = ::_kDartVmSnapshotData; + params.vm_snapshot_instructions = ::_kDartVmSnapshotInstructions; +#else + if (!MappedResource::LoadFromNamespace( + nullptr, "pkg/data/vm_snapshot_data.bin", vm_snapshot_data_)) { + FX_LOG(FATAL, LOG_TAG, "Failed to load vm snapshot data"); + } + if (!MappedResource::LoadFromNamespace( + nullptr, "pkg/data/vm_snapshot_instructions.bin", + vm_snapshot_instructions_, true /* executable */)) { + FX_LOG(FATAL, LOG_TAG, "Failed to load vm snapshot instructions"); + } + params.vm_snapshot_data = vm_snapshot_data_.address(); + params.vm_snapshot_instructions = vm_snapshot_instructions_.address(); +#endif + params.create = IsolateCreateCallback; + params.shutdown = IsolateShutdownCallback; + params.cleanup = IsolateCleanupCallback; + params.entropy_source = EntropySource; +#if !defined(DART_PRODUCT) + params.get_service_assets = GetVMServiceAssetsArchiveCallback; +#endif + error = Dart_Initialize(¶ms); + if (error) + FX_LOGF(FATAL, LOG_TAG, "Dart_Initialize failed: %s", error); +} + +DartRunner::~DartRunner() { + char* error = Dart_Cleanup(); + if (error) + FX_LOGF(FATAL, LOG_TAG, "Dart_Cleanup failed: %s", error); +} + +void DartRunner::StartComponent( + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + ::fidl::InterfaceRequest controller) { + TRACE_EVENT1("dart", "StartComponent", "url", package.resolved_url.c_str()); + std::thread thread(RunApplication, this, std::move(package), + std::move(startup_info), context_->svc(), + std::move(controller)); + thread.detach(); +} + +} // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/dart_runner.h b/engine/src/flutter/shell/platform/fuchsia/dart/dart_runner.h new file mode 100644 index 0000000000..bfb762fd3b --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/dart_runner.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef TOPAZ_RUNTIME_DART_RUNNER_DART_RUNNER_H_ +#define TOPAZ_RUNTIME_DART_RUNNER_DART_RUNNER_H_ + +#include +#include +#include + +#include "mapped_resource.h" + +namespace dart_runner { + +class DartRunner : public fuchsia::sys::Runner { + public: + explicit DartRunner(); + ~DartRunner() override; + + private: + // |fuchsia::sys::Runner| implementation: + void StartComponent( + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + ::fidl::InterfaceRequest controller) + override; + + std::unique_ptr context_; + fidl::BindingSet bindings_; + +#if !defined(AOT_RUNTIME) + MappedResource vm_snapshot_data_; + MappedResource vm_snapshot_instructions_; +#endif + + // Disallow copy and assignment. + DartRunner(const DartRunner&) = delete; + DartRunner& operator=(const DartRunner&) = delete; +}; + +} // namespace dart_runner + +#endif // TOPAZ_RUNTIME_DART_RUNNER_DART_RUNNER_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/BUILD.gn new file mode 100644 index 0000000000..53ad9b4bc8 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/BUILD.gn @@ -0,0 +1,101 @@ +# 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. + +import("//build/dart/toolchain.gni") +import("//topaz/runtime/dart/dart_component.gni") +import("//topaz/runtime/dart/dart_kernel.gni") + +dart_kernel("shim") { + platform_name = "dart_runner" + platform_deps = [ "//topaz/runtime/dart_runner/kernel:kernel_platform_files" ] + platform_path = "$root_out_dir/dart_runner_patched_sdk" + + disable_analysis = true + + main_dart = "shim.dart" + + aot = true + product = false + + visibility = [ ":*" ] +} + +dart_kernel("shim_product") { + platform_name = "dart_runner" + platform_deps = [ "//topaz/runtime/dart_runner/kernel:kernel_platform_files" ] + platform_path = "$root_out_dir/dart_runner_patched_sdk" + + disable_analysis = true + + main_dart = "shim.dart" + + aot = true + product = true + + visibility = [ ":*" ] +} + +template("create_aot_snapshot") { + assert(defined(invoker.product), "The parameter 'product' must be defined") + product_suffix = "" + if (invoker.product) { + product_suffix = "_product" + } + action("${target_name}_assembly") { + snapshot_assembly = "$target_gen_dir/aot${product_suffix}_vm_snapshot.S" + + # gen_snapshot only needs this to go through the motions of setting up an isolate. + shim_target = ":shim${product_suffix}_kernel" + shim_kernel = get_label_info(shim_target, "target_gen_dir") + + "/shim${product_suffix}_kernel.dil" + + inputs = [ + shim_kernel, + ] + outputs = [ + snapshot_assembly, + ] + + deps = gen_snapshot_deps + [ shim_target ] + if (invoker.product) { + script = gen_snapshot_product + } else { + script = gen_snapshot + } + + args = [ + "--no_causal_async_stacks", + "--deterministic", + "--snapshot_kind=vm-aot-assembly", + "--assembly=" + rebase_path(snapshot_assembly), + ] + + # No asserts in debug or release product. + # No asserts in release with flutter_profile=true (non-product) + # Yes asserts in non-product debug. + if (!invoker.product && (!flutter_profile || is_debug)) { + args += [ "--enable_asserts" ] + } + args += [ rebase_path(shim_kernel) ] + } + + source_set(target_name) { + deps = [ + ":${target_name}_assembly", + ] + + sources = [ + "$target_gen_dir/aot${product_suffix}_vm_snapshot.S", + "snapshot.h", + ] + } +} + +create_aot_snapshot("dart_aot_snapshot_cc") { + product = false +} + +create_aot_snapshot("dart_aot_product_snapshot_cc") { + product = true +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/builtin.dart b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/builtin.dart new file mode 100644 index 0000000000..7c389747d4 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/builtin.dart @@ -0,0 +1,50 @@ +// 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. + +library fuchsia_builtin; + +import 'dart:async'; +import 'dart:io'; +import 'dart:_internal' show VMLibraryHooks; + +// Corelib 'print' implementation. +void _print(arg) { + _Logger._printString(arg.toString()); + try { + // If stdout is connected, print to it as well. + stdout.writeln(arg); + } on FileSystemException catch (_) { + // Some Fuchsia applications will not have stdout connected. + } +} + +class _Logger { + static void _printString(String s) native "Logger_PrintString"; +} + +@pragma('vm:entry-point') +String _rawScript; + +Uri _scriptUri() { + if (_rawScript.startsWith('http:') || + _rawScript.startsWith('https:') || + _rawScript.startsWith('file:')) { + return Uri.parse(_rawScript); + } else { + return Uri.base.resolveUri(Uri.file(_rawScript)); + } +} + +void _scheduleMicrotask(void callback()) native "ScheduleMicrotask"; + +@pragma('vm:entry-point') +_getScheduleMicrotaskClosure() => _scheduleMicrotask; + +@pragma('vm:entry-point') +_setupHooks() { + VMLibraryHooks.platformScript = _scriptUri; +} + +@pragma('vm:entry-point') +_getPrintClosure() => _print; diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/pubspec.yaml new file mode 100644 index 0000000000..eaea68b269 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/pubspec.yaml @@ -0,0 +1,6 @@ +# 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. + +# The presence of this file is necessary in order to use the dart_library +# template in BUILD.gn. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/script_runner_snapshot.dart b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/script_runner_snapshot.dart new file mode 100644 index 0000000000..a3d7e41f5a --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/script_runner_snapshot.dart @@ -0,0 +1,31 @@ +// 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. + +// Core SDK libraries. +import 'dart:async'; +import 'dart:core'; +import 'dart:collection'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math'; +import 'dart:fuchsia.builtin'; +import 'dart:zircon'; +import 'dart:fuchsia'; +import 'dart:typed_data'; + +// If new imports are added to this list, then it is also necessary to ensure +// that the dart_deps parameter in the rule +// gen_snapshot_cc("script_runner_snapshot") in the BUILD.gn file in this +// directory is updated with any new dependencies. + +import 'package:fuchsia/fuchsia.dart'; +import 'package:zircon/zircon.dart'; + +// FIDL bindings and application libraries. +import 'package:lib.app.dart/app.dart'; +import 'package:fidl/fidl.dart'; + +// From //sdk/fidl/fuchsia.modular +import 'package:fidl_fuchsia_modular/fidl.dart'; diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/shim.dart b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/shim.dart new file mode 100644 index 0000000000..6fb4720184 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/shim.dart @@ -0,0 +1,5 @@ +// 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. + +main() {} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.cc.tmpl b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.cc.tmpl new file mode 100644 index 0000000000..29ce399315 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.cc.tmpl @@ -0,0 +1,25 @@ +// 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. + +// This file is linked into the dart executable when it has a snapshot +// linked into it. + +#include "embedder/snapshot.h" + +namespace dart_runner { + +// The string on the next line will be filled in with the contents of the +// generated snapshot binary file for the vm isolate. This string forms the +// content of the dart vm isolate snapshot which is loaded into the vm isolate. +static const uint8_t vm_isolate_snapshot_buffer_[] = { % s}; +uint8_t const* const vm_isolate_snapshot_buffer = vm_isolate_snapshot_buffer_; + +// The string on the next line will be filled in with the contents of the +// generated snapshot binary file for a regular dart isolate. +// This string forms the content of a regular dart isolate snapshot which +// is loaded into an isolate when it is created. +static const uint8_t isolate_snapshot_buffer_[] = { % s}; +uint8_t const* const isolate_snapshot_buffer = isolate_snapshot_buffer_; + +} // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.dart b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.dart new file mode 100644 index 0000000000..4bfa41edf0 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.dart @@ -0,0 +1,15 @@ +// 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. + +import 'dart:async'; +import 'dart:core'; +import 'dart:collection'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math'; +import 'dart:fuchsia.builtin'; +import 'dart:zircon'; +import 'dart:fuchsia'; +import 'dart:typed_data'; diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.h b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.h new file mode 100644 index 0000000000..72740a7a54 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/embedder/snapshot.h @@ -0,0 +1,12 @@ +// 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 + +namespace dart_runner { + +extern uint8_t const* const vm_isolate_snapshot_buffer; +extern uint8_t const* const isolate_snapshot_buffer; + +} // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/BUILD.gn new file mode 100644 index 0000000000..f8a76c2436 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/BUILD.gn @@ -0,0 +1,68 @@ +# 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. + +import("//build/testing/environments.gni") +import("//topaz/runtime/dart_runner/dart_app.gni") + +dart_jit_app("goodbye_dart_jit") { + sources = [ + "goodbye_dart.dart", + ] + main_dart = "goodbye_dart.dart" + + source_dir = "." + deps = [ + "//topaz/public/dart/fidl", + "//topaz/public/dart/fuchsia", + ] + + meta = [ + { + path = "meta/goodbye_dart_jit.cmx" + dest = "goodbye_dart_jit.cmx" + }, + ] +} + +dart_aot_app("goodbye_dart_aot") { + sources = [ + "goodbye_dart.dart", + ] + main_dart = "goodbye_dart.dart" + + source_dir = "." + deps = [ + "//topaz/public/dart/fidl", + "//topaz/public/dart/fuchsia", + ] + + meta = [ + { + path = "meta/goodbye_dart_aot.cmx" + dest = "goodbye_dart_aot.cmx" + }, + ] +} + +copy("copy_goodbye_dart_test") { + sources = [ + "goodbye_dart_test", + ] + outputs = [ + "${root_build_dir}/goodbye_dart_test", + ] +} + +package("goodbye_dart_test") { + testonly = true + tests = [ + { + name = "goodbye_dart_test" + environments = basic_envs + }, + ] + deps = [ + ":copy_goodbye_dart_test", + ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/analysis_options.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/analysis_options.yaml new file mode 100644 index 0000000000..791d599e3d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/analysis_options.yaml @@ -0,0 +1,5 @@ +# 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: ../../../../tools/analysis_options.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart.dart b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart.dart new file mode 100644 index 0000000000..5aea0fbb40 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart.dart @@ -0,0 +1,24 @@ +// 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. + +import 'dart:async'; + +import 'package:fuchsia/fuchsia.dart' as fuchsia; + +// ignore: unused_element +Timer _timer; + +void main(List args) { + print('Hello, Dart!'); + + if (args.isNotEmpty && args.first == '--now') { + print('Goodbye now!'); + fuchsia.exit(23); + } + + _timer = Timer(const Duration(seconds: 1), () { + print('Goodbye, Dart!'); + fuchsia.exit(42); + }); +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart_test b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart_test new file mode 100644 index 0000000000..e11e1bcdea --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/goodbye_dart_test @@ -0,0 +1,25 @@ +#!/boot/bin/sh + +run fuchsia-pkg://fuchsia.con/goodbye_dart_aot#meta/goodbye_dart_aot.cmx --now +if [ $? -ne 23 ]; then + echo "goodbye_dart_aot --now failed" + exit 1 +fi + +# run goodbye_dart_jit --now +# if [ $? -ne 23 ]; then +# echo "goodbye_dart_jit --now failed" +# exit 1 +# fi + +run fuchsia-pkg://fuchsia.con/goodbye_dart_aot#meta/goodbye_dart_aot.cmx +if [ $? -ne 42 ]; then + echo "goodbye_dart_aot failed" + exit 1 +fi + +# run goodbye_dart_jit +# if [ $? -ne 42 ]; then +# echo "goodbye_dart_jit failed" +# exit 1 +# fi diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_aot.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_aot.cmx new file mode 100644 index 0000000000..c2d2112f14 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_aot.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/goodbye_dart_aot" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_jit.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_jit.cmx new file mode 100644 index 0000000000..296167c381 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/meta/goodbye_dart_jit.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/goodbye_dart_jit" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/pubspec.yaml new file mode 100644 index 0000000000..5e8ae01a4e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/goodbye_dart/pubspec.yaml @@ -0,0 +1,3 @@ +# 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. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/BUILD.gn new file mode 100644 index 0000000000..082624f087 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/BUILD.gn @@ -0,0 +1,15 @@ +# 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. + +import("//build/dart/dart_library.gni") + +dart_library("greeting") { + infer_package_name = true + + sources = [ + "greeting.dart", + ] + + source_dir = "." +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/analysis_options.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/analysis_options.yaml new file mode 100644 index 0000000000..791d599e3d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/analysis_options.yaml @@ -0,0 +1,5 @@ +# 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: ../../../../tools/analysis_options.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/greeting.dart b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/greeting.dart new file mode 100644 index 0000000000..d18022a9db --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/greeting.dart @@ -0,0 +1,8 @@ +// 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. + +/// Returns a greeting. +String greeting() { + return 'Hello'; +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/pubspec.yaml new file mode 100644 index 0000000000..5e8ae01a4e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/greeting/pubspec.yaml @@ -0,0 +1,3 @@ +# 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. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/BUILD.gn new file mode 100644 index 0000000000..7e6e3e1e93 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/BUILD.gn @@ -0,0 +1,44 @@ +# 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. + +import("//topaz/runtime/dart_runner/dart_app.gni") + +dart_jit_app("hello_app_dart_jit") { + main_dart = "main.dart" + + source_dir = "." + + sources = [] + deps = [ + "//topaz/public/dart/fidl", + "//topaz/public/dart/fuchsia_services", + "//topaz/runtime/dart_runner/examples/hello_app_dart/interfaces:interfaces", + ] + + meta = [ + { + path = "meta/hello_app_dart_jit.cmx" + dest = "hello_app_dart_jit.cmx" + }, + ] +} + +dart_aot_app("hello_app_dart_aot") { + main_dart = "main.dart" + + source_dir = "." + + sources = [] + deps = [ + "//topaz/public/dart/fidl", + "//topaz/public/dart/fuchsia_services", + "//topaz/runtime/dart_runner/examples/hello_app_dart/interfaces:interfaces", + ] + meta = [ + { + path = "meta/hello_app_dart_aot.cmx" + dest = "hello_app_dart_aot.cmx" + }, + ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/analysis_options.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/analysis_options.yaml new file mode 100644 index 0000000000..791d599e3d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/analysis_options.yaml @@ -0,0 +1,5 @@ +# 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: ../../../../tools/analysis_options.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/BUILD.gn new file mode 100644 index 0000000000..19ac79665f --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/BUILD.gn @@ -0,0 +1,13 @@ +# 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. + +import("//build/fidl/fidl.gni") + +fidl("interfaces") { + name = "fuchsia.examples.hello" + + sources = [ + "hello.fidl", + ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/hello.fidl b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/hello.fidl new file mode 100644 index 0000000000..7dee0ffe7d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/interfaces/hello.fidl @@ -0,0 +1,10 @@ +// 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. + +library fuchsia.examples.hello; + +[Discoverable] +protocol Hello { + Say(string request) -> (string response); +}; diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/main.dart b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/main.dart new file mode 100644 index 0000000000..7ea8a58d2a --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/main.dart @@ -0,0 +1,28 @@ +// 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. + +import 'package:fidl/fidl.dart'; + +import 'package:fuchsia_services/services.dart'; +import 'package:fidl_fuchsia_examples_hello/fidl_async.dart'; + +class _HelloImpl extends Hello { + final HelloBinding _binding = HelloBinding(); + + void bind(InterfaceRequest request) { + _binding.bind(this, request); + } + + @override + Future say(String request) async { + return request == 'hello' ? 'hola from Dart!' : 'adios from Dart!'; + } +} + +void main(List args) { + StartupContext context = StartupContext.fromStartupInfo(); + + context.outgoing + .addPublicService(_HelloImpl().bind, Hello.$serviceName); +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_aot.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_aot.cmx new file mode 100644 index 0000000000..6046d17c17 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_aot.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_app_dart_aot" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_jit.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_jit.cmx new file mode 100644 index 0000000000..b8ff06f0a5 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/meta/hello_app_dart_jit.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_app_dart_jit" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/pubspec.yaml new file mode 100644 index 0000000000..5e8ae01a4e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_app_dart/pubspec.yaml @@ -0,0 +1,3 @@ +# 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. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/BUILD.gn new file mode 100644 index 0000000000..56505dda2f --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/BUILD.gn @@ -0,0 +1,111 @@ +# 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. + +import("//topaz/runtime/dart_runner/dart_app.gni") + +dart_jit_app("hello_dart_debug") { + main_dart = "bin/hello_dart.dart" + + source_dir = "." + + product = false + space_dart = false + + sources = [] + deps = [ + "//topaz/public/dart/zircon", + "//topaz/runtime/dart_runner/examples/greeting", + ] + + meta = [ + { + path = "meta/hello_dart_debug.cmx" + dest = "hello_dart_debug.cmx" + }, + ] +} + +dart_jit_app("hello_dart_jit") { + main_dart = "bin/hello_dart.dart" + + source_dir = "." + + product = false + + sources = [] + deps = [ + "//topaz/public/dart/zircon", + "//topaz/runtime/dart_runner/examples/greeting", + ] + + meta = [ + { + path = "meta/hello_dart_jit.cmx" + dest = "hello_dart_jit.cmx" + }, + ] +} + +dart_jit_app("hello_dart_jit_product") { + main_dart = "bin/hello_dart.dart" + + source_dir = "." + + product = true + + sources = [] + deps = [ + "//topaz/public/dart/zircon", + "//topaz/runtime/dart_runner/examples/greeting", + ] + + meta = [ + { + path = "meta/hello_dart_jit_product.cmx" + dest = "hello_dart_jit_product.cmx" + }, + ] +} + +dart_aot_app("hello_dart_aot") { + main_dart = "bin/hello_dart.dart" + + source_dir = "." + + product = false + + sources = [] + deps = [ + "//topaz/public/dart/zircon", + "//topaz/runtime/dart_runner/examples/greeting", + ] + + meta = [ + { + path = "meta/hello_dart_aot.cmx" + dest = "hello_dart_aot.cmx" + }, + ] +} + +dart_aot_app("hello_dart_aot_product") { + main_dart = "bin/hello_dart.dart" + + source_dir = "." + + product = true + + sources = [] + deps = [ + "//topaz/public/dart/zircon", + "//topaz/runtime/dart_runner/examples/greeting", + ] + + meta = [ + { + path = "meta/hello_dart_aot_product.cmx" + dest = "hello_dart_aot_product.cmx" + }, + ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/analysis_options.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/analysis_options.yaml new file mode 100644 index 0000000000..791d599e3d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/analysis_options.yaml @@ -0,0 +1,5 @@ +# 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: ../../../../tools/analysis_options.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/bin/hello_dart.dart b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/bin/hello_dart.dart new file mode 100644 index 0000000000..5e9ab22572 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/bin/hello_dart.dart @@ -0,0 +1,9 @@ +// 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. + +import 'package:topaz.runtime.dart_runner.examples.greeting/greeting.dart'; + +void main(List args) { + print('${greeting()}, Dart!'); +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot.cmx new file mode 100644 index 0000000000..7f95a4c133 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_dart_aot" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot_product.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot_product.cmx new file mode 100644 index 0000000000..8df0f57c4f --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_aot_product.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_dart_aot_product" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_debug.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_debug.cmx new file mode 100644 index 0000000000..4a7426b8d4 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_debug.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_dart_debug" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit.cmx new file mode 100644 index 0000000000..feccd66dda --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_dart_jit" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit_product.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit_product.cmx new file mode 100644 index 0000000000..fa55e46c67 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/meta/hello_dart_jit_product.cmx @@ -0,0 +1,11 @@ +{ + "program": { + "data": "data/hello_dart_jit_product" + }, + "sandbox": { + "features": [], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/pubspec.yaml new file mode 100644 index 0000000000..5e8ae01a4e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/examples/hello_dart/pubspec.yaml @@ -0,0 +1,3 @@ +# 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. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/integration/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/integration/BUILD.gn new file mode 100644 index 0000000000..311f38b50c --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/integration/BUILD.gn @@ -0,0 +1,51 @@ +# 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. + +import("//topaz/runtime/dart_runner/dart_app.gni") + +dart_jit_app("dart_jit_runner_test") { + testonly = true + + main_dart = "main.dart" + + source_dir = "." + + meta = [ + { + path = rebase_path("meta/dart_jit_runner_test.cmx") + dest = "dart_jit_runner_test.cmx" + }, + ] + + sources = [] + deps = [ + "//third_party/dart-pkg/pub/test", + "//topaz/public/dart/fuchsia_services", + "//topaz/runtime/dart_runner/examples/hello_app_dart/interfaces:interfaces", + "//zircon/public/fidl/fuchsia-io", + ] +} + +dart_aot_app("dart_aot_runner_test") { + testonly = true + + main_dart = "main.dart" + + source_dir = "." + + meta = [ + { + path = rebase_path("meta/dart_aot_runner_test.cmx") + dest = "dart_aot_runner_test.cmx" + }, + ] + + sources = [] + deps = [ + "//third_party/dart-pkg/pub/test", + "//topaz/public/dart/fuchsia_services", + "//topaz/runtime/dart_runner/examples/hello_app_dart/interfaces:interfaces", + "//zircon/public/fidl/fuchsia-io", + ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/integration/analysis_options.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/integration/analysis_options.yaml new file mode 100644 index 0000000000..704eb990c3 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/integration/analysis_options.yaml @@ -0,0 +1,5 @@ +# 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: ../../../tools/analysis_options.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/integration/main.dart b/engine/src/flutter/shell/platform/fuchsia/dart/integration/main.dart new file mode 100644 index 0000000000..0464f8a0f3 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/integration/main.dart @@ -0,0 +1,62 @@ +// 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. + +import 'dart:async'; +import 'dart:io' as io; + +import 'package:fidl_fuchsia_examples_hello/fidl_async.dart'; +import 'package:fidl_fuchsia_io/fidl_async.dart'; +import 'package:fidl_fuchsia_sys/fidl_async.dart'; +import 'package:fuchsia_services/services.dart'; +import 'package:test/test.dart'; + +void main(List args) { + final StartupContext context = StartupContext.fromStartupInfo(); + LauncherProxy launcher; + + setUp(() { + launcher = LauncherProxy(); + context.incoming.connectToService(launcher); + }); + + tearDown(() { + launcher.ctrl.close(); + launcher = null; + }); + + // TODO(rosswang): nested environments and determinism + + test('schedule delayed futures', + () => Future.delayed(const Duration(seconds: 1))); + + test('start hello_dart', () async { + const LaunchInfo info = LaunchInfo( + url: + 'fuchsia-pkg://fuchsia.com/hello_dart_jit#meta/hello_dart_jit.cmx'); + await launcher.createComponent( + info, ComponentControllerProxy().ctrl.request()); + }); + + test('communicate with a fidl service (hello_app_dart)', () async { + final HelloProxy service = HelloProxy(); + final dirProxy = DirectoryProxy(); + + final ComponentControllerProxy actl = ComponentControllerProxy(); + + final LaunchInfo info = LaunchInfo( + url: + 'fuchsia-pkg://fuchsia.com/hello_app_dart_jit#meta/hello_app_dart_jit.cmx', + directoryRequest: dirProxy.ctrl.request().passChannel()); + await launcher.createComponent(info, actl.ctrl.request()); + Incoming(dirProxy).connectToService(service); + + expect(await service.say('hello'), equals('hola from Dart!')); + + actl.ctrl.close(); + }); + + test('dart:io exit() throws UnsupportedError', () { + expect(() => io.exit(-1), throwsUnsupportedError); + }); +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/integration/meta/dart_aot_runner_test.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/integration/meta/dart_aot_runner_test.cmx new file mode 100644 index 0000000000..807f64665d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/integration/meta/dart_aot_runner_test.cmx @@ -0,0 +1,22 @@ +{ + "program": { + "data": "data/dart_aot_runner_test" + }, + "sandbox": { + "services": [ + "fuchsia.cobalt.LoggerFactory", + "fuchsia.fonts.Provider", + "fuchsia.logger.LogSink", + "fuchsia.modular.Clipboard", + "fuchsia.modular.ContextWriter", + "fuchsia.modular.ModuleContext", + "fuchsia.netstack.Netstack", + "fuchsia.sys.Environment", + "fuchsia.sys.Launcher", + "fuchsia.ui.input.ImeService", + "fuchsia.ui.policy.Presenter", + "fuchsia.ui.scenic.Scenic", + "fuchsia.wlan.service.Wlan" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/integration/meta/dart_jit_runner_test.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/integration/meta/dart_jit_runner_test.cmx new file mode 100644 index 0000000000..0553a6cf88 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/integration/meta/dart_jit_runner_test.cmx @@ -0,0 +1,22 @@ +{ + "program": { + "data": "data/dart_jit_runner_test" + }, + "sandbox": { + "services": [ + "fuchsia.cobalt.LoggerFactory", + "fuchsia.fonts.Provider", + "fuchsia.logger.LogSink", + "fuchsia.modular.Clipboard", + "fuchsia.modular.ContextWriter", + "fuchsia.modular.ModuleContext", + "fuchsia.netstack.Netstack", + "fuchsia.sys.Environment", + "fuchsia.sys.Launcher", + "fuchsia.ui.input.ImeService", + "fuchsia.ui.policy.Presenter", + "fuchsia.ui.scenic.Scenic", + "fuchsia.wlan.service.Wlan" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/integration/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/integration/pubspec.yaml new file mode 100644 index 0000000000..5e8ae01a4e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/integration/pubspec.yaml @@ -0,0 +1,3 @@ +# 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. diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/kernel/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/kernel/BUILD.gn new file mode 100644 index 0000000000..c163171c6f --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/kernel/BUILD.gn @@ -0,0 +1,104 @@ +# 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. + +import("//build/dart/dart_tool.gni") +import("//third_party/dart/utils/compile_platform.gni") +import("//topaz/runtime/dart/dart_component.gni") + +compile_platform("kernel_platform_files") { + single_root_scheme = "org-dartlang-sdk" + single_root_base = rebase_path("../../../../") + + libraries_specification_uri = + "org-dartlang-sdk:///topaz/runtime/dart_runner/kernel/libraries.json" + + outputs = [ + "$root_out_dir/dart_runner_patched_sdk/platform_strong.dill", + "$root_out_dir/dart_runner_patched_sdk/vm_outline_strong.dill", + ] + + args = [ + # TODO(dartbug.com/36342): enable bytecode for core libraries when performance of bytecode + # pipeline is on par with default pipeline and continuously tracked. + # "--bytecode", + "--target=dart_runner", + "dart:core", + ] +} + +template("create_kernel_core_snapshot") { + assert(defined(invoker.product), "The parameter 'product' must be defined") + product_suffix = "" + if (invoker.product) { + product_suffix = "_product" + } + action(target_name) { + deps = gen_snapshot_deps + [ ":kernel_platform_files" ] + + platform_dill = "$root_out_dir/dart_runner_patched_sdk/platform_strong.dill" + compilation_trace = "//topaz/runtime/flutter_runner/compilation_trace.txt" + inputs = [ + platform_dill, + compilation_trace, + ] + + vm_snapshot_data = "$target_gen_dir/vm_data${product_suffix}.bin" + vm_snapshot_instructions = + "$target_gen_dir/vm_instructions${product_suffix}.bin" + isolate_snapshot_data = "$target_gen_dir/isolate_data${product_suffix}.bin" + isolate_snapshot_instructions = + "$target_gen_dir/isolate_instructions${product_suffix}.bin" + snapshot_profile = "$target_gen_dir/snapshot_profile${product_suffix}.json" + outputs = [ + vm_snapshot_data, + vm_snapshot_instructions, + isolate_snapshot_data, + isolate_snapshot_instructions, + snapshot_profile, + ] + + if (invoker.product) { + script = gen_snapshot_product + } else { + script = gen_snapshot + } + + args = [ + # TODO(FL-117): Re-enable causal async stack traces when this issue is + # addressed. + "--no_causal_async_stacks", + "--use_bytecode_compiler", + "--enable_mirrors=false", + "--deterministic", + "--snapshot_kind=core-jit", + "--load_compilation_trace=" + + rebase_path(compilation_trace, root_build_dir), + "--vm_snapshot_data=" + rebase_path(vm_snapshot_data, root_build_dir), + "--vm_snapshot_instructions=" + + rebase_path(vm_snapshot_instructions, root_build_dir), + "--isolate_snapshot_data=" + + rebase_path(isolate_snapshot_data, root_build_dir), + "--isolate_snapshot_instructions=" + + rebase_path(isolate_snapshot_instructions, root_build_dir), + "--write_v8_snapshot_profile_to=" + + rebase_path(snapshot_profile, root_build_dir), + ] + + # No asserts in debug or release product. + # No asserts in release with flutter_profile=true (non-product) + # Yes asserts in non-product debug. + if (!invoker.product && (!flutter_profile || is_debug)) { + args += [ "--enable_asserts" ] + } + args += [ rebase_path(platform_dill) ] + } +} + +create_kernel_core_snapshot("kernel_core_snapshot") { + product = false +} + +create_kernel_core_snapshot("kernel_core_snapshot_product") { + product = true +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/kernel/libraries.json b/engine/src/flutter/shell/platform/fuchsia/dart/kernel/libraries.json new file mode 100644 index 0000000000..98f1ca322b --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/kernel/libraries.json @@ -0,0 +1,158 @@ +{ + "comment:0": "NOTE: THIS FILE IS GENERATED. DO NOT EDIT.", + "comment:1": "Instead modify 'topaz/runtime/dart_runner/kernel/libraries.yaml' and follow the instructions therein.", + "dart_runner": { + "libraries": { + "_builtin": { + "uri": "../../../../third_party/dart/runtime/bin/builtin.dart" + }, + "core": { + "patches": [ + "../../../../third_party/dart/runtime/lib/core_patch.dart", + "../../../../third_party/dart/runtime/lib/array.dart", + "../../../../third_party/dart/runtime/lib/array_patch.dart", + "../../../../third_party/dart/runtime/lib/bigint_patch.dart", + "../../../../third_party/dart/runtime/lib/bool_patch.dart", + "../../../../third_party/dart/runtime/lib/date_patch.dart", + "../../../../third_party/dart/runtime/lib/double.dart", + "../../../../third_party/dart/runtime/lib/double_patch.dart", + "../../../../third_party/dart/runtime/lib/errors_patch.dart", + "../../../../third_party/dart/runtime/lib/expando_patch.dart", + "../../../../third_party/dart/runtime/lib/function.dart", + "../../../../third_party/dart/runtime/lib/function_patch.dart", + "../../../../third_party/dart/runtime/lib/growable_array.dart", + "../../../../third_party/dart/runtime/lib/identical_patch.dart", + "../../../../third_party/dart/runtime/lib/immutable_map.dart", + "../../../../third_party/dart/runtime/lib/integers.dart", + "../../../../third_party/dart/runtime/lib/integers_patch.dart", + "../../../../third_party/dart/runtime/lib/invocation_mirror_patch.dart", + "../../../../third_party/dart/runtime/lib/lib_prefix.dart", + "../../../../third_party/dart/runtime/lib/map_patch.dart", + "../../../../third_party/dart/runtime/lib/null_patch.dart", + "../../../../third_party/dart/runtime/lib/object_patch.dart", + "../../../../third_party/dart/runtime/lib/regexp_patch.dart", + "../../../../third_party/dart/runtime/lib/stacktrace.dart", + "../../../../third_party/dart/runtime/lib/stopwatch_patch.dart", + "../../../../third_party/dart/runtime/lib/string_buffer_patch.dart", + "../../../../third_party/dart/runtime/lib/string_patch.dart", + "../../../../third_party/dart/runtime/lib/type_patch.dart", + "../../../../third_party/dart/runtime/lib/uri_patch.dart", + "../../../../third_party/dart/runtime/lib/weak_property.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/core/core.dart" + }, + "zircon": { + "uri": "../../../../topaz/public/dart-pkg/zircon/lib/zircon.dart" + }, + "async": { + "patches": [ + "../../../../third_party/dart/runtime/lib/async_patch.dart", + "../../../../third_party/dart/runtime/lib/deferred_load_patch.dart", + "../../../../third_party/dart/runtime/lib/schedule_microtask_patch.dart", + "../../../../third_party/dart/runtime/lib/timer_patch.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/async/async.dart" + }, + "collection": { + "patches": [ + "../../../../third_party/dart/runtime/lib/collection_patch.dart", + "../../../../third_party/dart/runtime/lib/compact_hash.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/collection/collection.dart" + }, + "ffi": { + "patches": [ + "../../../../third_party/dart/runtime/lib/ffi_dynamic_library_patch.dart", + "../../../../third_party/dart/runtime/lib/ffi_native_type_patch.dart", + "../../../../third_party/dart/runtime/lib/ffi_patch.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/ffi/ffi.dart" + }, + "typed_data": { + "patches": "../../../../third_party/dart/runtime/lib/typed_data_patch.dart", + "uri": "../../../../third_party/dart/sdk/lib/typed_data/typed_data.dart" + }, + "nativewrappers": { + "uri": "../../../../third_party/dart/sdk/lib/html/dartium/nativewrappers.dart" + }, + "developer": { + "patches": [ + "../../../../third_party/dart/runtime/lib/developer.dart", + "../../../../third_party/dart/runtime/lib/profiler.dart", + "../../../../third_party/dart/runtime/lib/timeline.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/developer/developer.dart" + }, + "isolate": { + "patches": [ + "../../../../third_party/dart/runtime/lib/isolate_patch.dart", + "../../../../third_party/dart/runtime/lib/timer_impl.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/isolate/isolate.dart" + }, + "mirrors": { + "patches": [ + "../../../../third_party/dart/runtime/lib/mirrors_patch.dart", + "../../../../third_party/dart/runtime/lib/mirrors_impl.dart", + "../../../../third_party/dart/runtime/lib/mirror_reference.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/mirrors/mirrors.dart" + }, + "_vmservice": { + "uri": "../../../../third_party/dart/sdk/lib/vmservice/vmservice.dart" + }, + "io": { + "patches": [ + "../../../../third_party/dart/runtime/bin/common_patch.dart", + "../../../../third_party/dart/runtime/bin/directory_patch.dart", + "../../../../third_party/dart/runtime/bin/eventhandler_patch.dart", + "../../../../third_party/dart/runtime/bin/file_patch.dart", + "../../../../third_party/dart/runtime/bin/file_system_entity_patch.dart", + "../../../../third_party/dart/runtime/bin/filter_patch.dart", + "../../../../third_party/dart/runtime/bin/io_service_patch.dart", + "../../../../third_party/dart/runtime/bin/namespace_patch.dart", + "../../../../third_party/dart/runtime/bin/platform_patch.dart", + "../../../../third_party/dart/runtime/bin/process_patch.dart", + "../../../../third_party/dart/runtime/bin/socket_patch.dart", + "../../../../third_party/dart/runtime/bin/stdio_patch.dart", + "../../../../third_party/dart/runtime/bin/secure_socket_patch.dart", + "../../../../third_party/dart/runtime/bin/sync_socket_patch.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/io/io.dart" + }, + "_internal": { + "patches": [ + "../../../../third_party/dart/runtime/lib/internal_patch.dart", + "../../../../third_party/dart/runtime/lib/class_id_fasta.dart", + "../../../../third_party/dart/runtime/lib/print_patch.dart", + "../../../../third_party/dart/runtime/lib/symbol_patch.dart", + "../../../../third_party/dart/sdk/lib/internal/patch.dart" + ], + "uri": "../../../../third_party/dart/sdk/lib/internal/internal.dart" + }, + "convert": { + "patches": "../../../../third_party/dart/runtime/lib/convert_patch.dart", + "uri": "../../../../third_party/dart/sdk/lib/convert/convert.dart" + }, + "profiler": { + "uri": "../../../../third_party/dart/sdk/lib/profiler/profiler.dart" + }, + "math": { + "patches": "../../../../third_party/dart/runtime/lib/math_patch.dart", + "uri": "../../../../third_party/dart/sdk/lib/math/math.dart" + }, + "_http": { + "uri": "../../../../third_party/dart/sdk/lib/_http/http.dart" + }, + "fuchsia": { + "uri": "../../../../topaz/public/dart-pkg/fuchsia/lib/fuchsia.dart" + }, + "fuchsia.builtin": { + "uri": "../../../../topaz/runtime/dart_runner/embedder/builtin.dart" + }, + "vmservice_io": { + "uri": "../../../../third_party/dart/runtime/bin/vmservice/vmservice_io.dart" + } + } + } +} \ No newline at end of file diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/kernel/libraries.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/kernel/libraries.yaml new file mode 100644 index 0000000000..3af64fab3e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/kernel/libraries.yaml @@ -0,0 +1,157 @@ +# Copyright (c) 2017, 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. + +# Note: if you edit this file, you must also edit libraries.json in this +# directory: +# +# python third_party/dart/tools/yaml2json.py \ +# topaz/runtime/dart_runner/kernel/libraries.yaml \ +# topaz/runtime/dart_runner/kernel/libraries.json +# +# We currently have several different files that needs to be updated when +# changing libraries, sources, and patch files. See +# https://github.com/dart-lang/sdk/issues/28836. + +dart_runner: + libraries: + _builtin: + uri: "../../../../third_party/dart/runtime/bin/builtin.dart" + + _internal: + uri: "../../../../third_party/dart/sdk/lib/internal/internal.dart" + patches: + - "../../../../third_party/dart/runtime/lib/internal_patch.dart" + - "../../../../third_party/dart/runtime/lib/class_id_fasta.dart" + - "../../../../third_party/dart/runtime/lib/print_patch.dart" + - "../../../../third_party/dart/runtime/lib/symbol_patch.dart" + - "../../../../third_party/dart/sdk/lib/internal/patch.dart" + + async: + uri: "../../../../third_party/dart/sdk/lib/async/async.dart" + patches: + - "../../../../third_party/dart/runtime/lib/async_patch.dart" + - "../../../../third_party/dart/runtime/lib/deferred_load_patch.dart" + - "../../../../third_party/dart/runtime/lib/schedule_microtask_patch.dart" + - "../../../../third_party/dart/runtime/lib/timer_patch.dart" + + collection: + uri: "../../../../third_party/dart/sdk/lib/collection/collection.dart" + patches: + - "../../../../third_party/dart/runtime/lib/collection_patch.dart" + - "../../../../third_party/dart/runtime/lib/compact_hash.dart" + + convert: + uri: "../../../../third_party/dart/sdk/lib/convert/convert.dart" + patches: "../../../../third_party/dart/runtime/lib/convert_patch.dart" + + core: + uri: "../../../../third_party/dart/sdk/lib/core/core.dart" + patches: + - "../../../../third_party/dart/runtime/lib/core_patch.dart" + - "../../../../third_party/dart/runtime/lib/array.dart" + - "../../../../third_party/dart/runtime/lib/array_patch.dart" + - "../../../../third_party/dart/runtime/lib/bigint_patch.dart" + - "../../../../third_party/dart/runtime/lib/bool_patch.dart" + - "../../../../third_party/dart/runtime/lib/date_patch.dart" + - "../../../../third_party/dart/runtime/lib/double.dart" + - "../../../../third_party/dart/runtime/lib/double_patch.dart" + - "../../../../third_party/dart/runtime/lib/errors_patch.dart" + - "../../../../third_party/dart/runtime/lib/expando_patch.dart" + - "../../../../third_party/dart/runtime/lib/function.dart" + - "../../../../third_party/dart/runtime/lib/function_patch.dart" + - "../../../../third_party/dart/runtime/lib/growable_array.dart" + - "../../../../third_party/dart/runtime/lib/identical_patch.dart" + - "../../../../third_party/dart/runtime/lib/immutable_map.dart" + - "../../../../third_party/dart/runtime/lib/integers.dart" + - "../../../../third_party/dart/runtime/lib/integers_patch.dart" + - "../../../../third_party/dart/runtime/lib/invocation_mirror_patch.dart" + - "../../../../third_party/dart/runtime/lib/lib_prefix.dart" + - "../../../../third_party/dart/runtime/lib/map_patch.dart" + - "../../../../third_party/dart/runtime/lib/null_patch.dart" + - "../../../../third_party/dart/runtime/lib/object_patch.dart" + - "../../../../third_party/dart/runtime/lib/regexp_patch.dart" + - "../../../../third_party/dart/runtime/lib/stacktrace.dart" + - "../../../../third_party/dart/runtime/lib/stopwatch_patch.dart" + - "../../../../third_party/dart/runtime/lib/string_buffer_patch.dart" + - "../../../../third_party/dart/runtime/lib/string_patch.dart" + - "../../../../third_party/dart/runtime/lib/type_patch.dart" + - "../../../../third_party/dart/runtime/lib/uri_patch.dart" + - "../../../../third_party/dart/runtime/lib/weak_property.dart" + + developer: + uri: "../../../../third_party/dart/sdk/lib/developer/developer.dart" + patches: + - "../../../../third_party/dart/runtime/lib/developer.dart" + - "../../../../third_party/dart/runtime/lib/profiler.dart" + - "../../../../third_party/dart/runtime/lib/timeline.dart" + + ffi: + uri: "../../../../third_party/dart/sdk/lib/ffi/ffi.dart" + patches: + - "../../../../third_party/dart/runtime/lib/ffi_dynamic_library_patch.dart" + - "../../../../third_party/dart/runtime/lib/ffi_native_type_patch.dart" + - "../../../../third_party/dart/runtime/lib/ffi_patch.dart" + + _http: + uri: "../../../../third_party/dart/sdk/lib/_http/http.dart" + + io: + uri: "../../../../third_party/dart/sdk/lib/io/io.dart" + patches: + - "../../../../third_party/dart/runtime/bin/common_patch.dart" + - "../../../../third_party/dart/runtime/bin/directory_patch.dart" + - "../../../../third_party/dart/runtime/bin/eventhandler_patch.dart" + - "../../../../third_party/dart/runtime/bin/file_patch.dart" + - "../../../../third_party/dart/runtime/bin/file_system_entity_patch.dart" + - "../../../../third_party/dart/runtime/bin/filter_patch.dart" + - "../../../../third_party/dart/runtime/bin/io_service_patch.dart" + - "../../../../third_party/dart/runtime/bin/namespace_patch.dart" + - "../../../../third_party/dart/runtime/bin/platform_patch.dart" + - "../../../../third_party/dart/runtime/bin/process_patch.dart" + - "../../../../third_party/dart/runtime/bin/socket_patch.dart" + - "../../../../third_party/dart/runtime/bin/stdio_patch.dart" + - "../../../../third_party/dart/runtime/bin/secure_socket_patch.dart" + - "../../../../third_party/dart/runtime/bin/sync_socket_patch.dart" + + isolate: + uri: "../../../../third_party/dart/sdk/lib/isolate/isolate.dart" + patches: + - "../../../../third_party/dart/runtime/lib/isolate_patch.dart" + - "../../../../third_party/dart/runtime/lib/timer_impl.dart" + + math: + uri: "../../../../third_party/dart/sdk/lib/math/math.dart" + patches: "../../../../third_party/dart/runtime/lib/math_patch.dart" + + mirrors: + uri: "../../../../third_party/dart/sdk/lib/mirrors/mirrors.dart" + patches: + - "../../../../third_party/dart/runtime/lib/mirrors_patch.dart" + - "../../../../third_party/dart/runtime/lib/mirrors_impl.dart" + - "../../../../third_party/dart/runtime/lib/mirror_reference.dart" + + nativewrappers: + uri: "../../../../third_party/dart/sdk/lib/html/dartium/nativewrappers.dart" + + profiler: + uri: "../../../../third_party/dart/sdk/lib/profiler/profiler.dart" + + typed_data: + uri: "../../../../third_party/dart/sdk/lib/typed_data/typed_data.dart" + patches: "../../../../third_party/dart/runtime/lib/typed_data_patch.dart" + + fuchsia.builtin: + uri: "../../../../topaz/runtime/dart_runner/embedder/builtin.dart" + + zircon: + uri: "../../../../topaz/public/dart-pkg/zircon/lib/zircon.dart" + + fuchsia: + uri: "../../../../topaz/public/dart-pkg/fuchsia/lib/fuchsia.dart" + + _vmservice: + uri: "../../../../third_party/dart/sdk/lib/vmservice/vmservice.dart" + + vmservice_io: + uri: "../../../../third_party/dart/runtime/bin/vmservice/vmservice_io.dart" diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/logging.h b/engine/src/flutter/shell/platform/fuchsia/dart/logging.h new file mode 100644 index 0000000000..e66806408b --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/logging.h @@ -0,0 +1,15 @@ +// 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. + +#ifndef TOPAZ_RUNTIME_DART_RUNNER_LOGGING_H_ +#define TOPAZ_RUNTIME_DART_RUNNER_LOGGING_H_ + +namespace dart_runner { + +// Use to mark logs published via the syslog API. +#define LOG_TAG "dart-runner" + +} // namespace dart_runner + +#endif // TOPAZ_RUNTIME_DART_RUNNER_LOGGING_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/main.cc b/engine/src/flutter/shell/platform/fuchsia/dart/main.cc new file mode 100644 index 0000000000..9c83274887 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/main.cc @@ -0,0 +1,69 @@ +// 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 + +#include "dart_runner.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" +#include "logging.h" +#include "runtime/dart/utils/files.h" +#include "runtime/dart/utils/tempfs.h" +#include "third_party/dart/runtime/include/dart_api.h" + +#if !defined(FUCHSIA_SDK) +#include +#include +#include +#endif // !defined(FUCHSIA_SDK) + +#if !defined(DART_PRODUCT) +// Register native symbol information for the Dart VM's profiler. +static void RegisterProfilerSymbols(const char* symbols_path, + const char* dso_name) { + std::string* symbols = new std::string(); + if (dart_utils::ReadFileToString(symbols_path, symbols)) { + Dart_AddSymbols(dso_name, symbols->data(), symbols->size()); + } else { + FML_LOG(ERROR) << "Failed to load " << symbols_path; + FML_CHECK(false); + } +} +#endif // !defined(DART_PRODUCT) + +int main(int argc, const char** argv) { + async::Loop loop(&kAsyncLoopConfigAttachToThread); + +#if !defined(FUCHSIA_SDK) + syslog::InitLogger(); + fbl::unique_ptr provider; + + { + TRACE_EVENT0("dart", "CreateTraceProvider"); + bool already_started; + // Use CreateSynchronously to prevent loss of early events. + trace::TraceProvider::CreateSynchronously(loop.dispatcher(), "dart_runner", + &provider, &already_started); + } +#endif // !defined(FUCHSIA_SDK) + +#if !defined(DART_PRODUCT) +#if defined(AOT_RUNTIME) + RegisterProfilerSymbols( + "pkg/data/libdart_precompiled_runtime.dartprofilersymbols", + "libdart_precompiled_runtime.so"); + RegisterProfilerSymbols("pkg/data/dart_aot_runner.dartprofilersymbols", ""); +#else + RegisterProfilerSymbols("pkg/data/libdart_jit.dartprofilersymbols", + "libdart_jit.so"); + RegisterProfilerSymbols("pkg/data/dart_jit_runner.dartprofilersymbols", ""); +#endif // defined(AOT_RUNTIME) +#endif // !defined(DART_PRODUCT) + + dart_utils::SetupRunnerTemp(); + + dart_runner::DartRunner runner; + loop.Run(); + return 0; +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/mapped_resource.cc b/engine/src/flutter/shell/platform/fuchsia/dart/mapped_resource.cc new file mode 100644 index 0000000000..6b9ba3ed21 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/mapped_resource.cc @@ -0,0 +1,105 @@ +// 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 "mapped_resource.h" + +#include +#include +#include +#include + +#if !defined(FUCHSIA_SDK) +#include +#endif // !defined(FUCHSIA_SDK) + +#include "flutter/fml/logging.h" +#include "logging.h" +#include "runtime/dart/utils/inlines.h" +#include "runtime/dart/utils/vmo.h" + +namespace dart_runner { + +bool MappedResource::LoadFromNamespace(fdio_ns_t* namespc, + const std::string& path, + MappedResource& resource, + bool executable) { +#if !defined(FUCHSIA_SDK) + TRACE_DURATION("dart", "LoadFromNamespace", "path", path); +#endif // !defined(FUCHSIA_SDK) + + // openat of a path with a leading '/' ignores the namespace fd. + dart_utils::Check(path[0] != '/', LOG_TAG); + + fuchsia::mem::Buffer resource_vmo; + if (namespc == nullptr) { + if (!dart_utils::VmoFromFilename(path, &resource_vmo)) { + return false; + } + } else { + auto root_dir = fdio_ns_opendir(namespc); + if (root_dir < 0) { + FML_LOG(ERROR) << "Failed to open namespace directory"; + return false; + } + + bool result = dart_utils::VmoFromFilenameAt(root_dir, path, &resource_vmo); + close(root_dir); + if (!result) { + return result; + } + } + + if (executable) { + // VmoFromFilenameAt will return VMOs without ZX_RIGHT_EXECUTE, + // so we need replace_as_executable to be able to map them as + // ZX_VM_PERM_EXECUTE. + // TODO(mdempsky): Update comment once SEC-42 is fixed. + zx_status_t status = + resource_vmo.vmo.replace_as_executable(zx::handle(), &resource_vmo.vmo); + if (status != ZX_OK) { + FML_LOG(ERROR) << "Failed to make VMO executable: " + << zx_status_get_string(status); + return false; + } + } + + return LoadFromVmo(path, std::move(resource_vmo), resource, executable); +} + +bool MappedResource::LoadFromVmo(const std::string& path, + fuchsia::mem::Buffer resource_vmo, + MappedResource& resource, + bool executable) { + if (resource_vmo.size == 0) { + return true; + } + + uint32_t flags = ZX_VM_PERM_READ; + if (executable) { + flags |= ZX_VM_PERM_EXECUTE; + } + uintptr_t addr; + zx_status_t status = zx::vmar::root_self()->map( + 0, resource_vmo.vmo, 0, resource_vmo.size, flags, &addr); + if (status != ZX_OK) { + FML_LOG(ERROR) << "Failed to map " << path << ": " + << zx_status_get_string(status); + + return false; + } + + resource.address_ = reinterpret_cast(addr); + resource.size_ = resource_vmo.size; + return true; +} + +MappedResource::~MappedResource() { + if (address_ != nullptr) { + zx::vmar::root_self()->unmap(reinterpret_cast(address_), size_); + address_ = nullptr; + size_ = 0; + } +} + +} // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/mapped_resource.h b/engine/src/flutter/shell/platform/fuchsia/dart/mapped_resource.h new file mode 100644 index 0000000000..fb2d1b74c0 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/mapped_resource.h @@ -0,0 +1,64 @@ +// 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. + +#ifndef APPS_DART_RUNNER_MAPPED_RESOURCE_H_ +#define APPS_DART_RUNNER_MAPPED_RESOURCE_H_ + +#include +#include + +namespace dart_runner { + +class MappedResource { + public: + MappedResource() : address_(nullptr), size_(0) {} + MappedResource(MappedResource&& other) + : address_(other.address_), size_(other.size_) { + other.address_ = nullptr; + other.size_ = 0; + } + MappedResource& operator=(MappedResource&& other) { + address_ = other.address_; + size_ = other.size_; + other.address_ = nullptr; + other.size_ = 0; + return *this; + } + ~MappedResource(); + + // Loads the content of a file from the given namespace and maps it into the + // current process's address space. If namespace is null, the fdio "global" + // namespace is used (in which case, ./pkg means the dart_runner's package). + // The content is unmapped when the MappedResource goes out of scope. Returns + // true on success. + static bool LoadFromNamespace(fdio_ns_t* namespc, + const std::string& path, + MappedResource& resource, + bool executable = false); + + // Maps a VMO into the current process's address space. The content is + // unmapped when the MappedResource goes out of scope. Returns true on + // success. The path is used only for error messages. + static bool LoadFromVmo(const std::string& path, + fuchsia::mem::Buffer resource_vmo, + MappedResource& resource, + bool executable = false); + + const uint8_t* address() const { + return reinterpret_cast(address_); + } + size_t size() const { return size_; } + + private: + void* address_; + size_t size_; + + // Disallow copy and assignment. + MappedResource(const MappedResource&) = delete; + MappedResource& operator=(const MappedResource&) = delete; +}; + +} // namespace dart_runner + +#endif // APPS_DART_RUNNER_MAPPED_RESOURCE_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/aot_product_runtime b/engine/src/flutter/shell/platform/fuchsia/dart/meta/aot_product_runtime new file mode 100644 index 0000000000..f824f5f8ac --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/aot_product_runtime @@ -0,0 +1,3 @@ +{ + "runner": "fuchsia-pkg://fuchsia.com/dart_aot_product_runner#meta/dart_aot_product_runner.cmx" +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/aot_runtime b/engine/src/flutter/shell/platform/fuchsia/dart/meta/aot_runtime new file mode 100644 index 0000000000..54f404a59f --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/aot_runtime @@ -0,0 +1,3 @@ +{ + "runner": "fuchsia-pkg://fuchsia.com/dart_aot_runner#meta/dart_aot_runner.cmx" +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_aot_product_runner.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_aot_product_runner.cmx new file mode 100644 index 0000000000..aa5a3e1775 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_aot_product_runner.cmx @@ -0,0 +1,17 @@ +{ + "program": { + "data": "data" + }, + "sandbox": { + "features": [ + "root-ssl-certificates" + ], + "services": [ + "fuchsia.crash.Analyzer", + "fuchsia.logger.LogSink", + "fuchsia.net.SocketProvider", + "fuchsia.timezone.Timezone", + "fuchsia.tracelink.Registry" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_aot_runner.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_aot_runner.cmx new file mode 100644 index 0000000000..aa5a3e1775 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_aot_runner.cmx @@ -0,0 +1,17 @@ +{ + "program": { + "data": "data" + }, + "sandbox": { + "features": [ + "root-ssl-certificates" + ], + "services": [ + "fuchsia.crash.Analyzer", + "fuchsia.logger.LogSink", + "fuchsia.net.SocketProvider", + "fuchsia.timezone.Timezone", + "fuchsia.tracelink.Registry" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_jit_product_runner.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_jit_product_runner.cmx new file mode 100644 index 0000000000..e28f9a97fc --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_jit_product_runner.cmx @@ -0,0 +1,19 @@ +{ + "program": { + "data": "data" + }, + "sandbox": { + "features": [ + "root-ssl-certificates" + ], + "services": [ + "fuchsia.crash.Analyzer", + "fuchsia.logger.LogSink", + "fuchsia.net.SocketProvider", + "fuchsia.process.Launcher", + "fuchsia.process.Resolver", + "fuchsia.timezone.Timezone", + "fuchsia.tracelink.Registry" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_jit_runner.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_jit_runner.cmx new file mode 100644 index 0000000000..e28f9a97fc --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_jit_runner.cmx @@ -0,0 +1,19 @@ +{ + "program": { + "data": "data" + }, + "sandbox": { + "features": [ + "root-ssl-certificates" + ], + "services": [ + "fuchsia.crash.Analyzer", + "fuchsia.logger.LogSink", + "fuchsia.net.SocketProvider", + "fuchsia.process.Launcher", + "fuchsia.process.Resolver", + "fuchsia.timezone.Timezone", + "fuchsia.tracelink.Registry" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_zircon_test.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_zircon_test.cmx new file mode 100644 index 0000000000..531309ed42 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/dart_zircon_test.cmx @@ -0,0 +1,13 @@ +{ + "program": { + "data": "data/dart_zircon_test" + }, + "sandbox": { + "features": [ + "root-ssl-certificates" + ], + "services": [ + "fuchsia.sys.Environment" + ] + } +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/jit_product_runtime b/engine/src/flutter/shell/platform/fuchsia/dart/meta/jit_product_runtime new file mode 100644 index 0000000000..59a1a6f5b7 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/jit_product_runtime @@ -0,0 +1,3 @@ +{ + "runner": "fuchsia-pkg://fuchsia.com/dart_jit_product_runner#meta/dart_jit_product_runner.cmx" +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/meta/jit_runtime b/engine/src/flutter/shell/platform/fuchsia/dart/meta/jit_runtime new file mode 100644 index 0000000000..894f821feb --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/meta/jit_runtime @@ -0,0 +1,3 @@ +{ + "runner": "fuchsia-pkg://fuchsia.com/dart_jit_runner#meta/dart_jit_runner.cmx" +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/service_isolate.cc b/engine/src/flutter/shell/platform/fuchsia/dart/service_isolate.cc new file mode 100644 index 0000000000..942c32c90e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/service_isolate.cc @@ -0,0 +1,213 @@ +// 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/uint8_list.h" + +#include "builtin_libraries.h" +#include "dart_component_controller.h" +#include "logging.h" + +namespace dart_runner { +namespace { + +MappedResource mapped_isolate_snapshot_data; +MappedResource mapped_isolate_snapshot_instructions; +MappedResource mapped_shared_snapshot_data; +MappedResource mapped_shared_snapshot_instructions; +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); + +#if defined(AOT_RUNTIME) + // 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 (!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 (!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; + } + +#if defined(AOT_RUNTIME) + if (!MappedResource::LoadFromNamespace( + nullptr, "pkg/data/vmservice_shared_snapshot_data.bin", + mapped_shared_snapshot_data)) { + *error = strdup("Failed to load snapshot for service isolate"); + FX_LOG(ERROR, LOG_TAG, *error); + return nullptr; + } + if (!MappedResource::LoadFromNamespace( + nullptr, "pkg/data/vmservice_shared_snapshot_instructions.bin", + mapped_shared_snapshot_instructions, true /* executable */)) { + *error = strdup("Failed to load snapshot for service isolate"); + FX_LOG(ERROR, LOG_TAG, *error); + return nullptr; + } +#endif + + auto state = new std::shared_ptr(new tonic::DartState()); + Dart_Isolate isolate = Dart_CreateIsolate( + uri, DART_VM_SERVICE_ISOLATE_NAME, mapped_isolate_snapshot_data.address(), + mapped_isolate_snapshot_instructions.address(), + mapped_shared_snapshot_data.address(), + mapped_shared_snapshot_instructions.address(), nullptr /* flags */, state, + error); + if (!isolate) { + FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolate 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() { + MappedResource observatory_tar; + if (!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::ToDart( + reinterpret_cast(observatory_tar.address()), + observatory_tar.size()); +} + +} // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/service_isolate.h b/engine/src/flutter/shell/platform/fuchsia/dart/service_isolate.h new file mode 100644 index 0000000000..1a589fd227 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/service_isolate.h @@ -0,0 +1,20 @@ +// 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. + +#ifndef APPS_DART_RUNNER_SERVICE_ISOLATE_H_ +#define APPS_DART_RUNNER_SERVICE_ISOLATE_H_ + +#include "third_party/dart/runtime/include/dart_api.h" + +namespace dart_runner { + +Dart_Isolate CreateServiceIsolate(const char* uri, + Dart_IsolateFlags* flags, + char** error); + +Dart_Handle GetVMServiceAssetsArchiveCallback(); + +} // namespace dart_runner + +#endif // APPS_DART_RUNNER_SERVICE_ISOLATE_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/BUILD.gn new file mode 100644 index 0000000000..19ef29cfd4 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/BUILD.gn @@ -0,0 +1,23 @@ +# 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. + +import("//topaz/runtime/dart_runner/dart_app.gni") + +dart_aot_app("vmservice") { + main_dart = "empty.dart" + + meta = [ + { + path = rebase_path("meta/vmservice.cmx") + dest = "vmservice.cmx" + }, + ] + + source_dir = "." + + product = false + + sources = [] + deps = [] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/analysis_options.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/analysis_options.yaml new file mode 100644 index 0000000000..704eb990c3 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/analysis_options.yaml @@ -0,0 +1,5 @@ +# 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: ../../../tools/analysis_options.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/empty.dart b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/empty.dart new file mode 100644 index 0000000000..0d7f6a4b8b --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/empty.dart @@ -0,0 +1,7 @@ +// 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. + +// This entry point is never invoked. Its purpose is to allow the vmservice's +// Dart code to built with dart_aot_app. +void main(List args) {} diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/meta/vmservice.cmx b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/meta/vmservice.cmx new file mode 100644 index 0000000000..d5b1215cc0 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/meta/vmservice.cmx @@ -0,0 +1,21 @@ +{ + "program": { + "data": "data/vmservice" + }, + "sandbox": { + "services": [ + "fuchsia.cobalt.LoggerFactory", + "fuchsia.fonts.Provider", + "fuchsia.logger.LogSink", + "fuchsia.modular.Clipboard", + "fuchsia.modular.ContextWriter", + "fuchsia.modular.ModuleContext", + "fuchsia.netstack.Netstack", + "fuchsia.sys.Environment", + "fuchsia.ui.input.ImeService", + "fuchsia.ui.policy.Presenter", + "fuchsia.ui.scenic.Scenic", + "fuchsia.wlan.service.Wlan" + ] + } +} \ No newline at end of file diff --git a/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/pubspec.yaml new file mode 100644 index 0000000000..5e8ae01a4e --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/dart/vmservice/pubspec.yaml @@ -0,0 +1,3 @@ +# 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. diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/logging.h b/engine/src/flutter/shell/platform/fuchsia/flutter/logging.h index 8a6cefb861..3eea76a034 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/logging.h +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/logging.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_LOGGING_H_ #define FLUTTER_SHELL_PLATFORM_FUCHSIA_LOGGING_H_ +#include "flutter/fml/logging.h" + namespace flutter_runner { // Use to mark logs published via the syslog API.