1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "builtin_libraries.h"
6
7 #include <lib/fdio/namespace.h>
8 #include <lib/zx/channel.h>
9
10 #include "dart-pkg/fuchsia/sdk_ext/fuchsia.h"
11 #include "flutter/fml/logging.h"
12 #include "runtime/dart/utils/inlines.h"
13 #include "third_party/dart/runtime/bin/io_natives.h"
14 #include "third_party/dart/runtime/include/dart_api.h"
15 #include "third_party/tonic/converter/dart_converter.h"
16 #include "third_party/tonic/dart_microtask_queue.h"
17 #include "third_party/tonic/logging/dart_error.h"
18
19 #include "logging.h"
20
21 using tonic::ToDart;
22
23 namespace dart_runner {
24 namespace {
25
26 #define REGISTER_FUNCTION(name, count) {#name, name, count},
27 #define DECLARE_FUNCTION(name, count) \
28 extern void name(Dart_NativeArguments args);
29
30 #define BUILTIN_NATIVE_LIST(V) \
31 V(Logger_PrintString, 1) \
32 V(ScheduleMicrotask, 1)
33
34 BUILTIN_NATIVE_LIST(DECLARE_FUNCTION);
35
36 const struct NativeEntry {
37 const char* name;
38 Dart_NativeFunction function;
39 int argument_count;
40 } kBuiltinEntries[] = {BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)};
41
BuiltinNativeLookup(Dart_Handle name,int argument_count,bool * auto_setup_scope)42 Dart_NativeFunction BuiltinNativeLookup(Dart_Handle name,
43 int argument_count,
44 bool* auto_setup_scope) {
45 const char* function_name = nullptr;
46 Dart_Handle result = Dart_StringToCString(name, &function_name);
47 if (Dart_IsError(result)) {
48 Dart_PropagateError(result);
49 }
50 FML_DCHECK(function_name != nullptr);
51 FML_DCHECK(auto_setup_scope != nullptr);
52 *auto_setup_scope = true;
53 size_t num_entries = dart_utils::ArraySize(kBuiltinEntries);
54 for (size_t i = 0; i < num_entries; i++) {
55 const NativeEntry& entry = kBuiltinEntries[i];
56 if (!strcmp(function_name, entry.name) &&
57 (entry.argument_count == argument_count)) {
58 return entry.function;
59 }
60 }
61 return nullptr;
62 }
63
BuiltinNativeSymbol(Dart_NativeFunction native_function)64 const uint8_t* BuiltinNativeSymbol(Dart_NativeFunction native_function) {
65 size_t num_entries = dart_utils::ArraySize(kBuiltinEntries);
66 for (size_t i = 0; i < num_entries; i++) {
67 const NativeEntry& entry = kBuiltinEntries[i];
68 if (entry.function == native_function)
69 return reinterpret_cast<const uint8_t*>(entry.name);
70 }
71 return nullptr;
72 }
73
Logger_PrintString(Dart_NativeArguments args)74 void Logger_PrintString(Dart_NativeArguments args) {
75 intptr_t length = 0;
76 uint8_t* chars = nullptr;
77 Dart_Handle str = Dart_GetNativeArgument(args, 0);
78 Dart_Handle result = Dart_StringToUTF8(str, &chars, &length);
79 if (Dart_IsError(result)) {
80 Dart_PropagateError(result);
81 } else {
82 fwrite(chars, 1, length, stdout);
83 fputc('\n', stdout);
84 fflush(stdout);
85 }
86 }
87
ScheduleMicrotask(Dart_NativeArguments args)88 void ScheduleMicrotask(Dart_NativeArguments args) {
89 Dart_Handle closure = Dart_GetNativeArgument(args, 0);
90 if (tonic::LogIfError(closure) || !Dart_IsClosure(closure))
91 return;
92 tonic::DartMicrotaskQueue::GetForCurrentThread()->ScheduleMicrotask(closure);
93 }
94
95 } // namespace
96
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)97 void InitBuiltinLibrariesForIsolate(
98 const std::string& script_uri,
99 fdio_ns_t* namespc,
100 int stdoutfd,
101 int stderrfd,
102 fidl::InterfaceHandle<fuchsia::sys::Environment> environment,
103 zx::channel directory_request,
104 bool service_isolate) {
105 // dart:fuchsia --------------------------------------------------------------
106 if (!service_isolate) {
107 fuchsia::dart::Initialize(std::move(environment),
108 std::move(directory_request));
109 }
110
111 // dart:fuchsia.builtin ------------------------------------------------------
112
113 Dart_Handle builtin_lib = Dart_LookupLibrary(ToDart("dart:fuchsia.builtin"));
114 FML_CHECK(!tonic::LogIfError(builtin_lib));
115 Dart_Handle result = Dart_SetNativeResolver(builtin_lib, BuiltinNativeLookup,
116 BuiltinNativeSymbol);
117 FML_CHECK(!tonic::LogIfError(result));
118
119 // dart:io -------------------------------------------------------------------
120
121 Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
122 FML_CHECK(!tonic::LogIfError(io_lib));
123 result = Dart_SetNativeResolver(io_lib, dart::bin::IONativeLookup,
124 dart::bin::IONativeSymbol);
125 FML_CHECK(!tonic::LogIfError(result));
126
127 // dart:zircon ---------------------------------------------------------------
128
129 Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon"));
130 FML_CHECK(!tonic::LogIfError(zircon_lib));
131 // NativeResolver already set by fuchsia::dart::Initialize().
132
133 // Core libraries ------------------------------------------------------------
134
135 Dart_Handle async_lib = Dart_LookupLibrary(ToDart("dart:async"));
136 FML_CHECK(!tonic::LogIfError(async_lib));
137
138 Dart_Handle core_lib = Dart_LookupLibrary(ToDart("dart:core"));
139 FML_CHECK(!tonic::LogIfError(core_lib));
140
141 Dart_Handle internal_lib = Dart_LookupLibrary(ToDart("dart:_internal"));
142 FML_CHECK(!tonic::LogIfError(internal_lib));
143
144 Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
145 FML_CHECK(!tonic::LogIfError(isolate_lib));
146
147 #if !defined(AOT_RUNTIME)
148 // AOT: These steps already happened at compile time in gen_snapshot.
149
150 // We need to ensure that all the scripts loaded so far are finalized
151 // as we are about to invoke some Dart code below to setup closures.
152 result = Dart_FinalizeLoading(false);
153 FML_CHECK(!tonic::LogIfError(result));
154 #endif
155
156 // Setup the internal library's 'internalPrint' function.
157 Dart_Handle print =
158 Dart_Invoke(builtin_lib, ToDart("_getPrintClosure"), 0, nullptr);
159 FML_CHECK(!tonic::LogIfError(print));
160
161 result = Dart_SetField(internal_lib, ToDart("_printClosure"), print);
162 FML_CHECK(!tonic::LogIfError(result));
163
164 // Set up the 'scheduleImmediate' closure.
165 Dart_Handle schedule_immediate_closure;
166 if (service_isolate) {
167 // Running on dart::ThreadPool.
168 schedule_immediate_closure = Dart_Invoke(
169 isolate_lib, ToDart("_getIsolateScheduleImmediateClosure"), 0, nullptr);
170 } else {
171 // Running on async::Loop.
172 schedule_immediate_closure = Dart_Invoke(
173 builtin_lib, ToDart("_getScheduleMicrotaskClosure"), 0, nullptr);
174 }
175 FML_CHECK(!tonic::LogIfError(schedule_immediate_closure));
176
177 Dart_Handle schedule_args[1];
178 schedule_args[0] = schedule_immediate_closure;
179 result = Dart_Invoke(async_lib, ToDart("_setScheduleImmediateClosure"), 1,
180 schedule_args);
181 FML_CHECK(!tonic::LogIfError(result));
182
183 // Set up the namespace in dart:io.
184 Dart_Handle namespace_type =
185 Dart_GetType(io_lib, ToDart("_Namespace"), 0, nullptr);
186 FML_CHECK(!tonic::LogIfError(namespace_type));
187
188 Dart_Handle namespace_args[1];
189 namespace_args[0] = ToDart(reinterpret_cast<intptr_t>(namespc));
190 result =
191 Dart_Invoke(namespace_type, ToDart("_setupNamespace"), 1, namespace_args);
192 FML_CHECK(!tonic::LogIfError(result));
193
194 // Set up the namespace in dart:zircon.
195 namespace_type = Dart_GetType(zircon_lib, ToDart("_Namespace"), 0, nullptr);
196 FML_CHECK(!tonic::LogIfError(namespace_type));
197
198 result = Dart_SetField(namespace_type, ToDart("_namespace"),
199 ToDart(reinterpret_cast<intptr_t>(namespc)));
200 FML_CHECK(!tonic::LogIfError(result));
201
202 // Set up stdout and stderr.
203 Dart_Handle stdio_args[3];
204 stdio_args[0] = Dart_NewInteger(0);
205 stdio_args[1] = Dart_NewInteger(stdoutfd);
206 stdio_args[2] = Dart_NewInteger(stderrfd);
207 result = Dart_Invoke(io_lib, ToDart("_setStdioFDs"), 3, stdio_args);
208 FML_CHECK(!tonic::LogIfError(result));
209
210 // Disable some dart:io operations.
211 Dart_Handle embedder_config_type =
212 Dart_GetType(io_lib, ToDart("_EmbedderConfig"), 0, nullptr);
213 FML_CHECK(!tonic::LogIfError(embedder_config_type));
214
215 result =
216 Dart_SetField(embedder_config_type, ToDart("_mayExit"), Dart_False());
217 FML_CHECK(!tonic::LogIfError(result));
218
219 // Set the script location.
220 result = Dart_SetField(builtin_lib, ToDart("_rawScript"), ToDart(script_uri));
221 FML_CHECK(!tonic::LogIfError(result));
222
223 // Setup the uriBase with the base uri of the fidl app.
224 Dart_Handle uri_base =
225 Dart_Invoke(io_lib, ToDart("_getUriBaseClosure"), 0, nullptr);
226 FML_CHECK(!tonic::LogIfError(uri_base));
227
228 result = Dart_SetField(core_lib, ToDart("_uriBaseClosure"), uri_base);
229 FML_CHECK(!tonic::LogIfError(result));
230
231 Dart_Handle setup_hooks = ToDart("_setupHooks");
232 result = Dart_Invoke(builtin_lib, setup_hooks, 0, nullptr);
233 FML_CHECK(!tonic::LogIfError(result));
234 result = Dart_Invoke(io_lib, setup_hooks, 0, nullptr);
235 FML_CHECK(!tonic::LogIfError(result));
236 result = Dart_Invoke(isolate_lib, setup_hooks, 0, nullptr);
237 FML_CHECK(!tonic::LogIfError(result));
238 }
239
240 } // namespace dart_runner
241