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

Commit f37c8c5

Browse files
authored
Implemented FlutterEngineGroup and Spawn API. (#22975)
1 parent 97def13 commit f37c8c5

File tree

14 files changed

+417
-23
lines changed

14 files changed

+417
-23
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDel
946946
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h
947947
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h
948948
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h
949+
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngineGroup.h
949950
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h
950951
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h
951952
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h
@@ -964,6 +965,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartPro
964965
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProjectTest.mm
965966
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h
966967
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
968+
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineGroup.mm
969+
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineGroupTest.mm
967970
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm
968971
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm
969972
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h

shell/common/shell.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,21 @@ Shell::~Shell() {
436436
platform_latch.Wait();
437437
}
438438

439+
std::unique_ptr<Shell> Shell::Spawn(
440+
Settings settings,
441+
const CreateCallback<PlatformView>& on_create_platform_view,
442+
const CreateCallback<Rasterizer>& on_create_rasterizer) {
443+
RunConfiguration configuration =
444+
RunConfiguration::InferFromSettings(settings);
445+
TaskRunners task_runners = task_runners_;
446+
FML_DCHECK(task_runners.IsValid());
447+
std::unique_ptr<Shell> result(Shell::Create(std::move(task_runners), settings,
448+
on_create_platform_view,
449+
on_create_rasterizer));
450+
result->RunEngine(std::move(configuration));
451+
return result;
452+
}
453+
439454
void Shell::NotifyLowMemoryWarning() const {
440455
auto trace_id = fml::tracing::TraceNonce();
441456
TRACE_EVENT_ASYNC_BEGIN0("flutter", "Shell::NotifyLowMemoryWarning",

shell/common/shell.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,19 @@ class Shell final : public PlatformView::Delegate,
220220
///
221221
~Shell();
222222

223+
//----------------------------------------------------------------------------
224+
/// @brief Creates one Shell from another Shell where the created Shell
225+
/// takes the opportunity to share any internal components it can.
226+
/// This results is a Shell that has a smaller startup time cost
227+
/// and a smaller memory footprint than an Shell created with a
228+
/// Create function.
229+
///
230+
/// @see http://flutter.dev/go/multiple-engines
231+
std::unique_ptr<Shell> Spawn(
232+
Settings settings,
233+
const CreateCallback<PlatformView>& on_create_platform_view,
234+
const CreateCallback<Rasterizer>& on_create_rasterizer);
235+
223236
//----------------------------------------------------------------------------
224237
/// @brief Starts an isolate for the given RunConfiguration.
225238
///

shell/common/shell_unittests.cc

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "flutter/shell/common/vsync_waiter_fallback.h"
3333
#include "flutter/shell/version/version.h"
3434
#include "flutter/testing/testing.h"
35+
#include "gmock/gmock.h"
3536
#include "third_party/rapidjson/include/rapidjson/writer.h"
3637
#include "third_party/skia/include/core/SkPictureRecorder.h"
3738
#include "third_party/tonic/converter/dart_converter.h"
@@ -42,6 +43,77 @@
4243

4344
namespace flutter {
4445
namespace testing {
46+
namespace {
47+
class MockPlatformViewDelegate : public PlatformView::Delegate {
48+
MOCK_METHOD1(OnPlatformViewCreated, void(std::unique_ptr<Surface> surface));
49+
50+
MOCK_METHOD0(OnPlatformViewDestroyed, void());
51+
52+
MOCK_METHOD1(OnPlatformViewSetNextFrameCallback,
53+
void(const fml::closure& closure));
54+
55+
MOCK_METHOD1(OnPlatformViewSetViewportMetrics,
56+
void(const ViewportMetrics& metrics));
57+
58+
MOCK_METHOD1(OnPlatformViewDispatchPlatformMessage,
59+
void(fml::RefPtr<PlatformMessage> message));
60+
61+
MOCK_METHOD1(OnPlatformViewDispatchPointerDataPacket,
62+
void(std::unique_ptr<PointerDataPacket> packet));
63+
64+
MOCK_METHOD3(OnPlatformViewDispatchSemanticsAction,
65+
void(int32_t id,
66+
SemanticsAction action,
67+
std::vector<uint8_t> args));
68+
69+
MOCK_METHOD1(OnPlatformViewSetSemanticsEnabled, void(bool enabled));
70+
71+
MOCK_METHOD1(OnPlatformViewSetAccessibilityFeatures, void(int32_t flags));
72+
73+
MOCK_METHOD1(OnPlatformViewRegisterTexture,
74+
void(std::shared_ptr<Texture> texture));
75+
76+
MOCK_METHOD1(OnPlatformViewUnregisterTexture, void(int64_t texture_id));
77+
78+
MOCK_METHOD1(OnPlatformViewMarkTextureFrameAvailable,
79+
void(int64_t texture_id));
80+
81+
MOCK_METHOD3(LoadDartDeferredLibrary,
82+
void(intptr_t loading_unit_id,
83+
std::unique_ptr<const fml::Mapping> snapshot_data,
84+
std::unique_ptr<const fml::Mapping> snapshot_instructions));
85+
86+
MOCK_METHOD3(LoadDartDeferredLibraryError,
87+
void(intptr_t loading_unit_id,
88+
const std::string error_message,
89+
bool transient));
90+
91+
MOCK_METHOD1(UpdateAssetManager,
92+
void(std::shared_ptr<AssetManager> asset_manager));
93+
};
94+
95+
class MockSurface : public Surface {
96+
MOCK_METHOD0(IsValid, bool());
97+
98+
MOCK_METHOD1(AcquireFrame,
99+
std::unique_ptr<SurfaceFrame>(const SkISize& size));
100+
101+
MOCK_CONST_METHOD0(GetRootTransformation, SkMatrix());
102+
103+
MOCK_METHOD0(GetContext, GrDirectContext*());
104+
105+
MOCK_METHOD0(MakeRenderContextCurrent, std::unique_ptr<GLContextResult>());
106+
107+
MOCK_METHOD0(ClearRenderContext, bool());
108+
};
109+
110+
class MockPlatformView : public PlatformView {
111+
public:
112+
MockPlatformView(MockPlatformViewDelegate& delegate, TaskRunners task_runners)
113+
: PlatformView(delegate, task_runners) {}
114+
MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr<Surface>());
115+
};
116+
} // namespace
45117

46118
static bool ValidateShell(Shell* shell) {
47119
if (!shell) {
@@ -2318,5 +2390,52 @@ TEST_F(ShellTest, AssetManagerMulti) {
23182390
}
23192391
}
23202392

2393+
TEST_F(ShellTest, Spawn) {
2394+
auto settings = CreateSettingsForFixture();
2395+
auto shell = CreateShell(settings);
2396+
ASSERT_TRUE(ValidateShell(shell.get()));
2397+
2398+
auto configuration = RunConfiguration::InferFromSettings(settings);
2399+
ASSERT_TRUE(configuration.IsValid());
2400+
configuration.SetEntrypoint("fixturesAreFunctionalMain");
2401+
2402+
fml::AutoResetWaitableEvent main_latch;
2403+
AddNativeCallback(
2404+
"SayHiFromFixturesAreFunctionalMain",
2405+
CREATE_NATIVE_ENTRY([&main_latch](auto args) { main_latch.Signal(); }));
2406+
2407+
RunEngine(shell.get(), std::move(configuration));
2408+
main_latch.Wait();
2409+
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
2410+
2411+
{
2412+
fml::AutoResetWaitableEvent latch;
2413+
fml::TaskRunner::RunNowOrPostTask(
2414+
shell->GetTaskRunners().GetPlatformTaskRunner(),
2415+
[this, &spawner = shell, &latch, settings]() {
2416+
MockPlatformViewDelegate platform_view_delegate;
2417+
auto spawn = spawner->Spawn(
2418+
settings,
2419+
[&platform_view_delegate](Shell& shell) {
2420+
auto result = std::make_unique<MockPlatformView>(
2421+
platform_view_delegate, shell.GetTaskRunners());
2422+
ON_CALL(*result, CreateRenderingSurface())
2423+
.WillByDefault(::testing::Invoke(
2424+
[] { return std::make_unique<MockSurface>(); }));
2425+
return result;
2426+
},
2427+
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); });
2428+
ASSERT_NE(nullptr, spawn.get());
2429+
ASSERT_TRUE(ValidateShell(spawn.get()));
2430+
DestroyShell(std::move(spawn));
2431+
latch.Signal();
2432+
});
2433+
latch.Wait();
2434+
}
2435+
2436+
DestroyShell(std::move(shell));
2437+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
2438+
}
2439+
23212440
} // namespace testing
23222441
} // namespace flutter

shell/platform/darwin/ios/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ _flutter_framework_headers = [
2828
"framework/Headers/FlutterCallbackCache.h",
2929
"framework/Headers/FlutterDartProject.h",
3030
"framework/Headers/FlutterEngine.h",
31+
"framework/Headers/FlutterEngineGroup.h",
3132
"framework/Headers/FlutterHeadlessDartRunner.h",
3233
"framework/Headers/FlutterPlatformViews.h",
3334
"framework/Headers/FlutterPlugin.h",
@@ -52,6 +53,7 @@ source_set("flutter_framework_source") {
5253
"framework/Source/FlutterDartProject.mm",
5354
"framework/Source/FlutterDartProject_Internal.h",
5455
"framework/Source/FlutterEngine.mm",
56+
"framework/Source/FlutterEngineGroup.mm",
5557
"framework/Source/FlutterEngine_Internal.h",
5658
"framework/Source/FlutterHeadlessDartRunner.mm",
5759
"framework/Source/FlutterObservatoryPublisher.h",
@@ -215,6 +217,7 @@ shared_library("ios_test_flutter") {
215217
"framework/Source/FlutterAppDelegateTest.mm",
216218
"framework/Source/FlutterBinaryMessengerRelayTest.mm",
217219
"framework/Source/FlutterDartProjectTest.mm",
220+
"framework/Source/FlutterEngineGroupTest.mm",
218221
"framework/Source/FlutterEngineTest.mm",
219222
"framework/Source/FlutterPluginAppLifeCycleDelegateTest.m",
220223
"framework/Source/FlutterTextInputPluginTest.m",

shell/platform/darwin/ios/framework/Headers/Flutter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#import "FlutterCodecs.h"
1313
#import "FlutterDartProject.h"
1414
#import "FlutterEngine.h"
15+
#import "FlutterEngineGroup.h"
1516
#import "FlutterHeadlessDartRunner.h"
1617
#import "FlutterMacros.h"
1718
#import "FlutterPlatformViews.h"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 <Foundation/Foundation.h>
6+
7+
#import "FlutterEngine.h"
8+
9+
NS_ASSUME_NONNULL_BEGIN
10+
11+
/**
12+
* Represents a collection of FlutterEngines who share resources which allows
13+
* them to be created with less time const and occupy less memory than just
14+
* creating multiple FlutterEngines.
15+
*
16+
* Deleting a FlutterEngineGroup doesn't invalidate existing FlutterEngines, but
17+
* it eliminates the possibility to create more FlutterEngines in that group.
18+
*
19+
* @warning This class is a work-in-progress and may change.
20+
* @see https://github.com/flutter/flutter/issues/72009
21+
*/
22+
@interface FlutterEngineGroup : NSObject
23+
- (instancetype)init NS_UNAVAILABLE;
24+
25+
/**
26+
* Initialize a new FlutterEngineGroup.
27+
*
28+
* @param name The name that will present in the threads shared across the
29+
* engines in this group.
30+
* @param project The `FlutterDartProject` that all FlutterEngines in this group
31+
* will be executing.
32+
*/
33+
- (instancetype)initWithName:(NSString*)name
34+
project:(nullable FlutterDartProject*)project NS_DESIGNATED_INITIALIZER;
35+
36+
/**
37+
* Creates a running `FlutterEngine` that shares components with this group.
38+
*
39+
* @see FlutterEngineGroup
40+
*/
41+
- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint
42+
libraryURI:(nullable NSString*)libraryURI;
43+
@end
44+
45+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)