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 
30 #if defined(OS_ANDROID)
31 #include <android/log.h>
32 #elif defined(OS_IOS)
33 extern "C" {
34 // Cannot import the syslog.h header directly because of macro collision.
35 extern void syslog(int, const char*, ...);
36 }
37 #endif
38 
40 using tonic::LogIfError;
41 using tonic::ToDart;
42 
43 namespace flutter {
44 
45 #define REGISTER_FUNCTION(name, count) {"" #name, name, count, true},
46 #define DECLARE_FUNCTION(name, count) \
47  extern void name(Dart_NativeArguments args);
48 
49 #define BUILTIN_NATIVE_LIST(V) \
50  V(Logger_PrintString, 1) \
51  V(Logger_PrintDebugString, 1) \
52  V(SaveCompilationTrace, 0) \
53  V(ScheduleMicrotask, 1) \
54  V(GetCallbackHandle, 1) \
55  V(GetCallbackFromHandle, 1)
56 
58 
61 }
62 
63 static void PropagateIfError(Dart_Handle result) {
64  if (Dart_IsError(result)) {
65  FML_LOG(ERROR) << "Dart Error: " << ::Dart_GetError(result);
66  Dart_PropagateError(result);
67  }
68 }
69 
70 static Dart_Handle InvokeFunction(Dart_Handle builtin_library,
71  const char* name) {
72  Dart_Handle getter_name = ToDart(name);
73  return Dart_Invoke(builtin_library, getter_name, 0, nullptr);
74 }
75 
76 static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate) {
77  Dart_Handle print = InvokeFunction(builtin_library, "_getPrintClosure");
78 
79  Dart_Handle internal_library = Dart_LookupLibrary(ToDart("dart:_internal"));
80 
81  Dart_Handle result =
82  Dart_SetField(internal_library, ToDart("_printClosure"), print);
83  PropagateIfError(result);
84 
85  if (is_ui_isolate) {
86  // Call |_setupHooks| to configure |VMLibraryHooks|.
87  Dart_Handle method_name = Dart_NewStringFromCString("_setupHooks");
88  result = Dart_Invoke(builtin_library, method_name, 0, NULL);
89  PropagateIfError(result);
90  }
91 
92  Dart_Handle setup_hooks = Dart_NewStringFromCString("_setupHooks");
93 
94  Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
95  result = Dart_Invoke(io_lib, setup_hooks, 0, NULL);
96  PropagateIfError(result);
97 
98  Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
99  result = Dart_Invoke(isolate_lib, setup_hooks, 0, NULL);
100  PropagateIfError(result);
101 }
102 
103 static void InitDartCore(Dart_Handle builtin, const std::string& script_uri) {
104  Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
105  Dart_Handle get_base_url =
106  Dart_Invoke(io_lib, ToDart("_getUriBaseClosure"), 0, NULL);
107  Dart_Handle core_library = Dart_LookupLibrary(ToDart("dart:core"));
108  Dart_Handle result =
109  Dart_SetField(core_library, ToDart("_uriBaseClosure"), get_base_url);
110  PropagateIfError(result);
111 }
112 
113 static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) {
114  Dart_Handle schedule_microtask;
115  if (is_ui_isolate) {
116  schedule_microtask =
117  InvokeFunction(builtin_library, "_getScheduleMicrotaskClosure");
118  } else {
119  Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
120  Dart_Handle method_name =
121  Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure");
122  schedule_microtask = Dart_Invoke(isolate_lib, method_name, 0, NULL);
123  }
124  Dart_Handle async_library = Dart_LookupLibrary(ToDart("dart:async"));
125  Dart_Handle set_schedule_microtask = ToDart("_setScheduleImmediateClosure");
126  Dart_Handle result = Dart_Invoke(async_library, set_schedule_microtask, 1,
127  &schedule_microtask);
128  PropagateIfError(result);
129 }
130 
131 static void InitDartIO(Dart_Handle builtin_library,
132  const std::string& script_uri) {
133  Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io"));
134  Dart_Handle platform_type =
135  Dart_GetNonNullableType(io_lib, ToDart("_Platform"), 0, nullptr);
136  if (!script_uri.empty()) {
137  Dart_Handle result = Dart_SetField(platform_type, ToDart("_nativeScript"),
138  ToDart(script_uri));
139  PropagateIfError(result);
140  }
141  // typedef _LocaleClosure = String Function();
142  Dart_Handle /* _LocaleClosure? */ locale_closure =
143  InvokeFunction(builtin_library, "_getLocaleClosure");
144  PropagateIfError(locale_closure);
145  // static String Function()? _localeClosure;
146  Dart_Handle result =
147  Dart_SetField(platform_type, ToDart("_localeClosure"), locale_closure);
148  PropagateIfError(result);
149 
150  // Register dart:io service extensions used for network profiling.
151  Dart_Handle network_profiling_type =
152  Dart_GetNonNullableType(io_lib, ToDart("_NetworkProfiling"), 0, nullptr);
153  PropagateIfError(network_profiling_type);
154  result = Dart_Invoke(network_profiling_type,
155  ToDart("_registerServiceExtension"), 0, nullptr);
156  PropagateIfError(result);
157 }
158 
159 void DartRuntimeHooks::Install(bool is_ui_isolate,
160  const std::string& script_uri) {
161  Dart_Handle builtin = Dart_LookupLibrary(ToDart("dart:ui"));
162  InitDartInternal(builtin, is_ui_isolate);
163  InitDartCore(builtin, script_uri);
164  InitDartAsync(builtin, is_ui_isolate);
165  InitDartIO(builtin, script_uri);
166 }
167 
168 void Logger_PrintDebugString(Dart_NativeArguments args) {
169 #ifndef NDEBUG
170  Logger_PrintString(args);
171 #endif
172 }
173 
174 // Implementation of native functions which are used for some
175 // test/debug functionality in standalone dart mode.
176 void Logger_PrintString(Dart_NativeArguments args) {
177  std::stringstream stream;
178  const auto& logger_prefix = UIDartState::Current()->logger_prefix();
179 
180 #if !OS_ANDROID
181  // Prepend all logs with the isolate debug name except on Android where that
182  // prefix is specified in the log tag.
183  if (logger_prefix.size() > 0) {
184  stream << logger_prefix << ": ";
185  }
186 #endif // !OS_ANDROID
187 
188  // Append the log buffer obtained from Dart code.
189  {
190  Dart_Handle str = Dart_GetNativeArgument(args, 0);
191  uint8_t* chars = nullptr;
192  intptr_t length = 0;
193  Dart_Handle result = Dart_StringToUTF8(str, &chars, &length);
194  if (Dart_IsError(result)) {
195  Dart_PropagateError(result);
196  return;
197  }
198  if (length > 0) {
199  stream << std::string{reinterpret_cast<const char*>(chars),
200  static_cast<size_t>(length)};
201  }
202  }
203 
204  const auto log_string = stream.str();
205  const char* chars = log_string.c_str();
206  const size_t length = log_string.size();
207 
208  // Log using platform specific mechanisms
209  {
210 #if defined(OS_ANDROID)
211  // Write to the logcat on Android.
212  __android_log_print(ANDROID_LOG_INFO, logger_prefix.c_str(), "%.*s",
213  (int)length, chars);
214 #elif defined(OS_IOS)
215  // Write to syslog on iOS.
216  //
217  // TODO(cbracken): replace with dedicated communication channel and bypass
218  // iOS logging APIs altogether.
219  syslog(1 /* LOG_ALERT */, "%.*s", (int)length, chars);
220 #else
221  std::cout << log_string << std::endl;
222 #endif
223  }
224 
225  if (dart::bin::ShouldCaptureStdout()) {
226  // For now we report print output on the Stdout stream.
227  uint8_t newline[] = {'\n'};
228  Dart_ServiceSendDataEvent("Stdout", "WriteEvent",
229  reinterpret_cast<const uint8_t*>(chars), length);
230  Dart_ServiceSendDataEvent("Stdout", "WriteEvent", newline, sizeof(newline));
231  }
232 }
233 
234 void SaveCompilationTrace(Dart_NativeArguments args) {
235  uint8_t* buffer = nullptr;
236  intptr_t length = 0;
237  Dart_Handle result = Dart_SaveCompilationTrace(&buffer, &length);
238  if (Dart_IsError(result)) {
239  Dart_SetReturnValue(args, result);
240  return;
241  }
242 
243  result = Dart_NewTypedData(Dart_TypedData_kUint8, length);
244  if (Dart_IsError(result)) {
245  Dart_SetReturnValue(args, result);
246  return;
247  }
248 
249  Dart_TypedData_Type type;
250  void* data = nullptr;
251  intptr_t size = 0;
252  Dart_Handle status = Dart_TypedDataAcquireData(result, &type, &data, &size);
253  if (Dart_IsError(status)) {
254  Dart_SetReturnValue(args, status);
255  return;
256  }
257 
258  memcpy(data, buffer, length);
259  Dart_TypedDataReleaseData(result);
260  Dart_SetReturnValue(args, result);
261 }
262 
263 void ScheduleMicrotask(Dart_NativeArguments args) {
264  Dart_Handle closure = Dart_GetNativeArgument(args, 0);
266 }
267 
268 static std::string GetFunctionLibraryUrl(Dart_Handle closure) {
269  if (Dart_IsClosure(closure)) {
270  closure = Dart_ClosureFunction(closure);
271  PropagateIfError(closure);
272  }
273 
274  if (!Dart_IsFunction(closure)) {
275  return "";
276  }
277 
278  Dart_Handle url = Dart_Null();
279  Dart_Handle owner = Dart_FunctionOwner(closure);
280  if (Dart_IsInstance(owner)) {
281  owner = Dart_ClassLibrary(owner);
282  }
283  if (Dart_IsLibrary(owner)) {
284  url = Dart_LibraryUrl(owner);
285  PropagateIfError(url);
286  }
288 }
289 
290 static std::string GetFunctionClassName(Dart_Handle closure) {
291  Dart_Handle result;
292 
293  if (Dart_IsClosure(closure)) {
294  closure = Dart_ClosureFunction(closure);
295  PropagateIfError(closure);
296  }
297 
298  if (!Dart_IsFunction(closure)) {
299  return "";
300  }
301 
302  bool is_static = false;
303  result = Dart_FunctionIsStatic(closure, &is_static);
304  PropagateIfError(result);
305  if (!is_static) {
306  return "";
307  }
308 
309  result = Dart_FunctionOwner(closure);
310  PropagateIfError(result);
311 
312  if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) {
313  return "";
314  }
315  return DartConverter<std::string>::FromDart(Dart_ClassName(result));
316 }
317 
318 static std::string GetFunctionName(Dart_Handle func) {
319  if (Dart_IsClosure(func)) {
320  func = Dart_ClosureFunction(func);
321  PropagateIfError(func);
322  }
323 
324  if (!Dart_IsFunction(func)) {
325  return "";
326  }
327 
328  bool is_static = false;
329  Dart_Handle result = Dart_FunctionIsStatic(func, &is_static);
330  PropagateIfError(result);
331  if (!is_static) {
332  return "";
333  }
334 
335  result = Dart_FunctionName(func);
336  PropagateIfError(result);
337 
339 }
340 
341 void GetCallbackHandle(Dart_NativeArguments args) {
342  Dart_Handle func = Dart_GetNativeArgument(args, 0);
343  std::string name = GetFunctionName(func);
344  std::string class_name = GetFunctionClassName(func);
345  std::string library_path = GetFunctionLibraryUrl(func);
346 
347  // `name` is empty if `func` can't be used as a callback. This is the case
348  // when `func` is not a function object or is not a static function. Anonymous
349  // closures (e.g. `(int a, int b) => a + b;`) also cannot be used as
350  // callbacks, so `func` must be a tear-off of a named static function.
351  if (!Dart_IsTearOff(func) || name.empty()) {
352  Dart_SetReturnValue(args, Dart_Null());
353  return;
354  }
355  Dart_SetReturnValue(
357  name, class_name, library_path)));
358 }
359 
360 void GetCallbackFromHandle(Dart_NativeArguments args) {
361  Dart_Handle h = Dart_GetNativeArgument(args, 0);
362  int64_t handle = DartConverter<int64_t>::FromDart(h);
363  Dart_SetReturnValue(args, DartCallbackCache::GetCallback(handle));
364 }
365 
366 } // namespace flutter
static void InitDartIO(Dart_Handle builtin_library, const std::string &script_uri)
void SaveCompilationTrace(Dart_NativeArguments args)
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)
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
const std::string & logger_prefix() const
Definition: ui_dart_state.h:46
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)
size_t length
void Register(std::initializer_list< Entry > entries)
static void InitDartCore(Dart_Handle builtin, const std::string &script_uri)
static void RegisterNatives(tonic::DartLibraryNatives *natives)
void GetCallbackHandle(Dart_NativeArguments args)
const char * name
Definition: fuchsia.cc:50
#define REGISTER_FUNCTION(name, count)
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()