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

Commit df02653

Browse files
committed
Allow running macOS embedder with ui and platform thread merged
1 parent 10e889e commit df02653

26 files changed

+416
-514
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43716,9 +43716,9 @@ ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTex
4371643716
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObjectTest.mm + ../../../flutter/LICENSE
4371743717
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextureRegistrar.h + ../../../flutter/LICENSE
4371843718
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextureRegistrar.mm + ../../../flutter/LICENSE
43719-
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterThreadSynchronizer.h + ../../../flutter/LICENSE
43720-
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterThreadSynchronizer.mm + ../../../flutter/LICENSE
43721-
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterThreadSynchronizerTest.mm + ../../../flutter/LICENSE
43719+
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h + ../../../flutter/LICENSE
43720+
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm + ../../../flutter/LICENSE
43721+
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizerTest.mm + ../../../flutter/LICENSE
4372243722
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTimeConverter.h + ../../../flutter/LICENSE
4372343723
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTimeConverter.mm + ../../../flutter/LICENSE
4372443724
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterUmbrellaImportTests.m + ../../../flutter/LICENSE

lib/ui/ui_dart_state.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ extern void syslog(int, const char*, ...);
2222
}
2323
#endif
2424

25+
namespace {
26+
static std::set<flutter::UIDartState*> state;
27+
}
28+
29+
void UglyHackFlushMicrotasks() {
30+
for (auto s : state) {
31+
s->FlushMicrotasksNow();
32+
}
33+
}
34+
2535
using tonic::ToDart;
2636

2737
namespace flutter {
@@ -73,10 +83,12 @@ UIDartState::UIDartState(
7383
isolate_name_server_(std::move(isolate_name_server)),
7484
context_(context) {
7585
AddOrRemoveTaskObserver(true /* add */);
86+
state.insert(this);
7687
}
7788

7889
UIDartState::~UIDartState() {
7990
AddOrRemoveTaskObserver(false /* remove */);
91+
state.erase(this);
8092
}
8193

8294
const std::string& UIDartState::GetAdvisoryScriptURI() const {

runtime/dart_isolate.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ bool DartIsolate::Initialize(Dart_Isolate dart_isolate) {
509509
SetMessageHandlingTaskRunner(GetTaskRunners().GetPlatformTaskRunner(),
510510
true);
511511
} else {
512-
SetMessageHandlingTaskRunner(GetTaskRunners().GetUITaskRunner(), false);
512+
SetMessageHandlingTaskRunner(GetTaskRunners().GetUITaskRunner(), true);
513513
}
514514

515515
if (tonic::CheckAndHandleError(

shell/platform/darwin/macos/BUILD.gn

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ source_set("flutter_framework_source") {
9191
"framework/Source/FlutterPlatformViewController.mm",
9292
"framework/Source/FlutterRenderer.h",
9393
"framework/Source/FlutterRenderer.mm",
94+
"framework/Source/FlutterResizeSynchronizer.h",
95+
"framework/Source/FlutterResizeSynchronizer.mm",
96+
"framework/Source/FlutterRunLoop.h",
97+
"framework/Source/FlutterRunLoop.mm",
9498
"framework/Source/FlutterSurface.h",
9599
"framework/Source/FlutterSurface.mm",
96100
"framework/Source/FlutterSurfaceManager.h",
@@ -101,8 +105,6 @@ source_set("flutter_framework_source") {
101105
"framework/Source/FlutterTextInputSemanticsObject.mm",
102106
"framework/Source/FlutterTextureRegistrar.h",
103107
"framework/Source/FlutterTextureRegistrar.mm",
104-
"framework/Source/FlutterThreadSynchronizer.h",
105-
"framework/Source/FlutterThreadSynchronizer.mm",
106108
"framework/Source/FlutterTimeConverter.h",
107109
"framework/Source/FlutterTimeConverter.mm",
108110
"framework/Source/FlutterVSyncWaiter.h",
@@ -190,10 +192,10 @@ executable("flutter_desktop_darwin_unittests") {
190192
"framework/Source/FlutterMutatorViewTest.mm",
191193
"framework/Source/FlutterPlatformNodeDelegateMacTest.mm",
192194
"framework/Source/FlutterPlatformViewControllerTest.mm",
195+
"framework/Source/FlutterResizeSynchronizerTest.mm",
193196
"framework/Source/FlutterSurfaceManagerTest.mm",
194197
"framework/Source/FlutterTextInputPluginTest.mm",
195198
"framework/Source/FlutterTextInputSemanticsObjectTest.mm",
196-
"framework/Source/FlutterThreadSynchronizerTest.mm",
197199
"framework/Source/FlutterVSyncWaiterTest.mm",
198200
"framework/Source/FlutterViewControllerTest.mm",
199201
"framework/Source/FlutterViewControllerTestUtils.h",

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h"
2525
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
2626
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h"
27+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRunLoop.h"
2728
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTimeConverter.h"
2829
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiter.h"
2930
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
@@ -37,6 +38,8 @@
3738

3839
using flutter::kFlutterImplicitViewId;
3940

41+
extern void UglyHackFlushMicrotasks();
42+
4043
/**
4144
* Constructs and returns a FlutterLocale struct corresponding to |locale|, which must outlive
4245
* the returned struct.
@@ -455,8 +458,6 @@ @implementation FlutterEngine {
455458
// A method channel for miscellaneous platform functionality.
456459
FlutterMethodChannel* _platformChannel;
457460

458-
FlutterThreadSynchronizer* _threadSynchronizer;
459-
460461
// Whether the application is currently the active application.
461462
BOOL _active;
462463

@@ -499,6 +500,9 @@ - (instancetype)initWithName:(NSString*)labelPrefix
499500
allowHeadlessExecution:(BOOL)allowHeadlessExecution {
500501
self = [super init];
501502
NSAssert(self, @"Super init cannot be nil");
503+
504+
[FlutterRunLoop ensureMainLoopInitialized];
505+
502506
_pasteboard = [[FlutterPasteboard alloc] init];
503507
_active = NO;
504508
_visible = NO;
@@ -527,7 +531,6 @@ - (instancetype)initWithName:(NSString*)labelPrefix
527531
object:nil];
528532

529533
_platformViewController = [[FlutterPlatformViewController alloc] init];
530-
_threadSynchronizer = [[FlutterThreadSynchronizer alloc] init];
531534
[self setUpPlatformViewChannel];
532535
[self setUpAccessibilityChannel];
533536
[self setUpNotificationCenterListeners];
@@ -653,7 +656,8 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
653656
const FlutterCustomTaskRunners custom_task_runners = {
654657
.struct_size = sizeof(FlutterCustomTaskRunners),
655658
.platform_task_runner = &cocoa_task_runner_description,
656-
.thread_priority_setter = SetThreadPriority};
659+
.thread_priority_setter = SetThreadPriority,
660+
.merged_ui_thread = 1};
657661
flutterArguments.custom_task_runners = &custom_task_runners;
658662

659663
[self loadAOTData:_project.assetsPath];
@@ -739,9 +743,7 @@ - (void)registerViewController:(FlutterViewController*)controller
739743
NSAssert([_viewControllers objectForKey:@(viewIdentifier)] == nil,
740744
@"The requested view ID is occupied.");
741745
[_viewControllers setObject:controller forKey:@(viewIdentifier)];
742-
[controller setUpWithEngine:self
743-
viewIdentifier:viewIdentifier
744-
threadSynchronizer:_threadSynchronizer];
746+
[controller setUpWithEngine:self viewIdentifier:viewIdentifier];
745747
NSAssert(controller.viewIdentifier == viewIdentifier, @"Failed to assign view ID.");
746748
// Verify that the controller's property are updated accordingly. Failing the
747749
// assertions is likely because either the FlutterViewController or the
@@ -769,13 +771,7 @@ - (void)viewControllerViewDidLoad:(FlutterViewController*)viewController {
769771
[timeConverter CAMediaTimeToEngineTime:targetTimestamp];
770772
FlutterEngine* engine = weakSelf;
771773
if (engine) {
772-
// It is a bit unfortunate that embedder requires OnVSync call on
773-
// platform thread just to immediately redispatch it to UI thread.
774-
// We are already on UI thread right now, but have to do the
775-
// extra hop to main thread.
776-
[engine->_threadSynchronizer performOnPlatformThread:^{
777-
engine->_embedderAPI.OnVsync(_engine, baton, timeNanos, targetTimeNanos);
778-
}];
774+
engine->_embedderAPI.OnVsync(_engine, baton, timeNanos, targetTimeNanos);
779775
}
780776
}];
781777
FML_DCHECK([_vsyncWaiters objectForKey:@(viewController.viewIdentifier)] == nil);
@@ -1132,9 +1128,6 @@ - (void)shutDownEngine {
11321128
return;
11331129
}
11341130

1135-
[_threadSynchronizer shutdown];
1136-
_threadSynchronizer = nil;
1137-
11381131
FlutterEngineResult result = _embedderAPI.Deinitialize(_engine);
11391132
if (result != kSuccess) {
11401133
NSLog(@"Could not de-initialize the Flutter engine: error %d", result);
@@ -1331,10 +1324,6 @@ - (BOOL)clipboardHasStrings {
13311324
return flutter::GetSwitchesFromEnvironment();
13321325
}
13331326

1334-
- (FlutterThreadSynchronizer*)testThreadSynchronizer {
1335-
return _threadSynchronizer;
1336-
}
1337-
13381327
#pragma mark - FlutterAppLifecycleDelegate
13391328

13401329
- (void)setApplicationState:(flutter::AppLifecycleState)state {
@@ -1518,29 +1507,23 @@ - (BOOL)unregisterTextureWithID:(int64_t)textureID {
15181507

15191508
#pragma mark - Task runner integration
15201509

1521-
- (void)runTaskOnEmbedder:(FlutterTask)task {
1522-
if (_engine) {
1523-
auto result = _embedderAPI.RunTask(_engine, &task);
1524-
if (result != kSuccess) {
1525-
NSLog(@"Could not post a task to the Flutter engine.");
1526-
}
1527-
}
1528-
}
1529-
15301510
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
15311511
__weak FlutterEngine* weakSelf = self;
1532-
auto worker = ^{
1533-
[weakSelf runTaskOnEmbedder:task];
1534-
};
15351512

15361513
const auto engine_time = _embedderAPI.GetCurrentTime();
1537-
if (targetTime <= engine_time) {
1538-
dispatch_async(dispatch_get_main_queue(), worker);
15391514

1540-
} else {
1541-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, targetTime - engine_time),
1542-
dispatch_get_main_queue(), worker);
1543-
}
1515+
[FlutterRunLoop.mainRunLoop
1516+
performBlock:^{
1517+
FlutterEngine* self = weakSelf;
1518+
if (_engine) {
1519+
auto result = _embedderAPI.RunTask(_engine, &task);
1520+
if (result != kSuccess) {
1521+
NSLog(@"Could not post a task to the Flutter engine.");
1522+
}
1523+
}
1524+
UglyHackFlushMicrotasks();
1525+
}
1526+
afterDelay:(targetTime - (double)engine_time) / 1000000000.0];
15441527
}
15451528

15461529
// Getter used by test harness, only exposed through the FlutterEngine(Test) category

shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
// CREATE_NATIVE_ENTRY and MOCK_ENGINE_PROC are leaky by design
3434
// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
3535

36-
constexpr int64_t kImplicitViewId = 0ll;
37-
3836
@interface FlutterEngine (Test)
3937
/**
4038
* The FlutterCompositor object currently in use by the FlutterEngine.
@@ -526,7 +524,7 @@ @implementation MockableFlutterEngine
526524
result:^(id result){
527525
}];
528526

529-
[engine.testThreadSynchronizer blockUntilFrameAvailable];
527+
// [engine.testThreadSynchronizer blockUntilFrameAvailable];
530528

531529
CALayer* rootLayer = viewController.flutterView.layer;
532530

@@ -863,20 +861,6 @@ @implementation MockableFlutterEngine
863861
}
864862
}
865863

866-
TEST_F(FlutterEngineTest, ThreadSynchronizerNotBlockingRasterThreadAfterShutdown) {
867-
FlutterThreadSynchronizer* threadSynchronizer = [[FlutterThreadSynchronizer alloc] init];
868-
[threadSynchronizer shutdown];
869-
870-
std::thread rasterThread([&threadSynchronizer] {
871-
[threadSynchronizer performCommitForView:kImplicitViewId
872-
size:CGSizeMake(100, 100)
873-
notify:^{
874-
}];
875-
});
876-
877-
rasterThread.join();
878-
}
879-
880864
TEST_F(FlutterEngineTest, ManageControllersIfInitiatedByController) {
881865
NSString* fixtures = @(flutter::testing::GetFixturesPath());
882866
FlutterDartProject* project = [[FlutterDartProject alloc]

shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,6 @@ typedef NS_ENUM(NSInteger, FlutterAppExitResponse) {
224224
- (NSArray<NSScreen*>*)screens;
225225
@end
226226

227-
@interface FlutterEngine (Tests)
228-
- (nonnull FlutterThreadSynchronizer*)testThreadSynchronizer;
229-
@end
230-
231227
NS_ASSUME_NONNULL_END
232228

233229
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_MACOS_FRAMEWORK_SOURCE_FLUTTERENGINE_INTERNAL_H_
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_MACOS_FRAMEWORK_SOURCE_FLUTTERRESIZESYNCHRONIZER_H_
6+
#define FLUTTER_SHELL_PLATFORM_DARWIN_MACOS_FRAMEWORK_SOURCE_FLUTTERRESIZESYNCHRONIZER_H_
7+
8+
#import <Cocoa/Cocoa.h>
9+
10+
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h"
11+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRunLoop.h"
12+
13+
@interface FlutterResizeSynchronizer : NSObject
14+
15+
/**
16+
* Begins a resize operation for the given size. Block the thread until
17+
* performCommitForSize: with the same size is called.
18+
* While the thread is blocked Flutter messages are being pumped.
19+
* See [FlutterRunLoop pollOnce].
20+
*/
21+
- (void)beginResizeForSize:(CGSize)size notify:(nonnull dispatch_block_t)notify;
22+
23+
/**
24+
* Called from raster thread. Schedules the given block on platform thread
25+
* at given delay and unblocks the platform thread if waiting for the surface
26+
* during resize.
27+
*/
28+
- (void)performCommitForSize:(CGSize)size
29+
notify:(nonnull dispatch_block_t)notify
30+
delay:(NSTimeInterval)delay;
31+
32+
/**
33+
* Called when the view is shut down. Unblocks platform thread if blocked
34+
* during resize.
35+
*/
36+
- (void)shutDown;
37+
38+
@end
39+
40+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_MACOS_FRAMEWORK_SOURCE_FLUTTERRESIZESYNCHRONIZER_H_
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h"
6+
7+
#import "flutter/fml/logging.h"
8+
9+
@implementation FlutterResizeSynchronizer {
10+
std::atomic_bool _inResize;
11+
bool _shuttingDown;
12+
bool _hasFrame;
13+
CGSize _contentSize;
14+
}
15+
16+
- (void)beginResizeForSize:(CGSize)size notify:(nonnull dispatch_block_t)notify {
17+
if (!_hasFrame || _shuttingDown) {
18+
notify();
19+
return;
20+
}
21+
22+
_inResize = true;
23+
_contentSize = CGSizeMake(-1, -1);
24+
notify();
25+
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
26+
while (true) {
27+
if (CGSizeEqualToSize(_contentSize, size) || _shuttingDown) {
28+
break;
29+
}
30+
if (CFAbsoluteTimeGetCurrent() - start > 1.0) {
31+
FML_LOG(ERROR) << "Resize timed out.";
32+
break;
33+
}
34+
[FlutterRunLoop.mainRunLoop pollOnce];
35+
}
36+
_inResize = false;
37+
}
38+
39+
- (void)performCommitForSize:(CGSize)size
40+
notify:(nonnull dispatch_block_t)notify
41+
delay:(NSTimeInterval)delay {
42+
if (_inResize) {
43+
delay = 0;
44+
}
45+
[FlutterRunLoop.mainRunLoop
46+
performBlock:^{
47+
_hasFrame = YES;
48+
_contentSize = size;
49+
notify();
50+
}
51+
afterDelay:delay];
52+
}
53+
54+
- (void)shutDown {
55+
[FlutterRunLoop.mainRunLoop performBlock:^{
56+
_shuttingDown = YES;
57+
}];
58+
}
59+
60+
@end

shell/platform/darwin/macos/framework/Source/FlutterThreadSynchronizerTest.mm renamed to shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizerTest.mm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#if 0
6+
57
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterThreadSynchronizer.h"
68

79
#import "flutter/fml/synchronization/waitable_event.h"
@@ -374,3 +376,5 @@ - (void)joinRender {
374376
[scaffold joinMain];
375377
EXPECT_FALSE([synchronizer isWaitingWhenMutexIsAvailable]);
376378
}
379+
380+
#endif

0 commit comments

Comments
 (0)