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  fml::MakeRefCounted<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  fml::MakeRefCounted<PlatformMessage>(
133  name, std::vector<uint8_t>(buffer, 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 Dart_Handle ToByteData(const std::vector<uint8_t>& buffer) {
185  return tonic::DartByteData::Create(buffer.data(), buffer.size());
186 }
187 
188 } // namespace
189 
191 
194  : client_(client) {}
195 
197 
199  library_.Set(tonic::DartState::Current(),
200  Dart_LookupLibrary(tonic::ToDart("dart:ui")));
201  windows_.insert(std::make_pair(0, std::unique_ptr<Window>(new Window{
202  0, ViewportMetrics{1.0, 0.0, 0.0}})));
203 }
204 
206  const std::vector<std::string>& locales) {
207  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
208  if (!dart_state) {
209  return;
210  }
211  tonic::DartState::Scope scope(dart_state);
213  library_.value(), "_updateLocales",
214  {
215  tonic::ToDart<std::vector<std::string>>(locales),
216  }));
217 }
218 
219 void PlatformConfiguration::UpdateUserSettingsData(const std::string& data) {
220  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
221  if (!dart_state) {
222  return;
223  }
224  tonic::DartState::Scope scope(dart_state);
225 
227  "_updateUserSettingsData",
228  {
230  }));
231 }
232 
233 void PlatformConfiguration::UpdateLifecycleState(const std::string& data) {
234  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
235  if (!dart_state) {
236  return;
237  }
238  tonic::DartState::Scope scope(dart_state);
240  "_updateLifecycleState",
241  {
243  }));
244 }
245 
247  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
248  if (!dart_state) {
249  return;
250  }
251  tonic::DartState::Scope scope(dart_state);
253 
255  library_.value(), "_updateSemanticsEnabled", {tonic::ToDart(enabled)}));
256 }
257 
259  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
260  if (!dart_state) {
261  return;
262  }
263  tonic::DartState::Scope scope(dart_state);
264 
266  "_updateAccessibilityFeatures",
267  {tonic::ToDart(values)}));
268 }
269 
272  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
273  if (!dart_state) {
274  FML_DLOG(WARNING)
275  << "Dropping platform message for lack of DartState on channel: "
276  << message->channel();
277  return;
278  }
279  tonic::DartState::Scope scope(dart_state);
280  Dart_Handle data_handle =
281  (message->hasData()) ? ToByteData(message->data()) : Dart_Null();
282  if (Dart_IsError(data_handle)) {
283  FML_DLOG(WARNING)
284  << "Dropping platform message because of a Dart error on channel: "
285  << message->channel();
286  return;
287  }
288 
289  int response_id = 0;
290  if (auto response = message->response()) {
291  response_id = next_response_id_++;
292  pending_responses_[response_id] = response;
293  }
294 
296  tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage",
297  {tonic::ToDart(message->channel()), data_handle,
298  tonic::ToDart(response_id)}));
299 }
300 
303  std::vector<uint8_t> args) {
304  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
305  if (!dart_state) {
306  return;
307  }
308  tonic::DartState::Scope scope(dart_state);
309 
310  Dart_Handle args_handle = (args.empty()) ? Dart_Null() : ToByteData(args);
311 
312  if (Dart_IsError(args_handle)) {
313  return;
314  }
315 
317  library_.value(), "_dispatchSemanticsAction",
318  {tonic::ToDart(id), tonic::ToDart(static_cast<int32_t>(action)),
319  args_handle}));
320 }
321 
323  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
324  if (!dart_state) {
325  return;
326  }
327  tonic::DartState::Scope scope(dart_state);
328 
329  int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();
330 
331  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame",
332  {
333  Dart_NewInteger(microseconds),
334  }));
335 
337 
338  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {}));
339 }
340 
341 void PlatformConfiguration::ReportTimings(std::vector<int64_t> timings) {
342  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
343  if (!dart_state) {
344  return;
345  }
346  tonic::DartState::Scope scope(dart_state);
347 
348  Dart_Handle data_handle =
349  Dart_NewTypedData(Dart_TypedData_kInt64, timings.size());
350 
351  Dart_TypedData_Type type;
352  void* data = nullptr;
353  intptr_t num_acquired = 0;
354  FML_CHECK(!Dart_IsError(
355  Dart_TypedDataAcquireData(data_handle, &type, &data, &num_acquired)));
356  FML_DCHECK(num_acquired == static_cast<int>(timings.size()));
357 
358  memcpy(data, timings.data(), sizeof(int64_t) * timings.size());
359  FML_CHECK(Dart_TypedDataReleaseData(data_handle));
360 
361  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_reportTimings",
362  {
363  data_handle,
364  }));
365 }
366 
368  int response_id) {
369  if (!response_id) {
370  return;
371  }
372  auto it = pending_responses_.find(response_id);
373  if (it == pending_responses_.end()) {
374  return;
375  }
376  auto response = std::move(it->second);
377  pending_responses_.erase(it);
378  response->CompleteEmpty();
379 }
380 
382  int response_id,
383  std::vector<uint8_t> data) {
384  if (!response_id) {
385  return;
386  }
387  auto it = pending_responses_.find(response_id);
388  if (it == pending_responses_.end()) {
389  return;
390  }
391  auto response = std::move(it->second);
392  pending_responses_.erase(it);
393  response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
394 }
395 
396 Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle) {
397  std::vector<std::string> supportedLocales =
399  supportedLocalesHandle);
400 
401  std::vector<std::string> results =
404  ->client()
405  ->ComputePlatformResolvedLocale(supportedLocales);
406 
408 }
409 
410 static void _ComputePlatformResolvedLocale(Dart_NativeArguments args) {
412  Dart_Handle result =
413  ComputePlatformResolvedLocale(Dart_GetNativeArgument(args, 1));
414  Dart_SetReturnValue(args, result);
415 }
416 
418  tonic::DartLibraryNatives* natives) {
419  natives->Register({
420  {"PlatformConfiguration_defaultRouteName", DefaultRouteName, 1, true},
421  {"PlatformConfiguration_scheduleFrame", ScheduleFrame, 1, true},
422  {"PlatformConfiguration_sendPlatformMessage", _SendPlatformMessage, 4,
423  true},
424  {"PlatformConfiguration_respondToPlatformMessage",
425  _RespondToPlatformMessage, 3, true},
426  {"PlatformConfiguration_render", Render, 3, true},
427  {"PlatformConfiguration_updateSemantics", UpdateSemantics, 2, true},
428  {"PlatformConfiguration_setIsolateDebugName", SetIsolateDebugName, 2,
429  true},
430  {"PlatformConfiguration_reportUnhandledException",
431  ReportUnhandledException, 2, true},
432  {"PlatformConfiguration_setNeedsReportTimings", SetNeedsReportTimings, 2,
433  true},
434  {"PlatformConfiguration_getPersistentIsolateData",
435  GetPersistentIsolateData, 1, true},
436  {"PlatformConfiguration_computePlatformResolvedLocale",
438  });
439 }
440 
441 } // 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.
void BeginFrame(fml::TimePoint frame_time)
Notifies the framework that it is time to begin working on a new frame previously scheduled via a cal...
G_BEGIN_DECLS FlValue * args
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
void DartCallStatic(Sig func, Dart_NativeArguments args)
Definition: dart_args.h:208
Dart_PersistentHandle value() const
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 GPU 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 GPU 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.
static DartState * Current()
Definition: dart_state.cc:55
void DispatchPlatformMessage(fml::RefPtr< PlatformMessage > message)
Notifies the PlatformConfiguration that the client has sent it a message. This call originates in the...
void SetDebugName(const std::string name)
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.
Dart_Handle DartInvokeField(Dart_Handle target, const char *name, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:12
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.
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
Definition: ui_dart_state.h:48
void UpdateLifecycleState(const std::string &data)
Updates the lifecycle state data in the framework.
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
virtual void UpdateSemantics(SemanticsUpdate *update)=0
Receives a updated semantics tree from the Framework.
#define FML_DLOG(severity)
Definition: logging.h:85
void DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector< uint8_t > args)
Notifies the framework that the embedder encountered an accessibility related action on the specified...
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)
void UpdateUserSettingsData(const std::string &data)
Update the user settings data in the framework.
static UIDartState * Current()