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