Flutter Engine
 
Loading...
Searching...
No Matches
platform_configuration_unittests.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#define FML_USED_ON_EMBEDDER
6
7#include <cstddef>
8#include <memory>
9
18#include "gmock/gmock.h"
19#include "googletest/googletest/include/gtest/gtest.h"
20#include "third_party/dart/runtime/include/dart_api.h"
22
23namespace flutter {
24namespace testing {
25
27
29 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
30
31 auto nativeValidateConfiguration =
32 [message_latch](Dart_NativeArguments args) {
33 PlatformConfiguration* configuration =
35 ASSERT_NE(configuration->GetMetrics(0), nullptr);
36 ASSERT_EQ(configuration->GetMetrics(0)->device_pixel_ratio, 1.0);
37 ASSERT_EQ(configuration->GetMetrics(0)->physical_width, 0.0);
38 ASSERT_EQ(configuration->GetMetrics(0)->physical_height, 0.0);
39
40 message_latch->Signal();
41 };
42
43 Settings settings = CreateSettingsForFixture();
44 TaskRunners task_runners("test", // label
45 GetCurrentTaskRunner(), // platform
46 CreateNewThread(), // raster
47 CreateNewThread(), // ui
48 CreateNewThread() // io
49 );
50
51 AddNativeCallback("ValidateConfiguration",
52 CREATE_NATIVE_ENTRY(nativeValidateConfiguration));
53
54 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
55
56 ASSERT_TRUE(shell->IsSetup());
57 auto run_configuration = RunConfiguration::InferFromSettings(settings);
58 run_configuration.SetEntrypoint("validateConfiguration");
59
60 shell->RunEngine(std::move(run_configuration), [&](auto result) {
61 ASSERT_EQ(result, Engine::RunStatus::Success);
62 });
63
64 message_latch->Wait();
65 DestroyShell(std::move(shell), task_runners);
66}
67
68TEST_F(PlatformConfigurationTest, WindowMetricsUpdate) {
69 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
70
71 auto nativeValidateConfiguration =
72 [message_latch](Dart_NativeArguments args) {
73 PlatformConfiguration* configuration =
75
76 ASSERT_NE(configuration->GetMetrics(0), nullptr);
77 bool has_view = configuration->UpdateViewMetrics(
78 0, ViewportMetrics{2.0, 10.0, 20.0, 22, 0});
79 ASSERT_TRUE(has_view);
80 ASSERT_EQ(configuration->GetMetrics(0)->device_pixel_ratio, 2.0);
81 ASSERT_EQ(configuration->GetMetrics(0)->physical_width, 10.0);
82 ASSERT_EQ(configuration->GetMetrics(0)->physical_height, 20.0);
83 ASSERT_EQ(configuration->GetMetrics(0)->physical_touch_slop, 22);
84
85 message_latch->Signal();
86 };
87
88 Settings settings = CreateSettingsForFixture();
89 TaskRunners task_runners("test", // label
90 GetCurrentTaskRunner(), // platform
91 CreateNewThread(), // raster
92 CreateNewThread(), // ui
93 CreateNewThread() // io
94 );
95
96 AddNativeCallback("ValidateConfiguration",
97 CREATE_NATIVE_ENTRY(nativeValidateConfiguration));
98
99 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
100
101 ASSERT_TRUE(shell->IsSetup());
102 auto run_configuration = RunConfiguration::InferFromSettings(settings);
103 run_configuration.SetEntrypoint("validateConfiguration");
104
105 shell->RunEngine(std::move(run_configuration), [&](auto result) {
106 ASSERT_EQ(result, Engine::RunStatus::Success);
107 });
108
109 message_latch->Wait();
110 DestroyShell(std::move(shell), task_runners);
111}
112
113TEST_F(PlatformConfigurationTest, GetWindowReturnsNullForNonexistentId) {
114 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
115
116 auto nativeValidateConfiguration =
117 [message_latch](Dart_NativeArguments args) {
118 PlatformConfiguration* configuration =
120
121 ASSERT_EQ(configuration->GetMetrics(1), nullptr);
122 ASSERT_EQ(configuration->GetMetrics(2), nullptr);
123
124 message_latch->Signal();
125 };
126
127 Settings settings = CreateSettingsForFixture();
128 TaskRunners task_runners("test", // label
129 GetCurrentTaskRunner(), // platform
130 CreateNewThread(), // raster
131 CreateNewThread(), // ui
132 CreateNewThread() // io
133 );
134
135 AddNativeCallback("ValidateConfiguration",
136 CREATE_NATIVE_ENTRY(nativeValidateConfiguration));
137
138 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
139
140 ASSERT_TRUE(shell->IsSetup());
141 auto run_configuration = RunConfiguration::InferFromSettings(settings);
142 run_configuration.SetEntrypoint("validateConfiguration");
143
144 shell->RunEngine(std::move(run_configuration), [&](auto result) {
145 ASSERT_EQ(result, Engine::RunStatus::Success);
146 });
147
148 message_latch->Wait();
149 DestroyShell(std::move(shell), task_runners);
150}
151
152TEST_F(PlatformConfigurationTest, OnErrorHandlesError) {
153 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
154 bool did_throw = false;
155
156 auto finish = [message_latch](Dart_NativeArguments args) {
157 message_latch->Signal();
158 };
159 AddNativeCallback("Finish", CREATE_NATIVE_ENTRY(finish));
160
161 Settings settings = CreateSettingsForFixture();
163 [&did_throw](const std::string& exception,
164 const std::string& stack_trace) -> bool {
165 did_throw = true;
166 return false;
167 };
168
169 TaskRunners task_runners("test", // label
170 GetCurrentTaskRunner(), // platform
171 CreateNewThread(), // raster
172 CreateNewThread(), // ui
173 CreateNewThread() // io
174 );
175
176 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
177
178 ASSERT_TRUE(shell->IsSetup());
179 auto run_configuration = RunConfiguration::InferFromSettings(settings);
180 run_configuration.SetEntrypoint("customOnErrorTrue");
181
182 shell->RunEngine(std::move(run_configuration), [&](auto result) {
183 ASSERT_EQ(result, Engine::RunStatus::Success);
184 });
185
186 message_latch->Wait();
187
188 // Flush the UI task runner to make sure errors that were triggered had a turn
189 // to propagate.
190 task_runners.GetUITaskRunner()->PostTask(
191 [&message_latch]() { message_latch->Signal(); });
192 message_latch->Wait();
193
194 ASSERT_FALSE(did_throw);
195 DestroyShell(std::move(shell), task_runners);
196}
197
198TEST_F(PlatformConfigurationTest, OnErrorDoesNotHandleError) {
199 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
200 std::string ex;
201 std::string st;
202 size_t throw_count = 0;
203
204 auto finish = [message_latch](Dart_NativeArguments args) {
205 message_latch->Signal();
206 };
207 AddNativeCallback("Finish", CREATE_NATIVE_ENTRY(finish));
208
209 Settings settings = CreateSettingsForFixture();
211 [&ex, &st, &throw_count](const std::string& exception,
212 const std::string& stack_trace) -> bool {
213 throw_count += 1;
214 ex = exception;
215 st = stack_trace;
216 return true;
217 };
218
219 TaskRunners task_runners("test", // label
220 GetCurrentTaskRunner(), // platform
221 CreateNewThread(), // raster
222 CreateNewThread(), // ui
223 CreateNewThread() // io
224 );
225
226 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
227
228 ASSERT_TRUE(shell->IsSetup());
229 auto run_configuration = RunConfiguration::InferFromSettings(settings);
230 run_configuration.SetEntrypoint("customOnErrorFalse");
231
232 shell->RunEngine(std::move(run_configuration), [&](auto result) {
233 ASSERT_EQ(result, Engine::RunStatus::Success);
234 });
235
236 message_latch->Wait();
237
238 // Flush the UI task runner to make sure errors that were triggered had a turn
239 // to propagate.
240 task_runners.GetUITaskRunner()->PostTask(
241 [&message_latch]() { message_latch->Signal(); });
242 message_latch->Wait();
243
244 ASSERT_EQ(throw_count, 1ul);
245 ASSERT_EQ(ex, "Exception: false") << ex;
246 ASSERT_EQ(st.rfind("#0 customOnErrorFalse", 0), 0ul) << st;
247 DestroyShell(std::move(shell), task_runners);
248}
249
251 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
252 std::vector<std::string> errors;
253 size_t throw_count = 0;
254
255 auto finish = [message_latch](Dart_NativeArguments args) {
256 message_latch->Signal();
257 };
258 AddNativeCallback("Finish", CREATE_NATIVE_ENTRY(finish));
259
260 Settings settings = CreateSettingsForFixture();
262 [&errors, &throw_count](const std::string& exception,
263 const std::string& stack_trace) -> bool {
264 throw_count += 1;
265 errors.push_back(exception);
266 errors.push_back(stack_trace);
267 return true;
268 };
269
270 TaskRunners task_runners("test", // label
271 GetCurrentTaskRunner(), // platform
272 CreateNewThread(), // raster
273 CreateNewThread(), // ui
274 CreateNewThread() // io
275 );
276
277 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
278
279 ASSERT_TRUE(shell->IsSetup());
280 auto run_configuration = RunConfiguration::InferFromSettings(settings);
281 run_configuration.SetEntrypoint("customOnErrorThrow");
282
283 shell->RunEngine(std::move(run_configuration), [&](auto result) {
284 ASSERT_EQ(result, Engine::RunStatus::Success);
285 });
286
287 message_latch->Wait();
288
289 // Flush the UI task runner to make sure errors that were triggered had a turn
290 // to propagate.
291 task_runners.GetUITaskRunner()->PostTask(
292 [&message_latch]() { message_latch->Signal(); });
293 message_latch->Wait();
294
295 ASSERT_EQ(throw_count, 2ul);
296 ASSERT_EQ(errors.size(), 4ul);
297 ASSERT_EQ(errors[0], "Exception: throw2") << errors[0];
298 ASSERT_EQ(errors[1].rfind("#0 customOnErrorThrow"), 0ul) << errors[1];
299 ASSERT_EQ(errors[2], "Exception: throw1") << errors[2];
300 ASSERT_EQ(errors[3].rfind("#0 customOnErrorThrow"), 0ul) << errors[3];
301
302 DestroyShell(std::move(shell), task_runners);
303}
304
305TEST_F(PlatformConfigurationTest, SetDartPerformanceMode) {
306 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
307 auto finish = [message_latch](Dart_NativeArguments args) {
308 // call needs to happen on the UI thread.
309 Dart_PerformanceMode prev =
310 Dart_SetPerformanceMode(Dart_PerformanceMode_Default);
311 ASSERT_EQ(Dart_PerformanceMode_Latency, prev);
312 message_latch->Signal();
313 };
314 AddNativeCallback("Finish", CREATE_NATIVE_ENTRY(finish));
315
316 Settings settings = CreateSettingsForFixture();
317
318 TaskRunners task_runners("test", // label
319 GetCurrentTaskRunner(), // platform
320 CreateNewThread(), // raster
321 CreateNewThread(), // ui
322 CreateNewThread() // io
323 );
324
325 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
326
327 ASSERT_TRUE(shell->IsSetup());
328 auto run_configuration = RunConfiguration::InferFromSettings(settings);
329 run_configuration.SetEntrypoint("setLatencyPerformanceMode");
330
331 shell->RunEngine(std::move(run_configuration), [&](auto result) {
332 ASSERT_EQ(result, Engine::RunStatus::Success);
333 });
334
335 message_latch->Wait();
336 DestroyShell(std::move(shell), task_runners);
337}
338
339TEST_F(PlatformConfigurationTest, BeginFrameMonotonic) {
340 auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
341
342 PlatformConfiguration* platform;
343
344 // Called at the load time and will be in an Dart isolate.
345 auto nativeValidateConfiguration = [message_latch,
346 &platform](Dart_NativeArguments args) {
348
349 // Hijacks the `_begin_frame` in hooks.dart so we can get a callback for
350 // validation.
351 auto field =
352 Dart_GetField(Dart_RootLibrary(), tonic::ToDart("_beginFrameHijack"));
353 platform->begin_frame_.Clear();
354 platform->begin_frame_.Set(UIDartState::Current(), field);
355
356 message_latch->Signal();
357 };
358 AddNativeCallback("ValidateConfiguration",
359 CREATE_NATIVE_ENTRY(nativeValidateConfiguration));
360
361 std::vector<int64_t> frame_times;
362 std::vector<uint64_t> frame_numbers;
363
364 auto frame_latch = std::make_shared<fml::AutoResetWaitableEvent>();
365
366 // Called for each `_begin_frame` that is hijacked.
367 auto nativeBeginFrame = [frame_latch, &frame_times,
368 &frame_numbers](Dart_NativeArguments args) {
369 int64_t microseconds;
370 uint64_t frame_number;
371 Dart_IntegerToInt64(Dart_GetNativeArgument(args, 0), &microseconds);
372 Dart_IntegerToUint64(Dart_GetNativeArgument(args, 1), &frame_number);
373
374 frame_times.push_back(microseconds);
375 frame_numbers.push_back(frame_number);
376
377 if (frame_times.size() == 3) {
378 frame_latch->Signal();
379 }
380 };
381 AddNativeCallback("BeginFrame", CREATE_NATIVE_ENTRY(nativeBeginFrame));
382
383 Settings settings = CreateSettingsForFixture();
384 TaskRunners task_runners("test", // label
385 GetCurrentTaskRunner(), // platform
386 CreateNewThread(), // raster
387 CreateNewThread(), // ui
388 CreateNewThread() // io
389 );
390
391 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
392 ASSERT_TRUE(shell->IsSetup());
393
394 auto configuration = RunConfiguration::InferFromSettings(settings);
395 configuration.SetEntrypoint("validateConfiguration");
396
397 shell->RunEngine(std::move(configuration), [&](auto result) {
398 ASSERT_EQ(result, Engine::RunStatus::Success);
399 });
400
401 // Wait for `nativeValidateConfiguration` to get called.
402 message_latch->Wait();
403
405 shell->GetTaskRunners().GetUITaskRunner(), [platform]() {
406 auto offset = fml::TimeDelta::FromMilliseconds(10);
407 auto zero = fml::TimePoint();
408 auto one = zero + offset;
409 auto two = one + offset;
410
411 platform->BeginFrame(zero, 1);
412 platform->BeginFrame(two, 2);
413 platform->BeginFrame(one, 3);
414 });
415
416 frame_latch->Wait();
417
418 ASSERT_THAT(frame_times, ::testing::ElementsAre(0, 20000, 20000));
419 ASSERT_THAT(frame_numbers, ::testing::ElementsAre(1, 2, 3));
420 DestroyShell(std::move(shell), task_runners);
421}
422
423} // namespace testing
424} // namespace flutter
A class for holding and distributing platform-level information to and from the Dart code in Flutter'...
const ViewportMetrics * GetMetrics(int view_id)
Retrieves the viewport metrics with the given ID managed by the PlatformConfiguration.
bool UpdateViewMetrics(int64_t view_id, const ViewportMetrics &metrics)
Update the view metrics for the specified view.
static RunConfiguration InferFromSettings(const Settings &settings, const fml::RefPtr< fml::TaskRunner > &io_worker=nullptr, IsolateLaunchType launch_type=IsolateLaunchType::kNewGroup)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
PlatformConfiguration * platform_configuration() const
static UIDartState * Current()
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
virtual void PostTask(const fml::closure &task) override
void Set(DartState *dart_state, Dart_Handle value)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
TEST_F(DisplayListTest, Defaults)
Dart_Handle ToDart(const T &object)
UnhandledExceptionCallback unhandled_exception_callback
Definition settings.h:311
#define CREATE_NATIVE_ENTRY(native_entry)