Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
dart_runner.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 <lib/async-loop/loop.h>
8#include <lib/async/default.h>
9#include <lib/vfs/cpp/pseudo_dir.h>
10#include <sys/stat.h>
11#include <zircon/status.h>
12#include <zircon/syscalls.h>
13
14#include <cerrno>
15#include <memory>
16#include <thread>
17#include <utility>
18
20#include "flutter/fml/logging.h"
26#include "third_party/dart/runtime/include/bin/dart_io_api.h"
29
30namespace dart_runner {
31
32namespace {
33
34const char* kDartVMArgs[] = {
35 // clang-format off
36
37 "--timeline_recorder=systrace",
38 "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM",
39
40#if defined(AOT_RUNTIME)
41 "--precompilation",
42#else
43 "--enable_mirrors=false",
44#endif
45
46 // No asserts in debug or release product.
47 // No asserts in release with flutter_profile=true (non-product)
48 // Yes asserts in non-product debug.
49#if !defined(DART_PRODUCT) && (!defined(FLUTTER_PROFILE) || !defined(NDEBUG))
50 "--enable_asserts",
51#endif
52};
53
54Dart_Isolate IsolateGroupCreateCallback(const char* uri,
55 const char* name,
56 const char* package_root,
57 const char* package_config,
58 Dart_IsolateFlags* flags,
59 void* callback_data,
60 char** error) {
61 if (std::string(uri) == DART_VM_SERVICE_ISOLATE_NAME) {
62#if defined(DART_PRODUCT)
63 *error = strdup("The service isolate is not implemented in product mode");
64 return NULL;
65#else
66 return CreateServiceIsolate(uri, flags, error);
67#endif
68 }
69
70 *error = strdup("Isolate spawning is not implemented in dart_runner");
71 return NULL;
72}
73
74void IsolateShutdownCallback(void* isolate_group_data, void* isolate_data) {
75 // The service isolate (and maybe later the kernel isolate) doesn't have an
76 // async loop.
77 auto dispatcher = async_get_default_dispatcher();
78 auto loop = async_loop_from_dispatcher(dispatcher);
79 if (loop) {
82 if (queue) {
83 queue->Destroy();
84 }
85
86 async_loop_quit(loop);
87 }
88
89 auto state =
90 static_cast<std::shared_ptr<tonic::DartState>*>(isolate_group_data);
91 state->get()->SetIsShuttingDown();
92}
93
94void IsolateGroupCleanupCallback(void* isolate_group_data) {
95 delete static_cast<std::shared_ptr<tonic::DartState>*>(isolate_group_data);
96}
97
98// Runs the application for a Dart component.
99void RunApplication(
100 DartRunner* runner,
101 fuchsia::component::runner::ComponentStartInfo start_info,
102 std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
103 fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
104 controller) {
105 const int64_t start = Dart_TimelineGetMicros();
106
107 DartComponentController app(std::move(start_info), runner_incoming_services,
108 std::move(controller));
109 const bool success = app.SetUp();
110
111 const int64_t end = Dart_TimelineGetMicros();
112 Dart_RecordTimelineEvent(
113 "DartComponentController::SetUp", start, end, 0, nullptr,
114 Dart_Timeline_Event_Duration, 0, NULL, NULL);
115 if (success) {
116 app.Run();
117 }
118
119 if (Dart_CurrentIsolate()) {
120 Dart_ShutdownIsolate();
121 }
122}
123
124void RunTestApplication(
125 DartRunner* runner,
126 fuchsia::component::runner::ComponentStartInfo start_info,
127 std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
128 fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
129 controller,
130 fit::function<void(std::shared_ptr<DartTestComponentController>)>
131 component_created_callback,
132 fit::function<void(DartTestComponentController*)> done_callback) {
133 const int64_t start = Dart_TimelineGetMicros();
134
135 auto test_component = std::make_shared<DartTestComponentController>(
136 std::move(start_info), runner_incoming_services, std::move(controller),
137 std::move(done_callback));
138
139 component_created_callback(test_component);
140
141 // Start up the dart isolate and serve the suite protocol.
142 test_component->SetUp();
143
144 const int64_t end = Dart_TimelineGetMicros();
145 Dart_RecordTimelineEvent(
146 "DartTestComponentController::SetUp", start, end, 0, nullptr,
147 Dart_Timeline_Event_Duration, 0, NULL, NULL);
148}
149
150bool EntropySource(uint8_t* buffer, intptr_t count) {
151 zx_cprng_draw(buffer, count);
152 return true;
153}
154
155} // namespace
156
157// "args" are how the component specifies arguments to the runner.
158constexpr char kArgsKey[] = "args";
159
160/// Parses the |args| field from the "program" field to determine
161/// if a test component is being executed.
162bool IsTestProgram(const fuchsia::data::Dictionary& program_metadata) {
163 for (const auto& entry : program_metadata.entries()) {
164 if (entry.key.compare(kArgsKey) != 0 || entry.value == nullptr) {
165 continue;
166 }
167 auto args = entry.value->str_vec();
168
169 // fml::CommandLine expects the first argument to be the name of the
170 // program, so we prepend a dummy argument so we can use fml::CommandLine to
171 // parse the arguments for us.
172 std::vector<std::string> command_line_args = {""};
173 command_line_args.insert(command_line_args.end(), args.begin(), args.end());
175 command_line_args.begin(), command_line_args.end());
176
177 std::string is_test_str;
178 return parsed_args.GetOptionValue("is_test", &is_test_str) &&
179 is_test_str == "true";
180 }
181 return false;
182}
183
184DartRunner::DartRunner(sys::ComponentContext* context) : context_(context) {
185 context_->outgoing()
186 ->AddPublicService<fuchsia::component::runner::ComponentRunner>(
187 [this](fidl::InterfaceRequest<
188 fuchsia::component::runner::ComponentRunner> request) {
189 component_runner_bindings_.AddBinding(this, std::move(request));
190 });
191
192#if !defined(DART_PRODUCT)
193 // The VM service isolate uses the process-wide namespace. It writes the
194 // vm service protocol port under /tmp. The VMServiceObject exposes that
195 // port number to The Hub.
196 context_->outgoing()->debug_dir()->AddEntry(
198 std::make_unique<dart_utils::VMServiceObject>());
199
200#endif // !defined(DART_PRODUCT)
201
202 dart::bin::BootstrapDartIo();
203
204 char* error =
205 Dart_SetVMFlags(dart_utils::ArraySize(kDartVMArgs), kDartVMArgs);
206 if (error) {
207 FML_LOG(FATAL) << "Dart_SetVMFlags failed: " << error;
208 }
209
210 Dart_InitializeParams params = {};
211 params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
212 params.create_group = IsolateGroupCreateCallback;
213 params.shutdown_isolate = IsolateShutdownCallback;
214 params.cleanup_group = IsolateGroupCleanupCallback;
215 params.entropy_source = EntropySource;
216 error = Dart_Initialize(&params);
217 if (error)
218 FML_LOG(FATAL) << "Dart_Initialize failed: " << error;
219}
220
222 char* error = Dart_Cleanup();
223 if (error)
224 FML_LOG(FATAL) << "Dart_Cleanup failed: " << error;
225}
226
227void DartRunner::Start(
228 fuchsia::component::runner::ComponentStartInfo start_info,
229 fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
230 controller) {
231 // Parse the program field of the component's cml and check if it is a test
232 // component. If so, serve the |fuchsia.test.Suite| protocol from the
233 // component's outgoing directory, via DartTestComponentController.
234 if (IsTestProgram(start_info.program())) {
235 std::string url_copy = start_info.resolved_url();
236 TRACE_EVENT1("dart", "Start", "url", url_copy.c_str());
237 std::thread thread(
238 RunTestApplication, this, std::move(start_info), context_->svc(),
239 std::move(controller),
240 // component_created_callback
241 [this](std::shared_ptr<DartTestComponentController> ptr) {
242 test_components_.emplace(ptr.get(), std::move(ptr));
243 },
244 // done_callback
245 [this](DartTestComponentController* ptr) {
246 auto it = test_components_.find(ptr);
247 if (it != test_components_.end()) {
248 test_components_.erase(it);
249 }
250 });
251 thread.detach();
252 } else {
253 std::string url_copy = start_info.resolved_url();
254 TRACE_EVENT1("dart", "Start", "url", url_copy.c_str());
255 std::thread thread(RunApplication, this, std::move(start_info),
256 context_->svc(), std::move(controller));
257 thread.detach();
258 }
259}
260
261void DartRunner::handle_unknown_method(uint64_t ordinal,
262 bool method_has_response) {
263 FML_LOG(ERROR) << "Unknown method called on DartRunner. Ordinal: "
264 << ordinal;
265}
266
267} // namespace dart_runner
DartRunner(sys::ComponentContext *context)
static constexpr const char * kPortDirName
bool GetOptionValue(std::string_view name, std::string *value) const
static DartMicrotaskQueue * GetForCurrentThread()
const EmbeddedViewParams * params
VkQueue queue
Definition main.cc:71
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
Definition logging.h:101
const char * name
Definition fuchsia.cc:50
constexpr char kArgsKey[]
bool IsTestProgram(const fuchsia::data::Dictionary &program_metadata)
Dart_Isolate CreateServiceIsolate(const char *uri, Dart_IsolateFlags *flags_unused, char **error)
size_t ArraySize(T(&array)[SIZE])
Definition inlines.h:11
char * strdup(const char *str1)
CommandLine CommandLineFromIterators(InputIterator first, InputIterator last)
std::shared_ptr< ContextGLES > context
const size_t start
const size_t end
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)