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

Commit 722414a

Browse files
authored
Implemented threadsafe platform channel replies on windows (#36909)
* Implemented threadsafe platform channel replies on windows * added unit test * added docstrings * implemented glfw * added comments * made glfw messenger unable to be copied * stuart feedback 1 * stuart feedback 2: replaced the shared_ptr * stuart feedback 3 * stuart feedback: remove error log * Moved FlutterDesktopMessenger to its own file. * updated licenses * stuart feedback
1 parent aa4b3ea commit 722414a

13 files changed

+370
-32
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,6 +3099,7 @@ FILE: ../../../flutter/shell/platform/windows/external_texture_d3d.cc
30993099
FILE: ../../../flutter/shell/platform/windows/external_texture_d3d.h
31003100
FILE: ../../../flutter/shell/platform/windows/external_texture_pixelbuffer.cc
31013101
FILE: ../../../flutter/shell/platform/windows/external_texture_pixelbuffer.h
3102+
FILE: ../../../flutter/shell/platform/windows/flutter_desktop_messenger.h
31023103
FILE: ../../../flutter/shell/platform/windows/flutter_key_map.g.cc
31033104
FILE: ../../../flutter/shell/platform/windows/flutter_platform_node_delegate_windows.cc
31043105
FILE: ../../../flutter/shell/platform/windows/flutter_platform_node_delegate_windows.h

shell/platform/common/client_wrapper/core_implementations.cc

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ namespace flutter {
2626
// ========== binary_messenger_impl.h ==========
2727

2828
namespace {
29+
30+
using FlutterDesktopMessengerScopedLock =
31+
std::unique_ptr<FlutterDesktopMessenger,
32+
decltype(&FlutterDesktopMessengerUnlock)>;
33+
2934
// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along
3035
// with a BinaryReply that will send a response on |message|'s response handle.
3136
//
@@ -36,17 +41,28 @@ void ForwardToHandler(FlutterDesktopMessengerRef messenger,
3641
const FlutterDesktopMessage* message,
3742
void* user_data) {
3843
auto* response_handle = message->response_handle;
39-
BinaryReply reply_handler = [messenger, response_handle](
44+
auto messenger_ptr = std::shared_ptr<FlutterDesktopMessenger>(
45+
FlutterDesktopMessengerAddRef(messenger),
46+
&FlutterDesktopMessengerRelease);
47+
BinaryReply reply_handler = [messenger_ptr, response_handle](
4048
const uint8_t* reply,
4149
size_t reply_size) mutable {
50+
// Note: This lambda can be called on any thread.
51+
auto lock = FlutterDesktopMessengerScopedLock(
52+
FlutterDesktopMessengerLock(messenger_ptr.get()),
53+
&FlutterDesktopMessengerUnlock);
54+
if (!FlutterDesktopMessengerIsAvailable(messenger_ptr.get())) {
55+
// Drop reply if it comes in after the engine is destroyed.
56+
return;
57+
}
4258
if (!response_handle) {
4359
std::cerr << "Error: Response can be set only once. Ignoring "
4460
"duplicate response."
4561
<< std::endl;
4662
return;
4763
}
48-
FlutterDesktopMessengerSendResponse(messenger, response_handle, reply,
49-
reply_size);
64+
FlutterDesktopMessengerSendResponse(messenger_ptr.get(), response_handle,
65+
reply, reply_size);
5066
// The engine frees the response handle once
5167
// FlutterDesktopSendMessageResponse is called.
5268
response_handle = nullptr;

shell/platform/common/client_wrapper/testing/stub_flutter_api.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "flutter/shell/platform/common/client_wrapper/testing/stub_flutter_api.h"
66

7+
#include <cassert>
8+
79
static flutter::testing::StubFlutterApi* s_stub_implementation;
810

911
namespace flutter {
@@ -93,6 +95,31 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
9395
}
9496
}
9597

98+
FlutterDesktopMessengerRef FlutterDesktopMessengerAddRef(
99+
FlutterDesktopMessengerRef messenger) {
100+
assert(false); // not implemented
101+
return nullptr;
102+
}
103+
104+
void FlutterDesktopMessengerRelease(FlutterDesktopMessengerRef messenger) {
105+
assert(false); // not implemented
106+
}
107+
108+
bool FlutterDesktopMessengerIsAvailable(FlutterDesktopMessengerRef messenger) {
109+
assert(false); // not implemented
110+
return false;
111+
}
112+
113+
FlutterDesktopMessengerRef FlutterDesktopMessengerLock(
114+
FlutterDesktopMessengerRef messenger) {
115+
assert(false); // not implemented
116+
return nullptr;
117+
}
118+
119+
void FlutterDesktopMessengerUnlock(FlutterDesktopMessengerRef messenger) {
120+
assert(false); // not implemented
121+
}
122+
96123
FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(
97124
FlutterDesktopPluginRegistrarRef registrar) {
98125
return reinterpret_cast<FlutterDesktopTextureRegistrarRef>(1);

shell/platform/common/public/flutter_messenger.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MESSENGER_H_
66
#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MESSENGER_H_
77

8+
#include <stdbool.h>
89
#include <stddef.h>
910
#include <stdint.h>
1011

@@ -87,6 +88,53 @@ FLUTTER_EXPORT void FlutterDesktopMessengerSetCallback(
8788
FlutterDesktopMessageCallback callback,
8889
void* user_data);
8990

91+
// Increments the reference count for the |messenger|.
92+
//
93+
// Operation is thread-safe.
94+
//
95+
// See also: |FlutterDesktopMessengerRelease|
96+
FLUTTER_EXPORT FlutterDesktopMessengerRef
97+
FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger);
98+
99+
// Decrements the reference count for the |messenger|.
100+
//
101+
// Operation is thread-safe.
102+
//
103+
// See also: |FlutterDesktopMessengerAddRef|
104+
FLUTTER_EXPORT void FlutterDesktopMessengerRelease(
105+
FlutterDesktopMessengerRef messenger);
106+
107+
// Returns `true` if the |FlutterDesktopMessengerRef| still references a running
108+
// engine.
109+
//
110+
// This check should be made inside of a |FlutterDesktopMessengerLock| and
111+
// before any other calls are made to the FlutterDesktopMessengerRef when using
112+
// it from a thread other than the platform thread.
113+
FLUTTER_EXPORT bool FlutterDesktopMessengerIsAvailable(
114+
FlutterDesktopMessengerRef messenger);
115+
116+
// Locks the `FlutterDesktopMessengerRef` ensuring that
117+
// |FlutterDesktopMessengerIsAvailable| does not change while locked.
118+
//
119+
// All calls to the FlutterDesktopMessengerRef from threads other than the
120+
// platform thread should happen inside of a lock.
121+
//
122+
// Operation is thread-safe.
123+
//
124+
// Returns the |messenger| value.
125+
//
126+
// See also: |FlutterDesktopMessengerUnlock|
127+
FLUTTER_EXPORT FlutterDesktopMessengerRef
128+
FlutterDesktopMessengerLock(FlutterDesktopMessengerRef messenger);
129+
130+
// Unlocks the `FlutterDesktopMessengerRef`.
131+
//
132+
// Operation is thread-safe.
133+
//
134+
// See also: |FlutterDesktopMessengerLock|
135+
FLUTTER_EXPORT void FlutterDesktopMessengerUnlock(
136+
FlutterDesktopMessengerRef messenger);
137+
90138
#if defined(__cplusplus)
91139
} // extern "C"
92140
#endif

shell/platform/embedder/embedder.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,7 @@ FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
23252325
return kSuccess;
23262326
}
23272327

2328+
// Note: This can execute on any thread.
23282329
FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
23292330
FLUTTER_API_SYMBOL(FlutterEngine) engine,
23302331
const FlutterPlatformMessageResponseHandle* handle,

shell/platform/glfw/flutter_glfw.cc

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ struct AOTDataDeleter {
106106
};
107107

108108
using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>;
109+
/// Maintains one ref on the FlutterDesktopMessenger's internal reference count.
110+
using FlutterDesktopMessengerReferenceOwner =
111+
std::unique_ptr<FlutterDesktopMessenger,
112+
decltype(&FlutterDesktopMessengerRelease)>;
109113

110114
// Struct for storing state of a Flutter engine instance.
111115
struct FlutterDesktopEngineState {
@@ -116,7 +120,8 @@ struct FlutterDesktopEngineState {
116120
std::unique_ptr<flutter::EventLoop> event_loop;
117121

118122
// The plugin messenger handle given to API clients.
119-
std::unique_ptr<FlutterDesktopMessenger> messenger;
123+
FlutterDesktopMessengerReferenceOwner messenger = {
124+
nullptr, [](FlutterDesktopMessengerRef ref) {}};
120125

121126
// Message dispatch manager for messages from the Flutter engine.
122127
std::unique_ptr<flutter::IncomingMessageDispatcher> message_dispatcher;
@@ -149,10 +154,75 @@ struct FlutterDesktopPluginRegistrar {
149154

150155
// State associated with the messenger used to communicate with the engine.
151156
struct FlutterDesktopMessenger {
157+
FlutterDesktopMessenger() = default;
158+
159+
/// Increments the reference count.
160+
///
161+
/// Thread-safe.
162+
void AddRef() { ref_count_.fetch_add(1); }
163+
164+
/// Decrements the reference count and deletes the object if the count has
165+
/// gone to zero.
166+
///
167+
/// Thread-safe.
168+
void Release() {
169+
int32_t old_count = ref_count_.fetch_sub(1);
170+
if (old_count <= 1) {
171+
delete this;
172+
}
173+
}
174+
175+
/// Getter for the engine field.
176+
FlutterDesktopEngineState* GetEngine() const { return engine_; }
177+
178+
/// Setter for the engine field.
179+
/// Thread-safe.
180+
void SetEngine(FlutterDesktopEngineState* engine) {
181+
std::scoped_lock lock(mutex_);
182+
engine_ = engine;
183+
}
184+
185+
/// Returns the mutex associated with the |FlutterDesktopMessenger|.
186+
///
187+
/// This mutex is used to synchronize reading or writing state inside the
188+
/// |FlutterDesktopMessenger| (ie |engine_|).
189+
std::mutex& GetMutex() { return mutex_; }
190+
191+
FlutterDesktopMessenger(const FlutterDesktopMessenger& value) = delete;
192+
FlutterDesktopMessenger& operator=(const FlutterDesktopMessenger& value) =
193+
delete;
194+
195+
private:
152196
// The engine that backs this messenger.
153-
FlutterDesktopEngineState* engine;
197+
FlutterDesktopEngineState* engine_;
198+
std::atomic<int32_t> ref_count_ = 0;
199+
std::mutex mutex_;
154200
};
155201

202+
FlutterDesktopMessengerRef FlutterDesktopMessengerAddRef(
203+
FlutterDesktopMessengerRef messenger) {
204+
messenger->AddRef();
205+
return messenger;
206+
}
207+
208+
void FlutterDesktopMessengerRelease(FlutterDesktopMessengerRef messenger) {
209+
messenger->Release();
210+
}
211+
212+
bool FlutterDesktopMessengerIsAvailable(FlutterDesktopMessengerRef messenger) {
213+
return messenger->GetEngine() != nullptr;
214+
}
215+
216+
FlutterDesktopMessengerRef FlutterDesktopMessengerLock(
217+
FlutterDesktopMessengerRef messenger) {
218+
messenger->GetMutex().lock();
219+
return messenger;
220+
}
221+
222+
void FlutterDesktopMessengerUnlock(FlutterDesktopMessengerRef messenger) {
223+
messenger->GetMutex().unlock();
224+
}
225+
156226
// Retrieves state bag for the window in question from the GLFWWindow.
157227
static FlutterDesktopWindowControllerState* GetWindowController(
158228
GLFWwindow* window) {
@@ -743,8 +813,10 @@ static void SetUpLocales(FlutterDesktopEngineState* state) {
743813
static void SetUpCommonEngineState(FlutterDesktopEngineState* state,
744814
GLFWwindow* window) {
745815
// Messaging.
746-
state->messenger = std::make_unique<FlutterDesktopMessenger>();
747-
state->messenger->engine = state;
816+
state->messenger = FlutterDesktopMessengerReferenceOwner(
817+
FlutterDesktopMessengerAddRef(new FlutterDesktopMessenger()),
818+
&FlutterDesktopMessengerRelease);
819+
state->messenger->SetEngine(state);
748820
state->message_dispatcher =
749821
std::make_unique<flutter::IncomingMessageDispatcher>(
750822
state->messenger.get());
@@ -846,6 +918,7 @@ FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow(
846918
}
847919

848920
void FlutterDesktopDestroyWindow(FlutterDesktopWindowControllerRef controller) {
921+
controller->engine->messenger->SetEngine(nullptr);
849922
FlutterDesktopPluginRegistrarRef registrar =
850923
controller->engine->plugin_registrar.get();
851924
if (registrar->destruction_handler) {
@@ -1045,7 +1118,8 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger,
10451118
FlutterPlatformMessageResponseHandle* response_handle = nullptr;
10461119
if (reply != nullptr && user_data != nullptr) {
10471120
FlutterEngineResult result = FlutterPlatformMessageCreateResponseHandle(
1048-
messenger->engine->flutter_engine, reply, user_data, &response_handle);
1121+
messenger->GetEngine()->flutter_engine, reply, user_data,
1122+
&response_handle);
10491123
if (result != kSuccess) {
10501124
std::cout << "Failed to create response handle\n";
10511125
return false;
@@ -1061,11 +1135,11 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger,
10611135
};
10621136

10631137
FlutterEngineResult message_result = FlutterEngineSendPlatformMessage(
1064-
messenger->engine->flutter_engine, &platform_message);
1138+
messenger->GetEngine()->flutter_engine, &platform_message);
10651139

10661140
if (response_handle != nullptr) {
10671141
FlutterPlatformMessageReleaseResponseHandle(
1068-
messenger->engine->flutter_engine, response_handle);
1142+
messenger->GetEngine()->flutter_engine, response_handle);
10691143
}
10701144

10711145
return message_result == kSuccess;
@@ -1084,16 +1158,16 @@ void FlutterDesktopMessengerSendResponse(
10841158
const FlutterDesktopMessageResponseHandle* handle,
10851159
const uint8_t* data,
10861160
size_t data_length) {
1087-
FlutterEngineSendPlatformMessageResponse(messenger->engine->flutter_engine,
1088-
handle, data, data_length);
1161+
FlutterEngineSendPlatformMessageResponse(
1162+
messenger->GetEngine()->flutter_engine, handle, data, data_length);
10891163
}
10901164

10911165
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
10921166
const char* channel,
10931167
FlutterDesktopMessageCallback callback,
10941168
void* user_data) {
1095-
messenger->engine->message_dispatcher->SetMessageCallback(channel, callback,
1096-
user_data);
1169+
messenger->GetEngine()->message_dispatcher->SetMessageCallback(
1170+
channel, callback, user_data);
10971171
}
10981172

10991173
FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(

0 commit comments

Comments
 (0)