Flutter Engine
dart_runtime_hooks.cc
Go to the documentation of this file.
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 "flutter/lib/ui/dart_runtime_hooks.h"
6 
7 #include <cstdio>
8 #include <cstdlib>
9 #include <cstring>
10 #include <iostream>
11 #include <sstream>
12 
13 #include "flutter/common/settings.h"
14 #include "flutter/fml/build_config.h"
15 #include "flutter/fml/logging.h"
16 #include "flutter/lib/ui/plugins/callback_cache.h"
17 #include "flutter/lib/ui/ui_dart_state.h"
18 #include "third_party/dart/runtime/include/bin/dart_io_api.h"
19 #include "third_party/dart/runtime/include/dart_api.h"
20 #include "third_party/dart/runtime/include/dart_tools_api.h"
29 
31 using tonic::LogIfError;
32 using tonic::ToDart;
33 
34 namespace flutter {
35 
36 #define REGISTER_FUNCTION(name, count) {"" #name, name, count, true},
37 #define DECLARE_FUNCTION(name, count) \
38  extern void name(Dart_NativeArguments args);
39 
40 #define BUILTIN_NATIVE_LIST(V) \
41  V(Logger_PrintString, 1) \
42  V(Logger_PrintDebugString, 1) \
43  V(ScheduleMicrotask, 1) \
44  V(GetCallbackHandle, 1) \
45  V(GetCallbackFromHandle, 1)
46 
48 
51 }
52 
53 static void PropagateIfError(Dart_Handle result) {
54  if (Dart_IsError(result)) {
55  FML_LOG(ERROR) << "Dart Error: " << ::Dart_GetError(result);
56  Dart_PropagateError(result);
57  }
58 }
59 
60 static Dart_Handle InvokeFunction(Dart_Handle builtin_library,
61  const char* name) {
62  Dart_Handle getter_name = ToDart(name);
63  return Dart_Invoke(builtin_library, getter_name, 0, nullptr);
64 }
65 
66 static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate) {
67  Dart_Handle print = InvokeFunction(builtin_library, "_getPrintClosure");
68 
69  Dart_Handle internal_library = Dart_LookupLibrary(ToDart("dart:_internal"));
70 
71  Dart_Handle result =
72  Dart_SetField(internal_library, ToDart("_printClosure"), print);
73  PropagateIfError(result);
74 
75  if (is_ui_isolate) {
76  // Call |_setupHooks| to configure |VMLibraryHooks|.
77  Dart_Handle method_name = Dart_NewStringFromCString("_setupHooks");
78  result = Dart_Invoke(builtin_library, method_name, 0, NULL);
79  PropagateIfError(result);
80  }
81 
82  Dart_Handle setup_hooks = Dart_NewStringFromCString("_setupHooks");
83 
84  Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
85  result = Dart_Invoke(io_lib, setup_hooks, 0, NULL);
86  PropagateIfError(result);
87 
88  Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
89  result = Dart_Invoke(isolate_lib, setup_hooks, 0, NULL);
90  PropagateIfError(result);
91 }
92 
93 static void InitDartCore(Dart_Handle builtin, const std::string& script_uri) {
94  Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
95  Dart_Handle get_base_url =
96  Dart_Invoke(io_lib, ToDart("_getUriBaseClosure"), 0, NULL);
97  Dart_Handle core_library = Dart_LookupLibrary(ToDart("dart:core"));
98  Dart_Handle result =
99  Dart_SetField(core_library, ToDart("_uriBaseClosure"), get_base_url);
100  PropagateIfError(result);
101 }
102 
103 static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) {
104  Dart_Handle schedule_microtask;
105  if (is_ui_isolate) {
106  schedule_microtask =
107  InvokeFunction(builtin_library, "_getScheduleMicrotaskClosure");
108  } else {
109  Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
110  Dart_Handle method_name =
111  Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure");
112  schedule_microtask = Dart_Invoke(isolate_lib, method_name, 0, NULL);
113  }
114  Dart_Handle async_library = Dart_LookupLibrary(ToDart("dart:async"));
115  Dart_Handle set_schedule_microtask = ToDart("_setScheduleImmediateClosure");
116  Dart_Handle result = Dart_Invoke(async_library, set_schedule_microtask, 1,
117  &schedule_microtask);
118  PropagateIfError(result);
119 }
120 
121 static void InitDartIO(Dart_Handle builtin_library,
122  const std::string& script_uri) {
123  Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
124  Dart_Handle platform_type =
125  Dart_GetNonNullableType(io_lib, ToDart("_Platform"), 0, nullptr);
126  if (!script_uri.empty()) {
127  Dart_Handle result = Dart_SetField(platform_type, ToDart("_nativeScript"),
128  ToDart(script_uri));
129  PropagateIfError(result);
130  }
131  // typedef _LocaleClosure = String Function();
132  Dart_Handle /* _LocaleClosure? */ locale_closure =
133  InvokeFunction(builtin_library, "_getLocaleClosure");
134  PropagateIfError(locale_closure);
135  // static String Function()? _localeClosure;
136  Dart_Handle result =
137  Dart_SetField(platform_type, ToDart("_localeClosure"), locale_closure);
138  PropagateIfError(result);
139 
140  // Register dart:io service extensions used for network profiling.
141  Dart_Handle network_profiling_type =
142  Dart_GetNonNullableType(io_lib, ToDart("_NetworkProfiling"), 0, nullptr);
143  PropagateIfError(network_profiling_type);
144  result = Dart_Invoke(network_profiling_type,
145  ToDart("_registerServiceExtension"), 0, nullptr);
146  PropagateIfError(result);
147 }
148 
149 void DartRuntimeHooks::Install(bool is_ui_isolate,
150  const std::string& script_uri) {
151  Dart_Handle builtin = Dart_LookupLibrary(ToDart("dart:ui"));
152  InitDartInternal(builtin, is_ui_isolate);
153  InitDartCore(builtin, script_uri);
154  InitDartAsync(builtin, is_ui_isolate);
155  InitDartIO(builtin, script_uri);
156 }
157 
158 void Logger_PrintDebugString(Dart_NativeArguments args) {
159 #ifndef NDEBUG
160  Logger_PrintString(args);
161 #endif
162 }
163 
164 // Implementation of native functions which are used for some
165 // test/debug functionality in standalone dart mode.
166 void Logger_PrintString(Dart_NativeArguments args) {
167  // Obtain the log buffer from Dart code.
168  std::string message;
169  {
170  Dart_Handle str = Dart_GetNativeArgument(args, 0);
171  uint8_t* chars = nullptr;
172  intptr_t length = 0;
173  Dart_Handle result = Dart_StringToUTF8(str, &chars, &length);
174  if (Dart_IsError(result)) {
175  Dart_PropagateError(result);
176  return;
177  }
178  if (length > 0) {
179  message = std::string{reinterpret_cast<const char*>(chars),
180  static_cast<size_t>(length)};
181  }
182  }
183 
184  const auto& tag = UIDartState::Current()->logger_prefix();
185  UIDartState::Current()->LogMessage(tag, message);
186 
187  if (dart::bin::ShouldCaptureStdout()) {
188  std::stringstream stream;
189  if (tag.size() > 0) {
190  stream << tag << ": ";
191  }
192  stream << message;
193  std::string log = stream.str();
194 
195  // For now we report print output on the Stdout stream.
196  uint8_t newline[] = {'\n'};
197  Dart_ServiceSendDataEvent("Stdout", "WriteEvent",
198  reinterpret_cast<const uint8_t*>(log.c_str()),
199  log.size());
200  Dart_ServiceSendDataEvent("Stdout", "WriteEvent", newline, sizeof(newline));
201  }
202 }
203 
204 void ScheduleMicrotask(Dart_NativeArguments args) {
205  Dart_Handle closure = Dart_GetNativeArgument(args, 0);
207 }
208 
209 static std::string GetFunctionLibraryUrl(Dart_Handle closure) {
210  if (Dart_IsClosure(closure)) {
211  closure = Dart_ClosureFunction(closure);
212  PropagateIfError(closure);
213  }
214 
215  if (!Dart_IsFunction(closure)) {
216  return "";
217  }
218 
219  Dart_Handle url = Dart_Null();
220  Dart_Handle owner = Dart_FunctionOwner(closure);
221  if (Dart_IsInstance(owner)) {
222  owner = Dart_ClassLibrary(owner);
223  }
224  if (Dart_IsLibrary(owner)) {
225  url = Dart_LibraryUrl(owner);
226  PropagateIfError(url);
227  }
229 }
230 
231 static std::string GetFunctionClassName(Dart_Handle closure) {
232  Dart_Handle result;
233 
234  if (Dart_IsClosure(closure)) {
235  closure = Dart_ClosureFunction(closure);
236  PropagateIfError(closure);
237  }
238 
239  if (!Dart_IsFunction(closure)) {
240  return "";
241  }
242 
243  bool is_static = false;
244  result = Dart_FunctionIsStatic(closure, &is_static);
245  PropagateIfError(result);
246  if (!is_static) {
247  return "";
248  }
249 
250  result = Dart_FunctionOwner(closure);
251  PropagateIfError(result);
252 
253  if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) {
254  return "";
255  }
256  return DartConverter<std::string>::FromDart(Dart_ClassName(result));
257 }
258 
259 static std::string GetFunctionName(Dart_Handle func) {
260  if (Dart_IsClosure(func)) {
261  func = Dart_ClosureFunction(func);
262  PropagateIfError(func);
263  }
264 
265  if (!Dart_IsFunction(func)) {
266  return "";
267  }
268 
269  bool is_static = false;
270  Dart_Handle result = Dart_FunctionIsStatic(func, &is_static);
271  PropagateIfError(result);
272  if (!is_static) {
273  return "";
274  }
275 
276  result = Dart_FunctionName(func);
277  PropagateIfError(result);
278 
280 }
281 
282 void GetCallbackHandle(Dart_NativeArguments args) {
283  Dart_Handle func = Dart_GetNativeArgument(args, 0);
284  std::string name = GetFunctionName(func);
285  std::string class_name = GetFunctionClassName(func);
286  std::string library_path = GetFunctionLibraryUrl(func);
287 
288  // `name` is empty if `func` can't be used as a callback. This is the case
289  // when `func` is not a function object or is not a static function. Anonymous
290  // closures (e.g. `(int a, int b) => a + b;`) also cannot be used as
291  // callbacks, so `func` must be a tear-off of a named static function.
292  if (!Dart_IsTearOff(func) || name.empty()) {
293  Dart_SetReturnValue(args, Dart_Null());
294  return;
295  }
296  Dart_SetReturnValue(
298  name, class_name, library_path)));
299 }
300 
301 void GetCallbackFromHandle(Dart_NativeArguments args) {
302  Dart_Handle h = Dart_GetNativeArgument(args, 0);
303  int64_t handle = DartConverter<int64_t>::FromDart(h);
304  Dart_SetReturnValue(args, DartCallbackCache::GetCallback(handle));
305 }
306 
307 } // namespace flutter
G_BEGIN_DECLS FlValue * args
static void InitDartIO(Dart_Handle builtin_library, const std::string &script_uri)
static Dart_Handle GetCallback(int64_t handle)
void Logger_PrintString(Dart_NativeArguments args)
static void Install(bool is_ui_isolate, const std::string &script_uri)
GAsyncResult * result
const std::string & logger_prefix() const
BUILTIN_NATIVE_LIST(DECLARE_FUNCTION)
#define FML_LOG(severity)
Definition: logging.h:65
void ScheduleMicrotask(Dart_NativeArguments args)
static std::string GetFunctionLibraryUrl(Dart_Handle closure)
#define DECLARE_FUNCTION(name, count)
static std::string GetFunctionName(Dart_Handle func)
static std::string GetFunctionClassName(Dart_Handle closure)
static int64_t GetCallbackHandle(const std::string &name, const std::string &class_name, const std::string &library_path)
static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate)
static void PropagateIfError(Dart_Handle result)
std::function< void()> closure
Definition: closure.h:14
static Dart_Handle InvokeFunction(Dart_Handle builtin_library, const char *name)
void Logger_PrintDebugString(Dart_NativeArguments args)
void Register(std::initializer_list< Entry > entries)
static void InitDartCore(Dart_Handle builtin, const std::string &script_uri)
size_t length
static void RegisterNatives(tonic::DartLibraryNatives *natives)
void GetCallbackHandle(Dart_NativeArguments args)
const char * name
Definition: fuchsia.cc:50
#define REGISTER_FUNCTION(name, count)
void LogMessage(const std::string &tag, const std::string &message) const
void ScheduleMicrotask(Dart_Handle handle)
Dart_Handle ToDart(const T &object)
void GetCallbackFromHandle(Dart_NativeArguments args)
bool LogIfError(Dart_Handle handle)
Definition: dart_error.cc:15
static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate)
static UIDartState * Current()