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 "runner.h"
6
7 #include <fuchsia/mem/cpp/fidl.h>
8 #include <lib/async/cpp/task.h>
9 #include <lib/trace-engine/instrumentation.h>
10 #include <zircon/status.h>
11 #include <zircon/types.h>
12
13 #include <sstream>
14 #include <utility>
15
16 #include "flutter/fml/make_copyable.h"
17 #include "flutter/lib/ui/text/font_collection.h"
18 #include "flutter/runtime/dart_vm.h"
19 #include "runtime/dart/utils/vmo.h"
20 #include "runtime/dart/utils/vmservice_object.h"
21 #include "third_party/icu/source/common/unicode/udata.h"
22 #include "third_party/skia/include/core/SkGraphics.h"
23
24 namespace flutter_runner {
25
26 namespace {
27
28 static constexpr char kIcuDataPath[] = "/pkg/data/icudtl.dat";
29
30 // Map the memory into the process and return a pointer to the memory.
GetICUData(const fuchsia::mem::Buffer & icu_data)31 uintptr_t GetICUData(const fuchsia::mem::Buffer& icu_data) {
32 uint64_t data_size = icu_data.size;
33 if (data_size > std::numeric_limits<size_t>::max())
34 return 0u;
35
36 uintptr_t data = 0u;
37 zx_status_t status = zx::vmar::root_self()->map(
38 0, icu_data.vmo, 0, static_cast<size_t>(data_size), ZX_VM_PERM_READ,
39 &data);
40 if (status == ZX_OK) {
41 return data;
42 }
43
44 return 0u;
45 }
46
47 // Return value indicates if initialization was successful.
InitializeICU()48 bool InitializeICU() {
49 const char* data_path = kIcuDataPath;
50
51 fuchsia::mem::Buffer icu_data;
52 if (!dart_utils::VmoFromFilename(data_path, &icu_data)) {
53 return false;
54 }
55
56 uintptr_t data = GetICUData(icu_data);
57 if (!data) {
58 return false;
59 }
60
61 // Pass the data to ICU.
62 UErrorCode err = U_ZERO_ERROR;
63 udata_setCommonData(reinterpret_cast<const char*>(data), &err);
64 return err == U_ZERO_ERROR;
65 }
66
67 } // namespace
68
SetProcessName()69 static void SetProcessName() {
70 std::stringstream stream;
71 #if defined(DART_PRODUCT)
72 stream << "io.flutter.product_runner.";
73 #else
74 stream << "io.flutter.runner.";
75 #endif
76 if (flutter::DartVM::IsRunningPrecompiledCode()) {
77 stream << "aot";
78 } else {
79 stream << "jit";
80 }
81 const auto name = stream.str();
82 zx::process::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size());
83 }
84
SetThreadName(const std::string & thread_name)85 static void SetThreadName(const std::string& thread_name) {
86 zx::thread::self()->set_property(ZX_PROP_NAME, thread_name.c_str(),
87 thread_name.size());
88 }
89
Runner(async::Loop * loop)90 Runner::Runner(async::Loop* loop)
91 : loop_(loop), runner_context_(RunnerContext::CreateFromStartupInfo()) {
92 #if !defined(DART_PRODUCT)
93 // The VM service isolate uses the process-wide namespace. It writes the
94 // vm service protocol port under /tmp. The VMServiceObject exposes that
95 // port number to The Hub.
96 runner_context_->debug_dir()->AddEntry(
97 dart_utils::VMServiceObject::kPortDirName,
98 std::make_unique<dart_utils::VMServiceObject>());
99
100 SetupTraceObserver();
101 #endif // !defined(DART_PRODUCT)
102
103 SkGraphics::Init();
104
105 SetupICU();
106
107 SetProcessName();
108
109 SetThreadName("io.flutter.runner.main");
110
111 runner_context_->AddPublicService<fuchsia::sys::Runner>(
112 std::bind(&Runner::RegisterApplication, this, std::placeholders::_1));
113 }
114
~Runner()115 Runner::~Runner() {
116 runner_context_->RemovePublicService<fuchsia::sys::Runner>();
117
118 #if !defined(DART_PRODUCT)
119 trace_observer_->Stop();
120 #endif // !defined(DART_PRODUCT)
121 }
122
RegisterApplication(fidl::InterfaceRequest<fuchsia::sys::Runner> request)123 void Runner::RegisterApplication(
124 fidl::InterfaceRequest<fuchsia::sys::Runner> request) {
125 active_applications_bindings_.AddBinding(this, std::move(request));
126 }
127
StartComponent(fuchsia::sys::Package package,fuchsia::sys::StartupInfo startup_info,fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller)128 void Runner::StartComponent(
129 fuchsia::sys::Package package,
130 fuchsia::sys::StartupInfo startup_info,
131 fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
132 // TRACE_DURATION currently requires that the string data does not change
133 // in the traced scope. Since |package| gets moved in the Application::Create
134 // call below, we cannot ensure that |package.resolved_url| does not move or
135 // change, so we make a copy to pass to TRACE_DURATION.
136 // TODO(PT-169): Remove this copy when TRACE_DURATION reads string arguments
137 // eagerly.
138 std::string url_copy = package.resolved_url;
139 TRACE_EVENT1("flutter", "StartComponent", "url", url_copy.c_str());
140 // Notes on application termination: Application typically terminate on the
141 // thread on which they were created. This usually means the thread was
142 // specifically created to host the application. But we want to ensure that
143 // access to the active applications collection is made on the same thread. So
144 // we capture the runner in the termination callback. There is no risk of
145 // there being multiple application runner instance in the process at the same
146 // time. So it is safe to use the raw pointer.
147 Application::TerminationCallback termination_callback =
148 [task_runner = loop_->dispatcher(), //
149 application_runner = this //
150 ](const Application* application) {
151 async::PostTask(task_runner, [application_runner, application]() {
152 application_runner->OnApplicationTerminate(application);
153 });
154 };
155
156 auto thread_application_pair = Application::Create(
157 std::move(termination_callback), // termination callback
158 std::move(package), // application package
159 std::move(startup_info), // startup info
160 runner_context_->svc(), // runner incoming services
161 std::move(controller) // controller request
162 );
163
164 auto key = thread_application_pair.second.get();
165
166 active_applications_[key] = std::move(thread_application_pair);
167 }
168
OnApplicationTerminate(const Application * application)169 void Runner::OnApplicationTerminate(const Application* application) {
170 auto app = active_applications_.find(application);
171 if (app == active_applications_.end()) {
172 FML_LOG(INFO)
173 << "The remote end of the application runner tried to terminate an "
174 "application that has already been terminated, possibly because we "
175 "initiated the termination";
176 return;
177 }
178 auto& active_application = app->second;
179
180 // Grab the items out of the entry because we will have to rethread the
181 // destruction.
182 auto application_to_destroy = std::move(active_application.application);
183 auto application_thread = std::move(active_application.thread);
184
185 // Delegate the entry.
186 active_applications_.erase(application);
187
188 // Post the task to destroy the application and quit its message loop.
189 async::PostTask(
190 application_thread->dispatcher(),
191 fml::MakeCopyable([instance = std::move(application_to_destroy),
192 thread = application_thread.get()]() mutable {
193 instance.reset();
194 thread->Quit();
195 }));
196
197 // This works because just posted the quit task on the hosted thread.
198 application_thread->Join();
199 }
200
SetupICU()201 void Runner::SetupICU() {
202 if (!InitializeICU()) {
203 FML_LOG(ERROR) << "Could not initialize ICU data.";
204 }
205 }
206
207 #if !defined(DART_PRODUCT)
SetupTraceObserver()208 void Runner::SetupTraceObserver() {
209 trace_observer_ = std::make_unique<trace::TraceObserver>();
210 trace_observer_->Start(loop_->dispatcher(), [runner = this]() {
211 if (!trace_is_category_enabled("dart:profiler")) {
212 return;
213 }
214 if (trace_state() == TRACE_STARTED) {
215 runner->prolonged_context_ = trace_acquire_prolonged_context();
216 Dart_StartProfiling();
217 } else if (trace_state() == TRACE_STOPPING) {
218 for (auto& it : runner->active_applications_) {
219 fml::AutoResetWaitableEvent latch;
220 async::PostTask(it.second.thread->dispatcher(), [&]() {
221 it.second.application->WriteProfileToTrace();
222 latch.Signal();
223 });
224 latch.Wait();
225 }
226 Dart_StopProfiling();
227 trace_release_prolonged_context(runner->prolonged_context_);
228 }
229 });
230 }
231 #endif // !defined(DART_PRODUCT)
232
233 } // namespace flutter_runner
234