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
7#include <utility>
8
9#include "flutter/runtime/isolate_configuration.h"
10
11namespace flutter {
12namespace testing {
13AutoIsolateShutdown::AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
14 fml::RefPtr<fml::TaskRunner> runner)
15 : isolate_(std::move(isolate)), runner_(std::move(runner)) {}
16
17AutoIsolateShutdown::~AutoIsolateShutdown() {
18 if (!isolate_->IsShuttingDown()) {
19 Shutdown();
20 }
21 fml::AutoResetWaitableEvent latch;
22 fml::TaskRunner::RunNowOrPostTask(runner: runner_, task: [this, &latch]() {
23 // Delete isolate on thread.
24 isolate_.reset();
25 latch.Signal();
26 });
27 latch.Wait();
28}
29
30void AutoIsolateShutdown::Shutdown() {
31 if (!IsValid()) {
32 return;
33 }
34 fml::AutoResetWaitableEvent latch;
35 fml::TaskRunner::RunNowOrPostTask(
36 runner: runner_, task: [isolate = isolate_.get(), &latch]() {
37 if (!isolate->Shutdown()) {
38 FML_LOG(ERROR) << "Could not shutdown isolate.";
39 FML_CHECK(false);
40 }
41 latch.Signal();
42 });
43 latch.Wait();
44}
45
46[[nodiscard]] bool AutoIsolateShutdown::RunInIsolateScope(
47 const std::function<bool(void)>& closure) {
48 if (!IsValid()) {
49 return false;
50 }
51
52 bool result = false;
53 fml::AutoResetWaitableEvent latch;
54 fml::TaskRunner::RunNowOrPostTask(
55 runner: runner_, task: [this, &result, &latch, closure]() {
56 tonic::DartIsolateScope scope(isolate_->isolate());
57 tonic::DartApiScope api_scope;
58 if (closure) {
59 result = closure();
60 }
61 latch.Signal();
62 });
63 latch.Wait();
64 return result;
65}
66
67std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolateOnUITaskRunner(
68 DartVMRef& vm_ref,
69 const Settings& p_settings,
70 const TaskRunners& task_runners,
71 std::string entrypoint,
72 const std::vector<std::string>& args,
73 const std::string& kernel_file_path,
74 fml::WeakPtr<IOManager> io_manager,
75 const std::shared_ptr<VolatilePathTracker>& volatile_path_tracker) {
76 FML_CHECK(task_runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
77
78 if (!vm_ref) {
79 return nullptr;
80 }
81
82 auto vm_data = vm_ref.GetVMData();
83
84 if (!vm_data) {
85 return nullptr;
86 }
87
88 auto settings = p_settings;
89
90 if (!DartVM::IsRunningPrecompiledCode()) {
91 if (!fml::IsFile(path: kernel_file_path)) {
92 FML_LOG(ERROR) << "Could not locate kernel file.";
93 return nullptr;
94 }
95
96 auto kernel_file = fml::OpenFile(path: kernel_file_path.c_str(), create_if_necessary: false,
97 permission: fml::FilePermission::kRead);
98
99 if (!kernel_file.is_valid()) {
100 FML_LOG(ERROR) << "Kernel file descriptor was invalid.";
101 return nullptr;
102 }
103
104 auto kernel_mapping = std::make_unique<fml::FileMapping>(args&: kernel_file);
105
106 if (kernel_mapping->GetMapping() == nullptr) {
107 FML_LOG(ERROR) << "Could not set up kernel mapping.";
108 return nullptr;
109 }
110
111 settings.application_kernels = fml::MakeCopyable(
112 lambda: [kernel_mapping = std::move(kernel_mapping)]() mutable -> Mappings {
113 Mappings mappings;
114 mappings.emplace_back(args: std::move(kernel_mapping));
115 return mappings;
116 });
117 }
118
119 auto isolate_configuration =
120 IsolateConfiguration::InferFromSettings(settings);
121
122 UIDartState::Context context(task_runners);
123 context.io_manager = std::move(io_manager);
124 context.advisory_script_uri = "main.dart";
125 context.advisory_script_entrypoint = entrypoint.c_str();
126 context.enable_impeller = p_settings.enable_impeller;
127
128 auto isolate =
129 DartIsolate::CreateRunningRootIsolate(
130 settings, // settings
131 isolate_snapshot: vm_data->GetIsolateSnapshot(), // isolate snapshot
132 platform_configuration: nullptr, // platform configuration
133 flags: DartIsolate::Flags{}, // flags
134 root_isolate_create_callback: nullptr, // root isolate create callback
135 isolate_create_callback: settings.isolate_create_callback, // isolate create callback
136 isolate_shutdown_callback: settings.isolate_shutdown_callback, // isolate shutdown callback
137 dart_entrypoint: entrypoint, // entrypoint
138 dart_entrypoint_library: std::nullopt, // library
139 dart_entrypoint_args: args, // args
140 isolate_configuration: std::move(isolate_configuration), // isolate configuration
141 context // engine context
142 )
143 .lock();
144
145 if (!isolate) {
146 FML_LOG(ERROR) << "Could not create running isolate.";
147 return nullptr;
148 }
149
150 return std::make_unique<AutoIsolateShutdown>(
151 args&: isolate, args: context.task_runners.GetUITaskRunner());
152}
153
154std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
155 DartVMRef& vm_ref,
156 const Settings& settings,
157 const TaskRunners& task_runners,
158 std::string entrypoint,
159 const std::vector<std::string>& args,
160 const std::string& kernel_file_path,
161 fml::WeakPtr<IOManager> io_manager,
162 std::shared_ptr<VolatilePathTracker> volatile_path_tracker) {
163 std::unique_ptr<AutoIsolateShutdown> result;
164 fml::AutoResetWaitableEvent latch;
165 fml::TaskRunner::RunNowOrPostTask(
166 runner: task_runners.GetUITaskRunner(), task: fml::MakeCopyable(lambda: [&]() mutable {
167 result = RunDartCodeInIsolateOnUITaskRunner(
168 vm_ref, p_settings: settings, task_runners, entrypoint, args, kernel_file_path,
169 io_manager, volatile_path_tracker);
170 latch.Signal();
171 }));
172 latch.Wait();
173 return result;
174}
175
176} // namespace testing
177} // namespace flutter
178

source code of flutter_engine/flutter/testing/dart_isolate_runner.cc