| // 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 <lib/fdio/namespace.h> |
| #include <lib/zx/channel.h> |
| |
| #include <optional> |
| |
| #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<const uint8_t*>(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::CheckAndHandleError(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<fuchsia::sys::Environment> environment, |
| zx::channel directory_request, |
| bool service_isolate) { |
| // dart:fuchsia -------------------------------------------------------------- |
| // dart runner doesn't care about scenic view ref. |
| if (!service_isolate) { |
| fuchsia::dart::Initialize(std::move(environment), |
| std::move(directory_request), std::nullopt); |
| } |
| |
| // dart:fuchsia.builtin ------------------------------------------------------ |
| |
| Dart_Handle builtin_lib = Dart_LookupLibrary(ToDart("dart:fuchsia.builtin")); |
| FML_CHECK(!tonic::CheckAndHandleError(builtin_lib)); |
| Dart_Handle result = Dart_SetNativeResolver(builtin_lib, BuiltinNativeLookup, |
| BuiltinNativeSymbol); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| |
| // dart:io ------------------------------------------------------------------- |
| |
| Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io")); |
| FML_CHECK(!tonic::CheckAndHandleError(io_lib)); |
| result = Dart_SetNativeResolver(io_lib, dart::bin::IONativeLookup, |
| dart::bin::IONativeSymbol); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| |
| // dart:zircon --------------------------------------------------------------- |
| |
| Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon")); |
| FML_CHECK(!tonic::CheckAndHandleError(zircon_lib)); |
| // NativeResolver already set by fuchsia::dart::Initialize(). |
| |
| // Core libraries ------------------------------------------------------------ |
| |
| Dart_Handle async_lib = Dart_LookupLibrary(ToDart("dart:async")); |
| FML_CHECK(!tonic::CheckAndHandleError(async_lib)); |
| |
| Dart_Handle core_lib = Dart_LookupLibrary(ToDart("dart:core")); |
| FML_CHECK(!tonic::CheckAndHandleError(core_lib)); |
| |
| Dart_Handle internal_lib = Dart_LookupLibrary(ToDart("dart:_internal")); |
| FML_CHECK(!tonic::CheckAndHandleError(internal_lib)); |
| |
| Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); |
| FML_CHECK(!tonic::CheckAndHandleError(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 set up closures. |
| result = Dart_FinalizeLoading(false); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| #endif |
| |
| // Setup the internal library's 'internalPrint' function. |
| Dart_Handle print = |
| Dart_Invoke(builtin_lib, ToDart("_getPrintClosure"), 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(print)); |
| |
| result = Dart_SetField(internal_lib, ToDart("_printClosure"), print); |
| FML_CHECK(!tonic::CheckAndHandleError(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::CheckAndHandleError(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::CheckAndHandleError(result)); |
| |
| // Set up the namespace in dart:io. |
| Dart_Handle namespace_type = |
| Dart_GetNonNullableType(io_lib, ToDart("_Namespace"), 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(namespace_type)); |
| |
| Dart_Handle namespace_args[1]; |
| namespace_args[0] = ToDart(reinterpret_cast<intptr_t>(namespc)); |
| result = |
| Dart_Invoke(namespace_type, ToDart("_setupNamespace"), 1, namespace_args); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| |
| // Set up the namespace in dart:zircon. |
| namespace_type = |
| Dart_GetNonNullableType(zircon_lib, ToDart("_Namespace"), 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(namespace_type)); |
| |
| result = Dart_SetField(namespace_type, ToDart("_namespace"), |
| ToDart(reinterpret_cast<intptr_t>(namespc))); |
| FML_CHECK(!tonic::CheckAndHandleError(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::CheckAndHandleError(result)); |
| |
| // Disable some dart:io operations. |
| Dart_Handle embedder_config_type = |
| Dart_GetNonNullableType(io_lib, ToDart("_EmbedderConfig"), 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(embedder_config_type)); |
| |
| result = |
| Dart_SetField(embedder_config_type, ToDart("_mayExit"), Dart_False()); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| |
| // Set the script location. |
| result = Dart_SetField(builtin_lib, ToDart("_rawScript"), ToDart(script_uri)); |
| FML_CHECK(!tonic::CheckAndHandleError(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::CheckAndHandleError(uri_base)); |
| |
| result = Dart_SetField(core_lib, ToDart("_uriBaseClosure"), uri_base); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| |
| Dart_Handle setup_hooks = ToDart("_setupHooks"); |
| result = Dart_Invoke(builtin_lib, setup_hooks, 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| result = Dart_Invoke(io_lib, setup_hooks, 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| result = Dart_Invoke(isolate_lib, setup_hooks, 0, nullptr); |
| FML_CHECK(!tonic::CheckAndHandleError(result)); |
| } |
| |
| } // namespace dart_runner |