• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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