Flutter Engine
platform_configuration.cc
Go to the documentation of this file.
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/lib/ui/window/platform_configuration.h"
6 
7 #include <cstring>
8 
9 #include "flutter/lib/ui/compositing/scene.h"
10 #include "flutter/lib/ui/ui_dart_state.h"
11 #include "flutter/lib/ui/window/platform_message_response_dart.h"
12 #include "flutter/lib/ui/window/viewport_metrics.h"
13 #include "flutter/lib/ui/window/window.h"
20 
21 namespace flutter {
22 namespace {
23 
24 void DefaultRouteName(Dart_NativeArguments args) {
26  std::string routeName = UIDartState::Current()
28  ->client()
29  ->DefaultRouteName();
30  Dart_SetReturnValue(args, tonic::StdStringToDart(routeName));
31 }
32 
33 void ScheduleFrame(Dart_NativeArguments args) {
36 }
37 
38 void Render(Dart_NativeArguments args) {
40  Dart_Handle exception = nullptr;
41  Scene* scene =
43  if (exception) {
44  Dart_ThrowException(exception);
45  return;
46  }
48 }
49 
50 void UpdateSemantics(Dart_NativeArguments args) {
52  Dart_Handle exception = nullptr;
53  SemanticsUpdate* update =
55  if (exception) {
56  Dart_ThrowException(exception);
57  return;
58  }
60  update);
61 }
62 
63 void SetIsolateDebugName(Dart_NativeArguments args) {
65  Dart_Handle exception = nullptr;
66  const std::string name =
68  if (exception) {
69  Dart_ThrowException(exception);
70  return;
71  }
73 }
74 
75 void SetNeedsReportTimings(Dart_NativeArguments args) {
77  Dart_Handle exception = nullptr;
78  bool value = tonic::DartConverter<bool>::FromArguments(args, 1, exception);
81  ->client()
82  ->SetNeedsReportTimings(value);
83 }
84 
85 void ReportUnhandledException(Dart_NativeArguments args) {
87 
88  Dart_Handle exception = nullptr;
89 
90  auto error_name =
92  if (exception) {
93  Dart_ThrowException(exception);
94  return;
95  }
96 
97  auto stack_trace =
99  if (exception) {
100  Dart_ThrowException(exception);
101  return;
102  }
103 
104  UIDartState::Current()->ReportUnhandledException(std::move(error_name),
105  std::move(stack_trace));
106 }
107 
108 Dart_Handle SendPlatformMessage(Dart_Handle window,
109  const std::string& name,
110  Dart_Handle callback,
111  Dart_Handle data_handle) {
112  UIDartState* dart_state = UIDartState::Current();
113 
114  if (!dart_state->platform_configuration()) {
115  return tonic::ToDart(
116  "Platform messages can only be sent from the main isolate");
117  }
118 
120  if (!Dart_IsNull(callback)) {
121  response = fml::MakeRefCounted<PlatformMessageResponseDart>(
122  tonic::DartPersistentValue(dart_state, callback),
123  dart_state->GetTaskRunners().GetUITaskRunner());
124  }
125  if (Dart_IsNull(data_handle)) {
126  dart_state->platform_configuration()->client()->HandlePlatformMessage(
127  std::make_unique<PlatformMessage>(name, response));
128  } else {
129  tonic::DartByteData data(data_handle);
130  const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
131  dart_state->platform_configuration()->client()->HandlePlatformMessage(
132  std::make_unique<PlatformMessage>(
133  name, fml::MallocMapping::Copy(buffer, data.length_in_bytes()),
134  response));
135  }
136 
137  return Dart_Null();
138 }
139 
140 void _SendPlatformMessage(Dart_NativeArguments args) {
141  tonic::DartCallStatic(&SendPlatformMessage, args);
142 }
143 
144 void RespondToPlatformMessage(Dart_Handle window,
145  int response_id,
146  const tonic::DartByteData& data) {
147  if (Dart_IsNull(data.dart_handle())) {
151  } else {
152  // TODO(engine): Avoid this copy.
153  const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
157  response_id,
158  std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()));
159  }
160 }
161 
162 void _RespondToPlatformMessage(Dart_NativeArguments args) {
163  tonic::DartCallStatic(&RespondToPlatformMessage, args);
164 }
165 
166 void GetPersistentIsolateData(Dart_NativeArguments args) {
168 
169  auto persistent_isolate_data = UIDartState::Current()
171  ->client()
173 
174  if (!persistent_isolate_data) {
175  Dart_SetReturnValue(args, Dart_Null());
176  return;
177  }
178 
179  Dart_SetReturnValue(
180  args, tonic::DartByteData::Create(persistent_isolate_data->GetMapping(),
181  persistent_isolate_data->GetSize()));
182 }
183 
184 void RespondToKeyData(Dart_Handle window, int response_id, bool handled) {
186  response_id, handled);
187 }
188 
189 void _RespondToKeyData(Dart_NativeArguments args) {
190  tonic::DartCallStatic(&RespondToKeyData, args);
191 }
192 
193 Dart_Handle ToByteData(const fml::Mapping& buffer) {
194  return tonic::DartByteData::Create(buffer.GetMapping(), buffer.GetSize());
195 }
196 
197 } // namespace
198 
200 
203  : client_(client) {}
204 
206 
208  Dart_Handle library = Dart_LookupLibrary(tonic::ToDart("dart:ui"));
209  update_locales_.Set(tonic::DartState::Current(),
210  Dart_GetField(library, tonic::ToDart("_updateLocales")));
211  update_user_settings_data_.Set(
213  Dart_GetField(library, tonic::ToDart("_updateUserSettingsData")));
214  update_lifecycle_state_.Set(
216  Dart_GetField(library, tonic::ToDart("_updateLifecycleState")));
217  update_semantics_enabled_.Set(
219  Dart_GetField(library, tonic::ToDart("_updateSemanticsEnabled")));
220  update_accessibility_features_.Set(
222  Dart_GetField(library, tonic::ToDart("_updateAccessibilityFeatures")));
223  dispatch_platform_message_.Set(
225  Dart_GetField(library, tonic::ToDart("_dispatchPlatformMessage")));
226  dispatch_semantics_action_.Set(
228  Dart_GetField(library, tonic::ToDart("_dispatchSemanticsAction")));
229  begin_frame_.Set(tonic::DartState::Current(),
230  Dart_GetField(library, tonic::ToDart("_beginFrame")));
231  draw_frame_.Set(tonic::DartState::Current(),
232  Dart_GetField(library, tonic::ToDart("_drawFrame")));
233  report_timings_.Set(tonic::DartState::Current(),
234  Dart_GetField(library, tonic::ToDart("_reportTimings")));
235  windows_.insert(
236  std::make_pair(0, std::unique_ptr<Window>(new Window{
237  0, ViewportMetrics{1.0, 0.0, 0.0, -1}})));
238 }
239 
241  const std::vector<std::string>& locales) {
242  std::shared_ptr<tonic::DartState> dart_state =
243  update_locales_.dart_state().lock();
244  if (!dart_state) {
245  return;
246  }
247 
248  tonic::DartState::Scope scope(dart_state);
250  tonic::DartInvoke(update_locales_.Get(),
251  {
252  tonic::ToDart<std::vector<std::string>>(locales),
253  }));
254 }
255 
256 void PlatformConfiguration::UpdateUserSettingsData(const std::string& data) {
257  std::shared_ptr<tonic::DartState> dart_state =
258  update_user_settings_data_.dart_state().lock();
259  if (!dart_state) {
260  return;
261  }
262  tonic::DartState::Scope scope(dart_state);
263 
264  tonic::LogIfError(tonic::DartInvoke(update_user_settings_data_.Get(),
265  {
267  }));
268 }
269 
270 void PlatformConfiguration::UpdateLifecycleState(const std::string& data) {
271  std::shared_ptr<tonic::DartState> dart_state =
272  update_lifecycle_state_.dart_state().lock();
273  if (!dart_state) {
274  return;
275  }
276  tonic::DartState::Scope scope(dart_state);
277  tonic::LogIfError(tonic::DartInvoke(update_lifecycle_state_.Get(),
278  {
280  }));
281 }
282 
284  std::shared_ptr<tonic::DartState> dart_state =
285  update_semantics_enabled_.dart_state().lock();
286  if (!dart_state) {
287  return;
288  }
289  tonic::DartState::Scope scope(dart_state);
291 
292  tonic::LogIfError(tonic::DartInvoke(update_semantics_enabled_.Get(),
293  {tonic::ToDart(enabled)}));
294 }
295 
297  std::shared_ptr<tonic::DartState> dart_state =
298  update_accessibility_features_.dart_state().lock();
299  if (!dart_state) {
300  return;
301  }
302  tonic::DartState::Scope scope(dart_state);
303 
304  tonic::LogIfError(tonic::DartInvoke(update_accessibility_features_.Get(),
305  {tonic::ToDart(values)}));
306 }
307 
309  std::unique_ptr<PlatformMessage> message) {
310  std::shared_ptr<tonic::DartState> dart_state =
311  dispatch_platform_message_.dart_state().lock();
312  if (!dart_state) {
313  FML_DLOG(WARNING)
314  << "Dropping platform message for lack of DartState on channel: "
315  << message->channel();
316  return;
317  }
318  tonic::DartState::Scope scope(dart_state);
319  Dart_Handle data_handle =
320  (message->hasData()) ? ToByteData(message->data()) : Dart_Null();
321  if (Dart_IsError(data_handle)) {
322  FML_DLOG(WARNING)
323  << "Dropping platform message because of a Dart error on channel: "
324  << message->channel();
325  return;
326  }
327 
328  int response_id = 0;
329  if (auto response = message->response()) {
330  response_id = next_response_id_++;
331  pending_responses_[response_id] = response;
332  }
333 
335  tonic::DartInvoke(dispatch_platform_message_.Get(),
336  {tonic::ToDart(message->channel()), data_handle,
337  tonic::ToDart(response_id)}));
338 }
339 
342  fml::MallocMapping args) {
343  std::shared_ptr<tonic::DartState> dart_state =
344  dispatch_semantics_action_.dart_state().lock();
345  if (!dart_state) {
346  return;
347  }
348  tonic::DartState::Scope scope(dart_state);
349 
350  Dart_Handle args_handle =
351  (args.GetSize() <= 0) ? Dart_Null() : ToByteData(args);
352 
353  if (Dart_IsError(args_handle)) {
354  return;
355  }
356 
358  dispatch_semantics_action_.Get(),
359  {tonic::ToDart(id), tonic::ToDart(static_cast<int32_t>(action)),
360  args_handle}));
361 }
362 
364  KeyDataResponse callback) {
365  uint64_t response_id = next_key_response_id_++;
366  pending_key_responses_[response_id] = std::move(callback);
367  return response_id;
368 }
369 
371  uint64_t frame_number) {
372  std::shared_ptr<tonic::DartState> dart_state =
373  begin_frame_.dart_state().lock();
374  if (!dart_state) {
375  return;
376  }
377  tonic::DartState::Scope scope(dart_state);
378 
379  int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();
380 
382  tonic::DartInvoke(begin_frame_.Get(), {
383  Dart_NewInteger(microseconds),
384  Dart_NewInteger(frame_number),
385  }));
386 
388 
390 }
391 
392 void PlatformConfiguration::ReportTimings(std::vector<int64_t> timings) {
393  std::shared_ptr<tonic::DartState> dart_state =
394  report_timings_.dart_state().lock();
395  if (!dart_state) {
396  return;
397  }
398  tonic::DartState::Scope scope(dart_state);
399 
400  Dart_Handle data_handle =
401  Dart_NewTypedData(Dart_TypedData_kInt64, timings.size());
402 
403  Dart_TypedData_Type type;
404  void* data = nullptr;
405  intptr_t num_acquired = 0;
406  FML_CHECK(!Dart_IsError(
407  Dart_TypedDataAcquireData(data_handle, &type, &data, &num_acquired)));
408  FML_DCHECK(num_acquired == static_cast<int>(timings.size()));
409 
410  memcpy(data, timings.data(), sizeof(int64_t) * timings.size());
411  FML_CHECK(Dart_TypedDataReleaseData(data_handle));
412 
413  tonic::LogIfError(tonic::DartInvoke(report_timings_.Get(), {
414  data_handle,
415  }));
416 }
417 
419  int response_id) {
420  if (!response_id) {
421  return;
422  }
423  auto it = pending_responses_.find(response_id);
424  if (it == pending_responses_.end()) {
425  return;
426  }
427  auto response = std::move(it->second);
428  pending_responses_.erase(it);
429  response->CompleteEmpty();
430 }
431 
433  int response_id,
434  std::vector<uint8_t> data) {
435  if (!response_id) {
436  return;
437  }
438  auto it = pending_responses_.find(response_id);
439  if (it == pending_responses_.end()) {
440  return;
441  }
442  auto response = std::move(it->second);
443  pending_responses_.erase(it);
444  response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
445 }
446 
448  bool handled) {
449  if (response_id == 0) {
450  return;
451  }
452  auto it = pending_key_responses_.find(response_id);
453  FML_DCHECK(it != pending_key_responses_.end());
454  if (it == pending_key_responses_.end()) {
455  return;
456  }
457  KeyDataResponse callback = std::move(it->second);
458  pending_key_responses_.erase(it);
459  // The key result callback must be called on the platform thread. This is
460  // mainly because iOS needs to block the platform message loop with a nested
461  // loop to respond to key events synchronously, and if the callback is called
462  // from another thread, it won't stop the nested message loop, causing a
463  // deadlock.
465  [handled, callback]() { callback(handled); });
466 }
467 
468 Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle) {
469  std::vector<std::string> supportedLocales =
471  supportedLocalesHandle);
472 
473  std::vector<std::string> results =
476  ->client()
477  ->ComputePlatformResolvedLocale(supportedLocales);
478 
480 }
481 
482 static void _ComputePlatformResolvedLocale(Dart_NativeArguments args) {
484  Dart_Handle result =
485  ComputePlatformResolvedLocale(Dart_GetNativeArgument(args, 1));
486  Dart_SetReturnValue(args, result);
487 }
488 
490  tonic::DartLibraryNatives* natives) {
491  natives->Register({
492  {"PlatformConfiguration_defaultRouteName", DefaultRouteName, 1, true},
493  {"PlatformConfiguration_scheduleFrame", ScheduleFrame, 1, true},
494  {"PlatformConfiguration_sendPlatformMessage", _SendPlatformMessage, 4,
495  true},
496  {"PlatformConfiguration_respondToPlatformMessage",
497  _RespondToPlatformMessage, 3, true},
498  {"PlatformConfiguration_respondToKeyData", _RespondToKeyData, 3, true},
499  {"PlatformConfiguration_render", Render, 3, true},
500  {"PlatformConfiguration_updateSemantics", UpdateSemantics, 2, true},
501  {"PlatformConfiguration_setIsolateDebugName", SetIsolateDebugName, 2,
502  true},
503  {"PlatformConfiguration_reportUnhandledException",
504  ReportUnhandledException, 2, true},
505  {"PlatformConfiguration_setNeedsReportTimings", SetNeedsReportTimings, 2,
506  true},
507  {"PlatformConfiguration_getPersistentIsolateData",
508  GetPersistentIsolateData, 1, true},
509  {"PlatformConfiguration_computePlatformResolvedLocale",
511  });
512 }
513 
514 } // namespace flutter
static void RegisterNatives(tonic::DartLibraryNatives *natives)
Registers the native handlers for Dart functions that this class handles.
PlatformConfigurationClient * client() const
Access to the platform configuration client (which typically is implemented by the RuntimeController)...
PlatformConfiguration(PlatformConfigurationClient *client)
Creates a new PlatformConfiguration, typically created by the RuntimeController.
virtual void Complete(std::unique_ptr< fml::Mapping > data)=0
G_BEGIN_DECLS FlValue * args
KeyCallType type
void ReportUnhandledException(const std::string &error, const std::string &stack_trace)
const void * data() const
virtual std::unique_ptr< std::vector< std::string > > ComputePlatformResolvedLocale(const std::vector< std::string > &supported_locale_data)=0
Directly invokes platform-specific APIs to compute the locale the platform would have natively resolv...
#define FML_DCHECK(condition)
Definition: logging.h:86
virtual size_t GetSize() const =0
void DartCallStatic(Sig func, Dart_NativeArguments args)
Definition: dart_args.h:208
void Set(DartState *dart_state, Dart_Handle value)
void ReportTimings(std::vector< int64_t > timings)
Dart code cannot fully measure the time it takes for a specific frame to be rendered. This is because Dart code only runs on the UI task runner. That is only a small part of the overall frame workload. The raster task runner frame workload is executed on a thread where Dart code cannot run (and hence instrument). Besides, due to the pipelined nature of rendering in Flutter, there may be multiple frame workloads being processed at any given time. However, for non-Timeline based profiling, it is useful for trace collection and processing to happen in Dart. To do this, the raster task runner frame workloads need to be instrumented separately. After a set number of these profiles have been gathered, they need to be reported back to Dart code. The engine reports this extra instrumentation information back to the framework by invoking this method at predefined intervals.
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
static DartState * Current()
Definition: dart_state.cc:56
GAsyncResult * result
virtual const uint8_t * GetMapping() const =0
void SetDebugName(const std::string name)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
virtual void ScheduleFrame()=0
Requests that, at the next appropriate opportunity, a new frame be scheduled for rendering.
virtual std::shared_ptr< const fml::Mapping > GetPersistentIsolateData()=0
The embedder can specify data that the isolate can request synchronously on launch. This accessor fetches that data.
FlKeyEvent FlKeyResponderAsyncCallback callback
uint64_t RegisterKeyDataResponse(KeyDataResponse callback)
Registers a callback to be invoked when the framework has decided whether to handle an event...
A client interface that the RuntimeController uses to define handlers for PlatformConfiguration reque...
void CompletePlatformMessageEmptyResponse(int response_id)
Responds to a previous platform message to the engine from the framework with an empty response...
void CompletePlatformMessageResponse(int response_id, std::vector< uint8_t > data)
Responds to a previous platform message to the engine from the framework.
uint8_t value
virtual std::string DefaultRouteName()=0
The route or path that the embedder requested when the application was launched.
void CompleteKeyDataResponse(uint64_t response_id, bool handled)
Responds to a previously registered key data message from the framework to the engine.
size_t GetSize() const override
Definition: mapping.cc:129
void DispatchSemanticsAction(int32_t id, SemanticsAction action, fml::MallocMapping args)
Notifies the framework that the embedder encountered an accessibility related action on the specified...
size_t length_in_bytes() const
static void _ComputePlatformResolvedLocale(Dart_NativeArguments args)
virtual void Render(Scene *scene)=0
Updates the client&#39;s rendering on the GPU with the newly provided Scene.
SemanticsAction action
Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle)
void Register(std::initializer_list< Entry > entries)
void UpdateLocales(const std::vector< std::string > &locales)
Update the specified locale data in the framework.
const std::weak_ptr< DartState > & dart_state() const
static void ThrowIfUIOperationsProhibited()
PlatformConfiguration * platform_configuration() const
void UpdateLifecycleState(const std::string &data)
Updates the lifecycle state data in the framework.
void BeginFrame(fml::TimePoint frame_time, uint64_t frame_number)
Notifies the framework that it is time to begin working on a new frame previously scheduled via a cal...
static MallocMapping Copy(const T *begin, const T *end)
Definition: mapping.h:147
void UpdateSemanticsEnabled(bool enabled)
Notifies the PlatformConfiguration that the embedder has expressed an opinion about whether the acces...
void DidCreateIsolate()
Called by the RuntimeController once it has created the root isolate, so that the PlatformController ...
virtual void SetNeedsReportTimings(bool value)=0
Notifies this client that the application has an opinion about whether its frame timings need to be r...
const char * name
Definition: fuchsia.cc:50
#define FML_CHECK(condition)
Definition: logging.h:68
Dart_Handle dart_handle() const
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition: mapping.h:129
void DispatchPlatformMessage(std::unique_ptr< PlatformMessage > message)
Notifies the PlatformConfiguration that the client has sent it a message. This call originates in the...
static const uint8_t buffer[]
std::function< void(bool)> KeyDataResponse
const TaskRunners & GetTaskRunners() const
virtual void UpdateSemantics(SemanticsUpdate *update)=0
Receives a updated semantics tree from the Framework.
#define FML_DLOG(severity)
Definition: logging.h:85
static Dart_Handle Create(const void *data, size_t length)
void UpdateAccessibilityFeatures(int32_t flags)
Forward the preference of accessibility features that must be enabled in the semantics tree to the fr...
Dart_Handle ToDart(const T &object)
bool LogIfError(Dart_Handle handle)
Definition: dart_error.cc:15
Dart_Handle StdStringToDart(const std::string &val)
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
Dart_Handle DartInvokeVoid(Dart_Handle closure)
Definition: dart_invoke.cc:29
void UpdateUserSettingsData(const std::string &data)
Update the user settings data in the framework.
static UIDartState * Current()