| 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 | |
| 11 | namespace flutter { |
| 12 | namespace testing { |
| 13 | AutoIsolateShutdown::AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate, |
| 14 | fml::RefPtr<fml::TaskRunner> runner) |
| 15 | : isolate_(std::move(isolate)), runner_(std::move(runner)) {} |
| 16 | |
| 17 | AutoIsolateShutdown::~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 | |
| 30 | void 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 | |
| 67 | std::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 | |
| 154 | std::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 | |