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