Skip to content

Commit dbbbf55

Browse files
committed
Implement FlutterTizenEngine spawn
Signed-off-by: swan.seo <swan.seo@samsung.com>
1 parent 5a343b3 commit dbbbf55

11 files changed

+263
-25
lines changed

flutter/shell/platform/embedder/embedder.h

+18
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,16 @@ FlutterEngineResult FlutterEngineRun(size_t version,
18241824
FLUTTER_API_SYMBOL(FlutterEngine) *
18251825
engine_out);
18261826

1827+
FLUTTER_EXPORT
1828+
FlutterEngineResult FlutterEngineSpawn(size_t version,
1829+
const FlutterRendererConfig* config,
1830+
const FlutterProjectArgs* args,
1831+
void* user_data,
1832+
FLUTTER_API_SYMBOL(FlutterEngine)
1833+
spawner,
1834+
FLUTTER_API_SYMBOL(FlutterEngine) *
1835+
engine_out);
1836+
18271837
//------------------------------------------------------------------------------
18281838
/// @brief Shuts down a Flutter engine instance. The engine handle is no
18291839
/// longer valid for any calls in the embedder API after this point.
@@ -2441,6 +2451,13 @@ typedef FlutterEngineResult (*FlutterEngineRunFnPtr)(
24412451
const FlutterProjectArgs* args,
24422452
void* user_data,
24432453
FLUTTER_API_SYMBOL(FlutterEngine) * engine_out);
2454+
typedef FlutterEngineResult (*FlutterEngineSpawnFnPtr)(
2455+
size_t version,
2456+
const FlutterRendererConfig* config,
2457+
const FlutterProjectArgs* args,
2458+
void* user_data,
2459+
FLUTTER_API_SYMBOL(FlutterEngine) engine_spawner,
2460+
FLUTTER_API_SYMBOL(FlutterEngine) * engine_out);
24442461
typedef FlutterEngineResult (*FlutterEngineShutdownFnPtr)(
24452462
FLUTTER_API_SYMBOL(FlutterEngine) engine);
24462463
typedef FlutterEngineResult (*FlutterEngineInitializeFnPtr)(
@@ -2554,6 +2571,7 @@ typedef struct {
25542571
FlutterEngineCreateAOTDataFnPtr CreateAOTData;
25552572
FlutterEngineCollectAOTDataFnPtr CollectAOTData;
25562573
FlutterEngineRunFnPtr Run;
2574+
FlutterEngineSpawnFnPtr Spawn;
25572575
FlutterEngineShutdownFnPtr Shutdown;
25582576
FlutterEngineInitializeFnPtr Initialize;
25592577
FlutterEngineDeinitializeFnPtr Deinitialize;

flutter/shell/platform/tizen/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ template("embedder") {
9797
"flutter_tizen.cc",
9898
"flutter_tizen_elementary.cc",
9999
"flutter_tizen_engine.cc",
100+
"flutter_tizen_engine_group.cc",
100101
"flutter_tizen_texture_registrar.cc",
101102
"flutter_tizen_view.cc",
102103
"logger.cc",

flutter/shell/platform/tizen/flutter_tizen.cc

+11-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "flutter/shell/platform/common/incoming_message_dispatcher.h"
1111
#include "flutter/shell/platform/tizen/flutter_project_bundle.h"
1212
#include "flutter/shell/platform/tizen/flutter_tizen_engine.h"
13+
#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h"
1314
#include "flutter/shell/platform/tizen/flutter_tizen_view.h"
1415
#include "flutter/shell/platform/tizen/logger.h"
1516
#include "flutter/shell/platform/tizen/public/flutter_platform_view.h"
@@ -71,20 +72,22 @@ FlutterDesktopEngineRef FlutterDesktopEngineCreate(
7172
}
7273
flutter::Logger::Start();
7374

74-
auto engine = std::make_unique<flutter::FlutterTizenEngine>(project);
75-
return HandleForEngine(engine.release());
75+
auto engine =
76+
flutter::FlutterTizenEngineGroup::GetInstance().MakeEngineWithProject(
77+
project);
78+
79+
return HandleForEngine(engine);
7680
}
7781

7882
bool FlutterDesktopEngineRun(const FlutterDesktopEngineRef engine) {
79-
return EngineFromHandle(engine)->RunEngine();
83+
return EngineFromHandle(engine)->RunOrSpawnEngine();
8084
}
8185

8286
void FlutterDesktopEngineShutdown(FlutterDesktopEngineRef engine_ref) {
8387
flutter::Logger::Stop();
8488

8589
flutter::FlutterTizenEngine* engine = EngineFromHandle(engine_ref);
86-
engine->StopEngine();
87-
delete engine;
90+
flutter::FlutterTizenEngineGroup::GetInstance().StopEngine(engine->id());
8891
}
8992

9093
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
@@ -219,12 +222,11 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow(
219222

220223
auto view = std::make_unique<flutter::FlutterTizenView>(std::move(window));
221224

222-
// Take ownership of the engine, starting it if necessary.
223-
view->SetEngine(
224-
std::unique_ptr<flutter::FlutterTizenEngine>(EngineFromHandle(engine)));
225+
// Starting it if necessary.
226+
view->SetEngine(EngineFromHandle(engine));
225227
view->CreateRenderSurface(window_properties.renderer_type);
226228
if (!view->engine()->IsRunning()) {
227-
if (!view->engine()->RunEngine()) {
229+
if (!view->engine()->RunOrSpawnEngine()) {
228230
return nullptr;
229231
}
230232
}

flutter/shell/platform/tizen/flutter_tizen_elementary.cc

+3-4
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,11 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromElmParent(
3333
auto view =
3434
std::make_unique<flutter::FlutterTizenView>(std::move(tizen_view));
3535

36-
// Take ownership of the engine, starting it if necessary.
37-
view->SetEngine(
38-
std::unique_ptr<flutter::FlutterTizenEngine>(EngineFromHandle(engine)));
36+
// Starting it if necessary.
37+
view->SetEngine(EngineFromHandle(engine));
3938
view->CreateRenderSurface(FlutterDesktopRendererType::kEvasGL);
4039
if (!view->engine()->IsRunning()) {
41-
if (!view->engine()->RunEngine()) {
40+
if (!view->engine()->RunOrSpawnEngine()) {
4241
return nullptr;
4342
}
4443
}

flutter/shell/platform/tizen/flutter_tizen_engine.cc

+134
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "flutter/shell/platform/tizen/flutter_platform_node_delegate_tizen.h"
1515
#include "flutter/shell/platform/tizen/tizen_renderer_egl.h"
1616
#endif
17+
#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h"
1718
#include "flutter/shell/platform/tizen/flutter_tizen_view.h"
1819
#include "flutter/shell/platform/tizen/logger.h"
1920
#include "flutter/shell/platform/tizen/system_utils.h"
@@ -100,6 +101,14 @@ void FlutterTizenEngine::CreateRenderer(
100101
#endif
101102
}
102103

104+
bool FlutterTizenEngine::RunOrSpawnEngine() {
105+
if (FlutterTizenEngineGroup::GetInstance().GetEngineCount() <= 1) {
106+
return RunEngine();
107+
} else {
108+
return SpawnEngine();
109+
}
110+
}
111+
103112
bool FlutterTizenEngine::RunEngine() {
104113
if (engine_ != nullptr) {
105114
FT_LOG(Error) << "The engine has already started.";
@@ -258,6 +267,131 @@ bool FlutterTizenEngine::RunEngine() {
258267
return true;
259268
}
260269

270+
bool FlutterTizenEngine::SpawnEngine() {
271+
if (engine_ != nullptr) {
272+
FT_LOG(Error) << "The engine has already started.";
273+
return false;
274+
}
275+
if (IsHeaded() && !renderer_->IsValid()) {
276+
FT_LOG(Error) << "The display was not valid.";
277+
return false;
278+
}
279+
280+
if (!project_->HasValidPaths()) {
281+
FT_LOG(Error) << "Missing or unresolvable path to assets.";
282+
return false;
283+
}
284+
std::string assets_path_string = project_->assets_path().u8string();
285+
std::string icu_path_string = project_->icu_path().u8string();
286+
if (embedder_api_.RunsAOTCompiledDartCode()) {
287+
aot_data_ = project_->LoadAotData(embedder_api_);
288+
if (!aot_data_) {
289+
FT_LOG(Error) << "Unable to start engine without AOT data.";
290+
return false;
291+
}
292+
}
293+
294+
// FlutterProjectArgs is expecting a full argv, so when processing it for
295+
// flags the first item is treated as the executable and ignored. Add a dummy
296+
// value so that all provided arguments are used.
297+
std::vector<std::string> engine_args = project_->engine_arguments();
298+
std::vector<const char*> engine_argv = {"placeholder"};
299+
std::transform(
300+
engine_args.begin(), engine_args.end(), std::back_inserter(engine_argv),
301+
[](const std::string& arg) -> const char* { return arg.c_str(); });
302+
303+
const std::vector<std::string>& entrypoint_args =
304+
project_->dart_entrypoint_arguments();
305+
std::vector<const char*> entrypoint_argv;
306+
std::transform(
307+
entrypoint_args.begin(), entrypoint_args.end(),
308+
std::back_inserter(entrypoint_argv),
309+
[](const std::string& arg) -> const char* { return arg.c_str(); });
310+
311+
FlutterProjectArgs args = {};
312+
args.struct_size = sizeof(FlutterProjectArgs);
313+
args.assets_path = assets_path_string.c_str();
314+
args.icu_data_path = icu_path_string.c_str();
315+
args.command_line_argc = static_cast<int>(engine_argv.size());
316+
args.command_line_argv =
317+
engine_argv.size() > 0 ? engine_argv.data() : nullptr;
318+
args.dart_entrypoint_argc = static_cast<int>(entrypoint_argv.size());
319+
args.dart_entrypoint_argv =
320+
entrypoint_argv.size() > 0 ? entrypoint_argv.data() : nullptr;
321+
args.platform_message_callback =
322+
[](const FlutterPlatformMessage* engine_message, void* user_data) {
323+
if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) {
324+
FT_LOG(Error) << "Invalid message size received. Expected: "
325+
<< sizeof(FlutterPlatformMessage) << ", but received "
326+
<< engine_message->struct_size;
327+
return;
328+
}
329+
auto* engine = reinterpret_cast<FlutterTizenEngine*>(user_data);
330+
FlutterDesktopMessage message =
331+
engine->ConvertToDesktopMessage(*engine_message);
332+
engine->message_dispatcher_->HandleMessage(message);
333+
};
334+
if (aot_data_) {
335+
args.aot_data = aot_data_.get();
336+
}
337+
if (!project_->custom_dart_entrypoint().empty()) {
338+
args.custom_dart_entrypoint = project_->custom_dart_entrypoint().c_str();
339+
}
340+
#ifndef WEARABLE_PROFILE
341+
args.update_semantics_node_callback = OnUpdateSemanticsNode;
342+
args.update_semantics_custom_action_callback = OnUpdateSemanticsCustomActions;
343+
344+
if (IsHeaded() && dynamic_cast<TizenRendererEvasGL*>(renderer_.get())) {
345+
vsync_waiter_ = std::make_unique<TizenVsyncWaiter>(this);
346+
args.vsync_callback = [](void* user_data, intptr_t baton) -> void {
347+
auto* engine = reinterpret_cast<FlutterTizenEngine*>(user_data);
348+
engine->vsync_waiter_->AsyncWaitForVsync(baton);
349+
};
350+
}
351+
#endif
352+
353+
auto* spawner = FlutterTizenEngineGroup::GetInstance().GetEngineSpawner();
354+
FlutterRendererConfig renderer_config = GetRendererConfig();
355+
FlutterEngineResult result =
356+
embedder_api_.Spawn(FLUTTER_ENGINE_VERSION, &renderer_config, &args, this,
357+
spawner->engine_, &engine_);
358+
359+
if (result != kSuccess || engine_ == nullptr) {
360+
FT_LOG(Error) << "Failed to start the Flutter engine with error: "
361+
<< result;
362+
return false;
363+
}
364+
365+
internal_plugin_registrar_ =
366+
std::make_unique<PluginRegistrar>(plugin_registrar_.get());
367+
accessibility_channel_ = std::make_unique<AccessibilityChannel>(
368+
internal_plugin_registrar_->messenger());
369+
app_control_channel_ = std::make_unique<AppControlChannel>(
370+
internal_plugin_registrar_->messenger());
371+
lifecycle_channel_ = std::make_unique<LifecycleChannel>(
372+
internal_plugin_registrar_->messenger());
373+
settings_channel_ = std::make_unique<SettingsChannel>(
374+
internal_plugin_registrar_->messenger());
375+
376+
if (IsHeaded()) {
377+
texture_registrar_ = std::make_unique<FlutterTizenTextureRegistrar>(this);
378+
key_event_channel_ = std::make_unique<KeyEventChannel>(
379+
internal_plugin_registrar_->messenger(),
380+
[this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback,
381+
void* user_data) { SendKeyEvent(event, callback, user_data); });
382+
navigation_channel_ = std::make_unique<NavigationChannel>(
383+
internal_plugin_registrar_->messenger());
384+
platform_view_channel_ = std::make_unique<PlatformViewChannel>(
385+
internal_plugin_registrar_->messenger());
386+
}
387+
388+
accessibility_settings_ = std::make_unique<AccessibilitySettings>(this);
389+
390+
SetupLocales();
391+
392+
return true;
393+
}
394+
261395
bool FlutterTizenEngine::StopEngine() {
262396
if (engine_) {
263397
if (platform_view_channel_) {

flutter/shell/platform/tizen/flutter_tizen_engine.h

+13
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,19 @@ class FlutterTizenEngine {
6262
// Creates a GL renderer from the given type.
6363
void CreateRenderer(FlutterDesktopRendererType renderer_type);
6464

65+
// If the engine is the only engine of the engine group, starts running the
66+
// engine. Otherwise, spawns the engine.
67+
bool RunOrSpawnEngine();
68+
6569
// Starts running the engine with the given entrypoint. If null, defaults to
6670
// main().
6771
//
6872
// Returns false if the engine couldn't be started.
6973
bool RunEngine();
7074

75+
// Returns false if the engine couldn't be spawned.
76+
bool SpawnEngine();
77+
7178
// Returns true if the engine is currently running.
7279
bool IsRunning() { return engine_ != nullptr; }
7380

@@ -81,6 +88,10 @@ class FlutterTizenEngine {
8188
// headless engines.
8289
FlutterTizenView* view() { return view_; }
8390

91+
void SetId(uint32_t id) { id_ = id; }
92+
93+
uint32_t id() { return id_; }
94+
8495
FlutterDesktopMessengerRef messenger() { return messenger_.get(); }
8596

8697
IncomingMessageDispatcher* message_dispatcher() {
@@ -288,6 +299,8 @@ class FlutterTizenEngine {
288299
// The vsync waiter for the embedder.
289300
std::unique_ptr<TizenVsyncWaiter> vsync_waiter_;
290301
#endif
302+
303+
uint32_t id_;
291304
};
292305

293306
} // namespace flutter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h"
2+
3+
#include <random>
4+
5+
namespace flutter {
6+
7+
FlutterTizenEngine* FlutterTizenEngineGroup::MakeEngineWithProject(
8+
const FlutterProjectBundle& project) {
9+
std::unique_ptr<FlutterTizenEngine> engine =
10+
std::make_unique<flutter::FlutterTizenEngine>(project);
11+
12+
static std::random_device random_device;
13+
static std::mt19937 generator(random_device());
14+
static std::uniform_int_distribution<uint32_t> distribution(0, 99999);
15+
16+
engine->SetId(distribution(generator));
17+
18+
engines_.push_back(std::move(engine));
19+
return engines_.back().get();
20+
}
21+
22+
FlutterTizenEngine* FlutterTizenEngineGroup::GetEngineSpawner() {
23+
return engines_[0].get();
24+
}
25+
26+
int FlutterTizenEngineGroup::GetEngineCount() {
27+
return engines_.size();
28+
}
29+
30+
void FlutterTizenEngineGroup::StopEngine(uint32_t id) {
31+
for (auto it = engines_.begin(); it != engines_.end(); ++it) {
32+
if (id == it->get()->id()) {
33+
it->get()->StopEngine();
34+
engines_.erase(it);
35+
return;
36+
}
37+
}
38+
}
39+
40+
} // namespace flutter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef EMBEDDER_FLUTTER_TIZEN_ENGINE_GROUP_H_
2+
#define EMBEDDER_FLUTTER_TIZEN_ENGINE_GROUP_H_
3+
4+
#include "flutter/shell/platform/tizen/flutter_tizen_engine.h"
5+
6+
namespace flutter {
7+
8+
class FlutterTizenEngineGroup {
9+
public:
10+
static FlutterTizenEngineGroup& GetInstance() {
11+
static FlutterTizenEngineGroup instance;
12+
return instance;
13+
}
14+
15+
FlutterTizenEngine* GetEngineSpawner();
16+
17+
FlutterTizenEngine* MakeEngineWithProject(
18+
const FlutterProjectBundle& project);
19+
20+
int GetEngineCount();
21+
22+
void StopEngine(uint32_t id);
23+
24+
private:
25+
FlutterTizenEngineGroup() {}
26+
27+
std::vector<std::unique_ptr<FlutterTizenEngine>> engines_;
28+
};
29+
30+
} // namespace flutter
31+
32+
#endif

flutter/shell/platform/tizen/flutter_tizen_nui.cc

+3-4
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,11 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromImageView(
4242
auto view =
4343
std::make_unique<flutter::FlutterTizenView>(std::move(tizen_view));
4444

45-
// Take ownership of the engine, starting it if necessary.
46-
view->SetEngine(
47-
std::unique_ptr<flutter::FlutterTizenEngine>(EngineFromHandle(engine)));
45+
// Starting it if necessary.
46+
view->SetEngine(EngineFromHandle(engine));
4847
view->CreateRenderSurface(FlutterDesktopRendererType::kEGL);
4948
if (!view->engine()->IsRunning()) {
50-
if (!view->engine()->RunEngine()) {
49+
if (!view->engine()->RunOrSpawnEngine()) {
5150
return nullptr;
5251
}
5352
}

0 commit comments

Comments
 (0)