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

Commit 3d194fa

Browse files
Switch macOS embedding to proc table embedder API (#21811)
Converts the macOS embedding to use the new proc table version of the embedding API, and adds one example unit test using it to demonstrate and validate the approach.
1 parent 2617101 commit 3d194fa

File tree

7 files changed

+110
-77
lines changed

7 files changed

+110
-77
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDe
10481048
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject.mm
10491049
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h
10501050
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
1051-
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineUnittests.mm
1051+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm
10521052
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h
10531053
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h
10541054
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.mm

shell/platform/darwin/macos/BUILD.gn

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ source_set("flutter_framework_source") {
8282

8383
public_configs = [ "//flutter:config" ]
8484

85-
defines = [ "FLUTTER_FRAMEWORK" ]
85+
defines = [
86+
"FLUTTER_FRAMEWORK",
87+
"FLUTTER_ENGINE_NO_PROTOTYPES",
88+
]
8689

8790
cflags_objcc = [ "-fobjc-arc" ]
8891

@@ -113,7 +116,7 @@ executable("flutter_desktop_darwin_unittests") {
113116
testonly = true
114117

115118
sources = [
116-
"framework/Source/FlutterEngineUnittests.mm",
119+
"framework/Source/FlutterEngineTest.mm",
117120
"framework/Source/FlutterViewControllerTest.mm",
118121
]
119122

@@ -126,6 +129,7 @@ executable("flutter_desktop_darwin_unittests") {
126129
":flutter_framework_source",
127130
"//flutter/shell/platform/darwin/common:framework_shared",
128131
"//flutter/shell/platform/embedder:embedder_as_internal_library",
132+
"//flutter/shell/platform/embedder:embedder_test_utils",
129133
"//flutter/testing",
130134
"//flutter/testing:dart",
131135
"//flutter/testing:skia",

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

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,6 @@ static FlutterLocale FlutterLocaleFromNSLocale(NSLocale* locale) {
2727
return flutterLocale;
2828
}
2929

30-
namespace {
31-
32-
struct AotDataDeleter {
33-
void operator()(FlutterEngineAOTData aot_data) { FlutterEngineCollectAOTData(aot_data); }
34-
};
35-
36-
using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AotDataDeleter>;
37-
38-
}
39-
4030
/**
4131
* Private interface declaration for FlutterEngine.
4232
*/
@@ -85,10 +75,10 @@ - (BOOL)populateTextureWithIdentifier:(int64_t)textureID
8575
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime;
8676

8777
/**
88-
* Loads the AOT snapshots and instructions from the elf bundle (app_elf_snapshot.so) if it is
89-
* present in the assets directory.
78+
* Loads the AOT snapshots and instructions from the elf bundle (app_elf_snapshot.so) into _aotData,
79+
* if it is present in the assets directory.
9080
*/
91-
- (UniqueAotDataPtr)loadAOTData:(NSString*)assetsDir;
81+
- (void)loadAOTData:(NSString*)assetsDir;
9282

9383
@end
9484

@@ -105,6 +95,7 @@ - (instancetype)initWithPlugin:(nonnull NSString*)pluginKey
10595
@implementation FlutterEngineRegistrar {
10696
NSString* _pluginKey;
10797
FlutterEngine* _flutterEngine;
98+
FlutterEngineProcTable _embedderAPI;
10899
}
109100

110101
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
@@ -201,7 +192,7 @@ @implementation FlutterEngine {
201192
NSMutableDictionary<NSNumber*, FlutterExternalTextureGL*>* _textures;
202193

203194
// Pointer to the Dart AOT snapshot and instruction data.
204-
UniqueAotDataPtr _aotData;
195+
_FlutterEngineAOTData* _aotData;
205196
}
206197

207198
- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
@@ -218,6 +209,8 @@ - (instancetype)initWithName:(NSString*)labelPrefix
218209
_messageHandlers = [[NSMutableDictionary alloc] init];
219210
_textures = [[NSMutableDictionary alloc] init];
220211
_allowHeadlessExecution = allowHeadlessExecution;
212+
_embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
213+
FlutterEngineGetProcAddresses(&_embedderAPI);
221214

222215
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
223216
[notificationCenter addObserver:self
@@ -230,6 +223,9 @@ - (instancetype)initWithName:(NSString*)labelPrefix
230223

231224
- (void)dealloc {
232225
[self shutDownEngine];
226+
if (_aotData) {
227+
_embedderAPI.CollectAOTData(_aotData);
228+
}
233229
}
234230

235231
- (BOOL)runWithEntrypoint:(NSString*)entrypoint {
@@ -301,19 +297,19 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
301297
};
302298
flutterArguments.custom_task_runners = &custom_task_runners;
303299

304-
_aotData = [self loadAOTData:_project.assetsPath];
300+
[self loadAOTData:_project.assetsPath];
305301
if (_aotData) {
306-
flutterArguments.aot_data = _aotData.get();
302+
flutterArguments.aot_data = _aotData;
307303
}
308304

309-
FlutterEngineResult result = FlutterEngineInitialize(
305+
FlutterEngineResult result = _embedderAPI.Initialize(
310306
FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine);
311307
if (result != kSuccess) {
312308
NSLog(@"Failed to initialize Flutter engine: error %d", result);
313309
return NO;
314310
}
315311

316-
result = FlutterEngineRunInitialized(_engine);
312+
result = _embedderAPI.RunInitialized(_engine);
317313
if (result != kSuccess) {
318314
NSLog(@"Failed to run an initialized engine: error %d", result);
319315
return NO;
@@ -326,9 +322,9 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
326322
return YES;
327323
}
328324

329-
- (UniqueAotDataPtr)loadAOTData:(NSString*)assetsDir {
330-
if (!FlutterEngineRunsAOTCompiledDartCode()) {
331-
return nullptr;
325+
- (void)loadAOTData:(NSString*)assetsDir {
326+
if (!_embedderAPI.RunsAOTCompiledDartCode()) {
327+
return;
332328
}
333329

334330
BOOL isDirOut = false; // required for NSFileManager fileExistsAtPath.
@@ -339,21 +335,17 @@ - (UniqueAotDataPtr)loadAOTData:(NSString*)assetsDir {
339335
NSString* elfPath = [NSString pathWithComponents:@[ assetsDir, @"app_elf_snapshot.so" ]];
340336

341337
if (![fileManager fileExistsAtPath:elfPath isDirectory:&isDirOut]) {
342-
return nullptr;
338+
return;
343339
}
344340

345341
FlutterEngineAOTDataSource source = {};
346342
source.type = kFlutterEngineAOTDataSourceTypeElfPath;
347343
source.elf_path = [elfPath cStringUsingEncoding:NSUTF8StringEncoding];
348344

349-
FlutterEngineAOTData data = nullptr;
350-
auto result = FlutterEngineCreateAOTData(&source, &data);
345+
auto result = _embedderAPI.CreateAOTData(&source, &_aotData);
351346
if (result != kSuccess) {
352347
NSLog(@"Failed to load AOT data from: %@", elfPath);
353-
return nullptr;
354348
}
355-
356-
return UniqueAotDataPtr(data);
357349
}
358350

359351
- (void)setViewController:(FlutterViewController*)controller {
@@ -409,13 +401,17 @@ - (void)updateDisplayConfig {
409401
display.refresh_rate = round(refreshRate);
410402

411403
std::vector<FlutterEngineDisplay> displays = {display};
412-
FlutterEngineNotifyDisplayUpdate(_engine, kFlutterEngineDisplaysUpdateTypeStartup,
404+
_embedderAPI.NotifyDisplayUpdate(_engine, kFlutterEngineDisplaysUpdateTypeStartup,
413405
displays.data(), displays.size());
414406
}
415407

416408
CVDisplayLinkRelease(displayLinkRef);
417409
}
418410

411+
- (FlutterEngineProcTable&)embedderAPI {
412+
return _embedderAPI;
413+
}
414+
419415
- (void)updateWindowMetrics {
420416
if (!_engine) {
421417
return;
@@ -433,11 +429,11 @@ - (void)updateWindowMetrics {
433429
.left = static_cast<size_t>(scaledBounds.origin.x),
434430
.top = static_cast<size_t>(scaledBounds.origin.y),
435431
};
436-
FlutterEngineSendWindowMetricsEvent(_engine, &windowMetricsEvent);
432+
_embedderAPI.SendWindowMetricsEvent(_engine, &windowMetricsEvent);
437433
}
438434

439435
- (void)sendPointerEvent:(const FlutterPointerEvent&)event {
440-
FlutterEngineSendPointerEvent(_engine, &event, 1);
436+
_embedderAPI.SendPointerEvent(_engine, &event, 1);
441437
}
442438

443439
#pragma mark - Private methods
@@ -462,7 +458,7 @@ - (void)sendUserLocales {
462458
std::transform(
463459
flutterLocales.begin(), flutterLocales.end(), std::back_inserter(flutterLocaleList),
464460
[](const auto& arg) -> const auto* { return &arg; });
465-
FlutterEngineUpdateLocales(_engine, flutterLocaleList.data(), flutterLocaleList.size());
461+
_embedderAPI.UpdateLocales(_engine, flutterLocaleList.data(), flutterLocaleList.size());
466462
}
467463

468464
- (bool)engineCallbackOnMakeCurrent {
@@ -500,7 +496,7 @@ - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message {
500496

501497
FlutterBinaryReply binaryResponseHandler = ^(NSData* response) {
502498
if (responseHandle) {
503-
FlutterEngineSendPlatformMessageResponse(self->_engine, responseHandle,
499+
_embedderAPI.SendPlatformMessageResponse(self->_engine, responseHandle,
504500
static_cast<const uint8_t*>(response.bytes),
505501
response.length);
506502
responseHandle = NULL;
@@ -527,15 +523,15 @@ - (void)shutDownEngine {
527523
return;
528524
}
529525

530-
FlutterEngineResult result = FlutterEngineDeinitialize(_engine);
526+
FlutterEngineResult result = _embedderAPI.Deinitialize(_engine);
531527
if (result != kSuccess) {
532528
NSLog(@"Could not de-initialize the Flutter engine: error %d", result);
533529
}
534530

535531
// Balancing release for the retain in the task runner dispatch table.
536532
CFRelease((CFTypeRef)self);
537533

538-
result = FlutterEngineShutdown(_engine);
534+
result = _embedderAPI.Shutdown(_engine);
539535
if (result != kSuccess) {
540536
NSLog(@"Failed to shut down Flutter engine: error %d", result);
541537
}
@@ -568,7 +564,7 @@ - (void)sendOnChannel:(NSString*)channel
568564
delete captures;
569565
};
570566

571-
FlutterEngineResult create_result = FlutterPlatformMessageCreateResponseHandle(
567+
FlutterEngineResult create_result = _embedderAPI.PlatformMessageCreateResponseHandle(
572568
_engine, message_reply, captures.get(), &response_handle);
573569
if (create_result != kSuccess) {
574570
NSLog(@"Failed to create a FlutterPlatformMessageResponseHandle (%d)", create_result);
@@ -585,15 +581,15 @@ - (void)sendOnChannel:(NSString*)channel
585581
.response_handle = response_handle,
586582
};
587583

588-
FlutterEngineResult message_result = FlutterEngineSendPlatformMessage(_engine, &platformMessage);
584+
FlutterEngineResult message_result = _embedderAPI.SendPlatformMessage(_engine, &platformMessage);
589585
if (message_result != kSuccess) {
590586
NSLog(@"Failed to send message to Flutter engine on channel '%@' (%d).", channel,
591587
message_result);
592588
}
593589

594590
if (response_handle != nullptr) {
595591
FlutterEngineResult release_result =
596-
FlutterPlatformMessageReleaseResponseHandle(_engine, response_handle);
592+
_embedderAPI.PlatformMessageReleaseResponseHandle(_engine, response_handle);
597593
if (release_result != kSuccess) {
598594
NSLog(@"Failed to release the response handle (%d).", release_result);
599595
};
@@ -628,30 +624,30 @@ - (int64_t)registerTexture:(id<FlutterTexture>)texture {
628624
FlutterExternalTextureGL* FlutterTexture =
629625
[[FlutterExternalTextureGL alloc] initWithFlutterTexture:texture];
630626
int64_t textureID = [FlutterTexture textureID];
631-
FlutterEngineRegisterExternalTexture(_engine, textureID);
627+
_embedderAPI.RegisterExternalTexture(_engine, textureID);
632628
_textures[@(textureID)] = FlutterTexture;
633629
return textureID;
634630
}
635631

636632
- (void)textureFrameAvailable:(int64_t)textureID {
637-
FlutterEngineMarkExternalTextureFrameAvailable(_engine, textureID);
633+
_embedderAPI.MarkExternalTextureFrameAvailable(_engine, textureID);
638634
}
639635

640636
- (void)unregisterTexture:(int64_t)textureID {
641-
FlutterEngineUnregisterExternalTexture(_engine, textureID);
637+
_embedderAPI.UnregisterExternalTexture(_engine, textureID);
642638
[_textures removeObjectForKey:@(textureID)];
643639
}
644640

645641
#pragma mark - Task runner integration
646642

647643
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
648-
const auto engine_time = FlutterEngineGetCurrentTime();
644+
const auto engine_time = _embedderAPI.GetCurrentTime();
649645

650646
__weak FlutterEngine* weak_self = self;
651647
auto worker = ^{
652648
FlutterEngine* strong_self = weak_self;
653649
if (strong_self && strong_self->_engine) {
654-
auto result = FlutterEngineRunTask(strong_self->_engine, &task);
650+
auto result = _embedderAPI.RunTask(strong_self->_engine, &task);
655651
if (result != kSuccess) {
656652
NSLog(@"Could not post a task to the Flutter engine.");
657653
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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/Headers/FlutterEngine.h"
6+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
7+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
8+
#include "flutter/shell/platform/embedder/embedder.h"
9+
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
10+
#include "flutter/testing/testing.h"
11+
12+
namespace flutter::testing {
13+
14+
namespace {
15+
// Returns an engine configured for the text fixture resource configuration.
16+
FlutterEngine* CreateTestEngine() {
17+
NSString* fixtures = @(testing::GetFixturesPath());
18+
FlutterDartProject* project = [[FlutterDartProject alloc]
19+
initWithAssetsPath:fixtures
20+
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
21+
return [[FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true];
22+
}
23+
} // namespace
24+
25+
TEST(FlutterEngine, CanLaunch) {
26+
FlutterEngine* engine = CreateTestEngine();
27+
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
28+
EXPECT_TRUE(engine.running);
29+
[engine shutDownEngine];
30+
}
31+
32+
TEST(FlutterEngine, MessengerSend) {
33+
FlutterEngine* engine = CreateTestEngine();
34+
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
35+
36+
NSData* test_message = [@"a message" dataUsingEncoding:NSUTF8StringEncoding];
37+
bool called = false;
38+
39+
engine.embedderAPI.SendPlatformMessage = MOCK_ENGINE_PROC(
40+
SendPlatformMessage, ([&called, test_message](auto engine, auto message) {
41+
called = true;
42+
EXPECT_STREQ(message->channel, "test");
43+
EXPECT_EQ(memcmp(message->message, test_message.bytes, message->message_size), 0);
44+
return kSuccess;
45+
}));
46+
47+
[engine.binaryMessenger sendOnChannel:@"test" message:test_message];
48+
EXPECT_TRUE(called);
49+
50+
[engine shutDownEngine];
51+
}
52+
53+
} // flutter::testing

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

Lines changed: 0 additions & 25 deletions
This file was deleted.

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#import <Cocoa/Cocoa.h>
88

9-
#import "flutter/shell/platform/embedder/embedder.h"
9+
#include "flutter/shell/platform/embedder/embedder.h"
1010

1111
@interface FlutterEngine ()
1212

@@ -21,6 +21,11 @@
2121
*/
2222
@property(nonatomic, readonly, nullable) NSOpenGLContext* resourceContext;
2323

24+
/**
25+
* Function pointers for interacting with the embedder.h API.
26+
*/
27+
@property(nonatomic) FlutterEngineProcTable& embedderAPI;
28+
2429
/**
2530
* Informs the engine that the associated view controller's view size has changed.
2631
*/

0 commit comments

Comments
 (0)