Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 193b7b4

Browse files
committed
Add tests and move to class variable
1 parent 7840de7 commit 193b7b4

File tree

5 files changed

+131
-9
lines changed

5 files changed

+131
-9
lines changed

fml/macros.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@
3838
TypeName() = delete; \
3939
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName)
4040

41+
#define FML_TEST_NAME(test_case_name, test_name) \
42+
test_case_name##_##test_name##_Test
43+
44+
#define FML_TEST_CLASS(test_case_name, test_name) \
45+
class FML_TEST_NAME(test_case_name, test_name)
46+
4147
#define FML_FRIEND_TEST(test_case_name, test_name) \
42-
friend class test_case_name##_##test_name##_Test
48+
friend FML_TEST_CLASS(test_case_name, test_name)
4349

4450
#endif // FLUTTER_FML_MACROS_H_

lib/ui/fixtures/ui_test.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,16 @@ void convertPaintToDlPaint() {
492492
@pragma('vm:external-name', 'ConvertPaintToDlPaint')
493493
external void _convertPaintToDlPaint(Paint paint);
494494

495+
/// Hooks for platform_configuration_unittests.cc
496+
@pragma('vm:entry-point')
497+
void _beginFrameHijack(int microseconds, int frameNumber) {
498+
nativeBeginFrame(microseconds, frameNumber);
499+
}
500+
501+
@pragma('vm:entry-point')
502+
@pragma('vm:external-name', 'BeginFrame')
503+
external nativeBeginFrame(int microseconds, int frameNumber);
504+
495505
@pragma('vm:entry-point')
496506
void hooksTests() async {
497507
Future<void> test(String name, FutureOr<void> Function() testFunction) async {

lib/ui/window/platform_configuration.cc

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,18 +377,25 @@ void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime,
377377
}
378378
tonic::DartState::Scope scope(dart_state);
379379

380-
int64_t microseconds = frameTime.ToEpochDelta().ToMicroseconds();
380+
if (last_frame_number_ > frame_number) {
381+
FML_LOG(ERROR) << "Frame number is out of order: " << frame_number << " < "
382+
<< last_frame_number_;
383+
}
384+
last_frame_number_ = frame_number;
381385

382-
static int64_t last_microseconds = 0;
383-
if (last_microseconds > microseconds) {
386+
// frameTime is not a delta; its the timestamp of the presentation.
387+
// This is just a type conversion.
388+
int64_t microseconds = frameTime.ToEpochDelta().ToMicroseconds();
389+
if (last_microseconds_ > microseconds) {
384390
// Do not allow time traveling frametimes
385391
// github.com/flutter/flutter/issues/106277
386392
FML_LOG(ERROR)
387393
<< "Reported frame time is older than the last one; clamping. "
388-
<< microseconds << " < " << last_microseconds
389-
<< " ~= " << last_microseconds - microseconds;
390-
microseconds = last_microseconds;
394+
<< microseconds << " < " << last_microseconds_
395+
<< " ~= " << last_microseconds_ - microseconds;
396+
microseconds = last_microseconds_;
391397
}
398+
last_microseconds_ = microseconds;
392399

393400
tonic::CheckAndHandleError(
394401
tonic::DartInvoke(begin_frame_.Get(), {

lib/ui/window/platform_configuration.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "flutter/lib/ui/window/pointer_data_packet.h"
1919
#include "flutter/lib/ui/window/viewport_metrics.h"
2020
#include "flutter/shell/common/display.h"
21+
#include "fml/macros.h"
2122
#include "third_party/tonic/dart_persistent_value.h"
2223
#include "third_party/tonic/typed_data/dart_byte_data.h"
2324

@@ -28,6 +29,11 @@ class PlatformMessageHandler;
2829
class PlatformIsolateManager;
2930
class Scene;
3031

32+
// Forward declaration of friendly tests.
33+
namespace testing {
34+
FML_TEST_CLASS(PlatformConfigurationTest, BeginFrameMonotonic);
35+
}
36+
3137
//--------------------------------------------------------------------------
3238
/// @brief An enum for defining the different kinds of accessibility features
3339
/// that can be enabled by the platform.
@@ -517,6 +523,8 @@ class PlatformConfiguration final {
517523
Dart_Handle on_error() { return on_error_.Get(); }
518524

519525
private:
526+
FML_FRIEND_TEST(testing::PlatformConfigurationTest, BeginFrameMonotonic);
527+
520528
PlatformConfigurationClient* client_;
521529
tonic::DartPersistentValue on_error_;
522530
tonic::DartPersistentValue add_view_;
@@ -535,6 +543,9 @@ class PlatformConfiguration final {
535543
tonic::DartPersistentValue draw_frame_;
536544
tonic::DartPersistentValue report_timings_;
537545

546+
uint64_t last_frame_number_;
547+
int64_t last_microseconds_;
548+
538549
// All current views' view metrics mapped from view IDs.
539550
std::unordered_map<int64_t, ViewportMetrics> metrics_;
540551

lib/ui/window/platform_configuration_unittests.cc

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@
44

55
#define FML_USED_ON_EMBEDDER
66

7-
#include "flutter/lib/ui/window/platform_configuration.h"
8-
7+
#include <cstddef>
98
#include <memory>
109

1110
#include "flutter/common/task_runners.h"
1211
#include "flutter/fml/synchronization/waitable_event.h"
1312
#include "flutter/lib/ui/painting/vertices.h"
13+
#include "flutter/lib/ui/window/platform_configuration.h"
1414
#include "flutter/runtime/dart_vm.h"
1515
#include "flutter/shell/common/shell_test.h"
1616
#include "flutter/shell/common/thread_host.h"
1717
#include "flutter/testing/testing.h"
18+
#include "gmock/gmock.h"
19+
#include "googletest/googletest/include/gtest/gtest.h"
20+
#include "third_party/dart/runtime/include/dart_api.h"
21+
#include "tonic/converter/dart_converter.h"
1822

1923
namespace flutter {
2024
namespace testing {
@@ -332,5 +336,89 @@ TEST_F(PlatformConfigurationTest, SetDartPerformanceMode) {
332336
DestroyShell(std::move(shell), task_runners);
333337
}
334338

339+
TEST_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) {
347+
platform = UIDartState::Current()->platform_configuration();
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+
404+
fml::TaskRunner::RunNowOrPostTask(
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+
335423
} // namespace testing
336424
} // namespace flutter

0 commit comments

Comments
 (0)