Flutter Engine
 
Loading...
Searching...
No Matches
dart_vm_initializer.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
6
7#include <atomic>
8
15
17
18namespace {
19// Tracks whether Dart has been initialized and if it is safe to call Dart
20// APIs.
21static std::atomic<bool> gDartInitialized;
22
23void LogUnhandledException(Dart_Handle exception_handle,
24 Dart_Handle stack_trace_handle) {
25 const std::string error =
26 tonic::StdStringFromDart(Dart_ToString(exception_handle));
27 const std::string stack_trace =
28 tonic::StdStringFromDart(Dart_ToString(stack_trace_handle));
29
30 auto state = flutter::UIDartState::Current();
31 if (state && state->unhandled_exception_callback()) {
32 auto callback = state->unhandled_exception_callback();
33 if (callback(error, stack_trace)) {
34 return;
35 }
36 }
37
38 // Either the exception handler was not set or it could not handle the
39 // error, just log the exception.
40 FML_LOG(ERROR) << "Unhandled Exception: " << error << std::endl
41 << stack_trace;
42}
43
44void ReportUnhandledException(Dart_Handle exception_handle,
45 Dart_Handle stack_trace_handle) {
46 // Hooks.dart will call the error handler on PlatformDispatcher if it is
47 // not null. If it is null, returns false, fall into the !handled branch
48 // below and log.
49 // If it is not null, defer to the return value of that closure
50 // to determine whether to report via logging.
51 bool handled = false;
52 auto state = flutter::UIDartState::Current();
53 if (!state || !state->platform_configuration()) {
54 LogUnhandledException(exception_handle, stack_trace_handle);
55 return;
56 }
57 auto on_error = state->platform_configuration()->on_error();
58 if (on_error) {
59 FML_DCHECK(!Dart_IsNull(on_error));
60 Dart_Handle args[2];
61 args[0] = exception_handle;
62 args[1] = stack_trace_handle;
63 Dart_Handle on_error_result = Dart_InvokeClosure(on_error, 2, args);
64
65 // An exception was thrown by the exception handler.
66 if (Dart_IsError(on_error_result)) {
67 LogUnhandledException(Dart_ErrorGetException(on_error_result),
68 Dart_ErrorGetStackTrace(on_error_result));
69
70 handled = false;
71 } else {
72 handled = tonic::DartConverter<bool>::FromDart(on_error_result);
73 }
74 if (!handled) {
75 LogUnhandledException(exception_handle, stack_trace_handle);
76 }
77 }
78}
79} // namespace
80
81void DartVMInitializer::Initialize(Dart_InitializeParams* params,
82 bool enable_timeline_event_handler,
83 bool trace_systrace) {
84 FML_DCHECK(!gDartInitialized);
85
86 char* error = Dart_Initialize(params);
87 if (error) {
88 FML_LOG(FATAL) << "Error while initializing the Dart VM: " << error;
89 ::free(error);
90 } else {
91 gDartInitialized = true;
92 }
93
94 if (enable_timeline_event_handler) {
95 if (!trace_systrace) {
96 // Systrace on all platforms except Fuchsia ignores the timestamp provided
97 // here. On Android in particular, calls to get the system clock show up
98 // in profiles.
99 // Fuchsia does not use the TraceSetTimelineMicrosSource.
100 fml::tracing::TraceSetTimelineMicrosSource(Dart_TimelineGetMicros);
101 } else {
103 []() -> int64_t { return -1; });
104 }
105 fml::tracing::TraceSetTimelineEventHandler(LogDartTimelineEvent);
106 }
107
109 tonic::SetUnhandledExceptionReporter(&ReportUnhandledException);
110}
111
113 FML_DCHECK(gDartInitialized);
114
115 // Dart_RecordTimelineEvent is unsafe during a concurrent call to Dart_Cleanup
116 // because Dart_Cleanup will destroy the timeline recorder. Clear the
117 // initialized flag so that future calls to LogDartTimelineEvent will not
118 // call Dart_RecordTimelineEvent.
119 //
120 // Note that this is inherently racy. If a thread sees that gDartInitialized
121 // is set and proceeds to call Dart_RecordTimelineEvent shortly before another
122 // thread calls Dart_Cleanup, then the Dart_RecordTimelineEvent call may crash
123 // if Dart_Cleanup deletes the timeline before Dart_RecordTimelineEvent
124 // completes. In practice this is unlikely because Dart_Cleanup does
125 // significant other work before deleting the timeline.
126 //
127 // The engine can not safely guard Dart_Cleanup and LogDartTimelineEvent with
128 // a lock due to the risk of deadlocks. Dart_Cleanup waits for various
129 // Dart-owned threads to shut down. If one of those threads invokes an engine
130 // callback that calls LogDartTimelineEvent while the Dart_Cleanup thread owns
131 // the lock, then Dart_Cleanup would deadlock.
132 gDartInitialized = false;
133
134 char* error = Dart_Cleanup();
135 if (error) {
136 FML_LOG(FATAL) << "Error while cleaning up the Dart VM: " << error;
137 ::free(error);
138 }
139}
140
141void DartVMInitializer::LogDartTimelineEvent(const char* label,
142 int64_t timestamp0,
143 int64_t timestamp1_or_async_id,
144 intptr_t flow_id_count,
145 const int64_t* flow_ids,
146 Dart_Timeline_Event_Type type,
147 intptr_t argument_count,
148 const char** argument_names,
149 const char** argument_values) {
150 if (gDartInitialized) {
151 Dart_RecordTimelineEvent(label, timestamp0, timestamp1_or_async_id,
152 flow_id_count, flow_ids, type, argument_count,
153 argument_names, argument_values);
154 }
155}
GLenum type
static void Initialize(Dart_InitializeParams *params, bool enable_timeline_event_handler, bool trace_systrace)
static UIDartState * Current()
static void SetClockSource(ClockSource source)
Definition time_point.cc:45
const EmbeddedViewParams * params
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
Definition logging.h:101
#define FML_DCHECK(condition)
Definition logging.h:122
int argument_count
Definition fuchsia.cc:51
fml::TimePoint DartTimelineTicksSinceEpoch()
void TraceSetTimelineEventHandler(TimelineEventHandler handler)
void TraceSetTimelineMicrosSource(TimelineMicrosSource source)
void SetUnhandledExceptionReporter(DartError::UnhandledExceptionReporter reporter)
Definition dart_error.cc:28
std::string StdStringFromDart(Dart_Handle handle)