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/testing/dart_isolate_runner.h"
6
7namespace flutter {
8namespace testing {
9AutoIsolateShutdown::AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
10 fml::RefPtr<fml::TaskRunner> runner)
11 : isolate_(std::move(isolate)), runner_(std::move(runner)) {}
12
13AutoIsolateShutdown::~AutoIsolateShutdown() {
14 if (!IsValid()) {
15 return;
16 }
17 fml::AutoResetWaitableEvent latch;
18 fml::TaskRunner::RunNowOrPostTask(
19 runner_, [isolate = std::move(isolate_), &latch]() {
20 if (!isolate->Shutdown()) {
21 FML_LOG(ERROR) << "Could not shutdown isolate.";
22 FML_CHECK(false);
23 }
24 latch.Signal();
25 });
26 latch.Wait();
27}
28
29[[nodiscard]] bool AutoIsolateShutdown::RunInIsolateScope(
30 std::function<bool(void)> closure) {
31 if (!IsValid()) {
32 return false;
33 }
34
35 bool result = false;
36 fml::AutoResetWaitableEvent latch;
37 fml::TaskRunner::RunNowOrPostTask(
38 runner_, [this, &result, &latch, closure]() {
39 tonic::DartIsolateScope scope(isolate_->isolate());
40 tonic::DartApiScope api_scope;
41 if (closure) {
42 result = closure();
43 }
44 latch.Signal();
45 });
46 latch.Wait();
47 return true;
48}
49
50void RunDartCodeInIsolate(DartVMRef& vm_ref,
51 std::unique_ptr<AutoIsolateShutdown>& result,
52 const Settings& settings,
53 const TaskRunners& task_runners,
54 std::string entrypoint,
55 const std::vector<std::string>& args,
56 const std::string& fixtures_path,
57 fml::WeakPtr<IOManager> io_manager) {
58 FML_CHECK(task_runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
59
60 if (!vm_ref) {
61 return;
62 }
63
64 auto vm_data = vm_ref.GetVMData();
65
66 if (!vm_data) {
67 return;
68 }
69
70 auto weak_isolate = DartIsolate::CreateRootIsolate(
71 vm_data->GetSettings(), // settings
72 vm_data->GetIsolateSnapshot(), // isolate snapshot
73 std::move(task_runners), // task runners
74 nullptr, // window
75 {}, // snapshot delegate
76 io_manager, // io manager
77 {}, // unref queue
78 {}, // image decoder
79 "main.dart", // advisory uri
80 "main", // advisory entrypoint
81 nullptr, // flags
82 settings.isolate_create_callback, // isolate create callback
83 settings.isolate_shutdown_callback // isolate shutdown callback
84 );
85
86 auto root_isolate = std::make_unique<AutoIsolateShutdown>(
87 weak_isolate.lock(), task_runners.GetUITaskRunner());
88
89 if (!root_isolate->IsValid()) {
90 FML_LOG(ERROR) << "Could not create isolate.";
91 return;
92 }
93
94 if (root_isolate->get()->GetPhase() != DartIsolate::Phase::LibrariesSetup) {
95 FML_LOG(ERROR) << "Created isolate is in unexpected phase.";
96 return;
97 }
98
99 if (!DartVM::IsRunningPrecompiledCode()) {
100 auto kernel_file_path =
101 fml::paths::JoinPaths({fixtures_path, "kernel_blob.bin"});
102
103 if (!fml::IsFile(kernel_file_path)) {
104 FML_LOG(ERROR) << "Could not locate kernel file.";
105 return;
106 }
107
108 auto kernel_file = fml::OpenFile(kernel_file_path.c_str(), false,
109 fml::FilePermission::kRead);
110
111 if (!kernel_file.is_valid()) {
112 FML_LOG(ERROR) << "Kernel file descriptor was invalid.";
113 return;
114 }
115
116 auto kernel_mapping = std::make_unique<fml::FileMapping>(kernel_file);
117
118 if (kernel_mapping->GetMapping() == nullptr) {
119 FML_LOG(ERROR) << "Could not setup kernel mapping.";
120 return;
121 }
122
123 if (!root_isolate->get()->PrepareForRunningFromKernel(
124 std::move(kernel_mapping))) {
125 FML_LOG(ERROR)
126 << "Could not prepare to run the isolate from the kernel file.";
127 return;
128 }
129 } else {
130 if (!root_isolate->get()->PrepareForRunningFromPrecompiledCode()) {
131 FML_LOG(ERROR)
132 << "Could not prepare to run the isolate from precompiled code.";
133 return;
134 }
135 }
136
137 if (root_isolate->get()->GetPhase() != DartIsolate::Phase::Ready) {
138 FML_LOG(ERROR) << "Isolate is in unexpected phase.";
139 return;
140 }
141
142 if (!root_isolate->get()->Run(entrypoint, args,
143 settings.root_isolate_create_callback)) {
144 FML_LOG(ERROR) << "Could not run the method \"" << entrypoint
145 << "\" in the isolate.";
146 return;
147 }
148
149 root_isolate->get()->AddIsolateShutdownCallback(
150 settings.root_isolate_shutdown_callback);
151
152 result = std::move(root_isolate);
153}
154
155std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
156 DartVMRef& vm_ref,
157 const Settings& settings,
158 const TaskRunners& task_runners,
159 std::string entrypoint,
160 const std::vector<std::string>& args,
161 const std::string& fixtures_path,
162 fml::WeakPtr<IOManager> io_manager) {
163 std::unique_ptr<AutoIsolateShutdown> result;
164 fml::AutoResetWaitableEvent latch;
165 fml::TaskRunner::RunNowOrPostTask(
166 task_runners.GetUITaskRunner(), fml::MakeCopyable([&]() mutable {
167 RunDartCodeInIsolate(vm_ref, result, settings, task_runners, entrypoint,
168 args, fixtures_path, io_manager);
169 latch.Signal();
170 }));
171 latch.Wait();
172 return result;
173}
174
175} // namespace testing
176} // namespace flutter
177