Implemented threadsafe platform channel replies on windows (flutter/engine#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
This commit is contained in:
@@ -3099,6 +3099,7 @@ FILE: ../../../flutter/shell/platform/windows/external_texture_d3d.cc
|
||||
FILE: ../../../flutter/shell/platform/windows/external_texture_d3d.h
|
||||
FILE: ../../../flutter/shell/platform/windows/external_texture_pixelbuffer.cc
|
||||
FILE: ../../../flutter/shell/platform/windows/external_texture_pixelbuffer.h
|
||||
FILE: ../../../flutter/shell/platform/windows/flutter_desktop_messenger.h
|
||||
FILE: ../../../flutter/shell/platform/windows/flutter_key_map.g.cc
|
||||
FILE: ../../../flutter/shell/platform/windows/flutter_platform_node_delegate_windows.cc
|
||||
FILE: ../../../flutter/shell/platform/windows/flutter_platform_node_delegate_windows.h
|
||||
|
||||
@@ -26,6 +26,11 @@ namespace flutter {
|
||||
// ========== binary_messenger_impl.h ==========
|
||||
|
||||
namespace {
|
||||
|
||||
using FlutterDesktopMessengerScopedLock =
|
||||
std::unique_ptr<FlutterDesktopMessenger,
|
||||
decltype(&FlutterDesktopMessengerUnlock)>;
|
||||
|
||||
// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along
|
||||
// with a BinaryReply that will send a response on |message|'s response handle.
|
||||
//
|
||||
@@ -36,17 +41,28 @@ void ForwardToHandler(FlutterDesktopMessengerRef messenger,
|
||||
const FlutterDesktopMessage* message,
|
||||
void* user_data) {
|
||||
auto* response_handle = message->response_handle;
|
||||
BinaryReply reply_handler = [messenger, response_handle](
|
||||
auto messenger_ptr = std::shared_ptr<FlutterDesktopMessenger>(
|
||||
FlutterDesktopMessengerAddRef(messenger),
|
||||
&FlutterDesktopMessengerRelease);
|
||||
BinaryReply reply_handler = [messenger_ptr, response_handle](
|
||||
const uint8_t* reply,
|
||||
size_t reply_size) mutable {
|
||||
// Note: This lambda can be called on any thread.
|
||||
auto lock = FlutterDesktopMessengerScopedLock(
|
||||
FlutterDesktopMessengerLock(messenger_ptr.get()),
|
||||
&FlutterDesktopMessengerUnlock);
|
||||
if (!FlutterDesktopMessengerIsAvailable(messenger_ptr.get())) {
|
||||
// Drop reply if it comes in after the engine is destroyed.
|
||||
return;
|
||||
}
|
||||
if (!response_handle) {
|
||||
std::cerr << "Error: Response can be set only once. Ignoring "
|
||||
"duplicate response."
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
FlutterDesktopMessengerSendResponse(messenger, response_handle, reply,
|
||||
reply_size);
|
||||
FlutterDesktopMessengerSendResponse(messenger_ptr.get(), response_handle,
|
||||
reply, reply_size);
|
||||
// The engine frees the response handle once
|
||||
// FlutterDesktopSendMessageResponse is called.
|
||||
response_handle = nullptr;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "flutter/shell/platform/common/client_wrapper/testing/stub_flutter_api.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
static flutter::testing::StubFlutterApi* s_stub_implementation;
|
||||
|
||||
namespace flutter {
|
||||
@@ -93,6 +95,31 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
|
||||
}
|
||||
}
|
||||
|
||||
FlutterDesktopMessengerRef FlutterDesktopMessengerAddRef(
|
||||
FlutterDesktopMessengerRef messenger) {
|
||||
assert(false); // not implemented
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerRelease(FlutterDesktopMessengerRef messenger) {
|
||||
assert(false); // not implemented
|
||||
}
|
||||
|
||||
bool FlutterDesktopMessengerIsAvailable(FlutterDesktopMessengerRef messenger) {
|
||||
assert(false); // not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
FlutterDesktopMessengerRef FlutterDesktopMessengerLock(
|
||||
FlutterDesktopMessengerRef messenger) {
|
||||
assert(false); // not implemented
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerUnlock(FlutterDesktopMessengerRef messenger) {
|
||||
assert(false); // not implemented
|
||||
}
|
||||
|
||||
FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar) {
|
||||
return reinterpret_cast<FlutterDesktopTextureRegistrarRef>(1);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MESSENGER_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MESSENGER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -87,6 +88,53 @@ FLUTTER_EXPORT void FlutterDesktopMessengerSetCallback(
|
||||
FlutterDesktopMessageCallback callback,
|
||||
void* user_data);
|
||||
|
||||
// Increments the reference count for the |messenger|.
|
||||
//
|
||||
// Operation is thread-safe.
|
||||
//
|
||||
// See also: |FlutterDesktopMessengerRelease|
|
||||
FLUTTER_EXPORT FlutterDesktopMessengerRef
|
||||
FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger);
|
||||
|
||||
// Decrements the reference count for the |messenger|.
|
||||
//
|
||||
// Operation is thread-safe.
|
||||
//
|
||||
// See also: |FlutterDesktopMessengerAddRef|
|
||||
FLUTTER_EXPORT void FlutterDesktopMessengerRelease(
|
||||
FlutterDesktopMessengerRef messenger);
|
||||
|
||||
// Returns `true` if the |FlutterDesktopMessengerRef| still references a running
|
||||
// engine.
|
||||
//
|
||||
// This check should be made inside of a |FlutterDesktopMessengerLock| and
|
||||
// before any other calls are made to the FlutterDesktopMessengerRef when using
|
||||
// it from a thread other than the platform thread.
|
||||
FLUTTER_EXPORT bool FlutterDesktopMessengerIsAvailable(
|
||||
FlutterDesktopMessengerRef messenger);
|
||||
|
||||
// Locks the `FlutterDesktopMessengerRef` ensuring that
|
||||
// |FlutterDesktopMessengerIsAvailable| does not change while locked.
|
||||
//
|
||||
// All calls to the FlutterDesktopMessengerRef from threads other than the
|
||||
// platform thread should happen inside of a lock.
|
||||
//
|
||||
// Operation is thread-safe.
|
||||
//
|
||||
// Returns the |messenger| value.
|
||||
//
|
||||
// See also: |FlutterDesktopMessengerUnlock|
|
||||
FLUTTER_EXPORT FlutterDesktopMessengerRef
|
||||
FlutterDesktopMessengerLock(FlutterDesktopMessengerRef messenger);
|
||||
|
||||
// Unlocks the `FlutterDesktopMessengerRef`.
|
||||
//
|
||||
// Operation is thread-safe.
|
||||
//
|
||||
// See also: |FlutterDesktopMessengerLock|
|
||||
FLUTTER_EXPORT void FlutterDesktopMessengerUnlock(
|
||||
FlutterDesktopMessengerRef messenger);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@@ -2325,6 +2325,7 @@ FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
// Note: This can execute on any thread.
|
||||
FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
|
||||
FLUTTER_API_SYMBOL(FlutterEngine) engine,
|
||||
const FlutterPlatformMessageResponseHandle* handle,
|
||||
|
||||
@@ -106,6 +106,10 @@ struct AOTDataDeleter {
|
||||
};
|
||||
|
||||
using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>;
|
||||
/// Maintains one ref on the FlutterDesktopMessenger's internal reference count.
|
||||
using FlutterDesktopMessengerReferenceOwner =
|
||||
std::unique_ptr<FlutterDesktopMessenger,
|
||||
decltype(&FlutterDesktopMessengerRelease)>;
|
||||
|
||||
// Struct for storing state of a Flutter engine instance.
|
||||
struct FlutterDesktopEngineState {
|
||||
@@ -116,7 +120,8 @@ struct FlutterDesktopEngineState {
|
||||
std::unique_ptr<flutter::EventLoop> event_loop;
|
||||
|
||||
// The plugin messenger handle given to API clients.
|
||||
std::unique_ptr<FlutterDesktopMessenger> messenger;
|
||||
FlutterDesktopMessengerReferenceOwner messenger = {
|
||||
nullptr, [](FlutterDesktopMessengerRef ref) {}};
|
||||
|
||||
// Message dispatch manager for messages from the Flutter engine.
|
||||
std::unique_ptr<flutter::IncomingMessageDispatcher> message_dispatcher;
|
||||
@@ -149,10 +154,75 @@ struct FlutterDesktopPluginRegistrar {
|
||||
|
||||
// State associated with the messenger used to communicate with the engine.
|
||||
struct FlutterDesktopMessenger {
|
||||
FlutterDesktopMessenger() = default;
|
||||
|
||||
/// Increments the reference count.
|
||||
///
|
||||
/// Thread-safe.
|
||||
void AddRef() { ref_count_.fetch_add(1); }
|
||||
|
||||
/// Decrements the reference count and deletes the object if the count has
|
||||
/// gone to zero.
|
||||
///
|
||||
/// Thread-safe.
|
||||
void Release() {
|
||||
int32_t old_count = ref_count_.fetch_sub(1);
|
||||
if (old_count <= 1) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
/// Getter for the engine field.
|
||||
FlutterDesktopEngineState* GetEngine() const { return engine_; }
|
||||
|
||||
/// Setter for the engine field.
|
||||
/// Thread-safe.
|
||||
void SetEngine(FlutterDesktopEngineState* engine) {
|
||||
std::scoped_lock lock(mutex_);
|
||||
engine_ = engine;
|
||||
}
|
||||
|
||||
/// Returns the mutex associated with the |FlutterDesktopMessenger|.
|
||||
///
|
||||
/// This mutex is used to synchronize reading or writing state inside the
|
||||
/// |FlutterDesktopMessenger| (ie |engine_|).
|
||||
std::mutex& GetMutex() { return mutex_; }
|
||||
|
||||
FlutterDesktopMessenger(const FlutterDesktopMessenger& value) = delete;
|
||||
FlutterDesktopMessenger& operator=(const FlutterDesktopMessenger& value) =
|
||||
delete;
|
||||
|
||||
private:
|
||||
// The engine that backs this messenger.
|
||||
FlutterDesktopEngineState* engine;
|
||||
FlutterDesktopEngineState* engine_;
|
||||
std::atomic<int32_t> ref_count_ = 0;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
FlutterDesktopMessengerRef FlutterDesktopMessengerAddRef(
|
||||
FlutterDesktopMessengerRef messenger) {
|
||||
messenger->AddRef();
|
||||
return messenger;
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerRelease(FlutterDesktopMessengerRef messenger) {
|
||||
messenger->Release();
|
||||
}
|
||||
|
||||
bool FlutterDesktopMessengerIsAvailable(FlutterDesktopMessengerRef messenger) {
|
||||
return messenger->GetEngine() != nullptr;
|
||||
}
|
||||
|
||||
FlutterDesktopMessengerRef FlutterDesktopMessengerLock(
|
||||
FlutterDesktopMessengerRef messenger) {
|
||||
messenger->GetMutex().lock();
|
||||
return messenger;
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerUnlock(FlutterDesktopMessengerRef messenger) {
|
||||
messenger->GetMutex().unlock();
|
||||
}
|
||||
|
||||
// Retrieves state bag for the window in question from the GLFWWindow.
|
||||
static FlutterDesktopWindowControllerState* GetWindowController(
|
||||
GLFWwindow* window) {
|
||||
@@ -743,8 +813,10 @@ static void SetUpLocales(FlutterDesktopEngineState* state) {
|
||||
static void SetUpCommonEngineState(FlutterDesktopEngineState* state,
|
||||
GLFWwindow* window) {
|
||||
// Messaging.
|
||||
state->messenger = std::make_unique<FlutterDesktopMessenger>();
|
||||
state->messenger->engine = state;
|
||||
state->messenger = FlutterDesktopMessengerReferenceOwner(
|
||||
FlutterDesktopMessengerAddRef(new FlutterDesktopMessenger()),
|
||||
&FlutterDesktopMessengerRelease);
|
||||
state->messenger->SetEngine(state);
|
||||
state->message_dispatcher =
|
||||
std::make_unique<flutter::IncomingMessageDispatcher>(
|
||||
state->messenger.get());
|
||||
@@ -846,6 +918,7 @@ FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow(
|
||||
}
|
||||
|
||||
void FlutterDesktopDestroyWindow(FlutterDesktopWindowControllerRef controller) {
|
||||
controller->engine->messenger->SetEngine(nullptr);
|
||||
FlutterDesktopPluginRegistrarRef registrar =
|
||||
controller->engine->plugin_registrar.get();
|
||||
if (registrar->destruction_handler) {
|
||||
@@ -1045,7 +1118,8 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger,
|
||||
FlutterPlatformMessageResponseHandle* response_handle = nullptr;
|
||||
if (reply != nullptr && user_data != nullptr) {
|
||||
FlutterEngineResult result = FlutterPlatformMessageCreateResponseHandle(
|
||||
messenger->engine->flutter_engine, reply, user_data, &response_handle);
|
||||
messenger->GetEngine()->flutter_engine, reply, user_data,
|
||||
&response_handle);
|
||||
if (result != kSuccess) {
|
||||
std::cout << "Failed to create response handle\n";
|
||||
return false;
|
||||
@@ -1061,11 +1135,11 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger,
|
||||
};
|
||||
|
||||
FlutterEngineResult message_result = FlutterEngineSendPlatformMessage(
|
||||
messenger->engine->flutter_engine, &platform_message);
|
||||
messenger->GetEngine()->flutter_engine, &platform_message);
|
||||
|
||||
if (response_handle != nullptr) {
|
||||
FlutterPlatformMessageReleaseResponseHandle(
|
||||
messenger->engine->flutter_engine, response_handle);
|
||||
messenger->GetEngine()->flutter_engine, response_handle);
|
||||
}
|
||||
|
||||
return message_result == kSuccess;
|
||||
@@ -1084,16 +1158,16 @@ void FlutterDesktopMessengerSendResponse(
|
||||
const FlutterDesktopMessageResponseHandle* handle,
|
||||
const uint8_t* data,
|
||||
size_t data_length) {
|
||||
FlutterEngineSendPlatformMessageResponse(messenger->engine->flutter_engine,
|
||||
handle, data, data_length);
|
||||
FlutterEngineSendPlatformMessageResponse(
|
||||
messenger->GetEngine()->flutter_engine, handle, data, data_length);
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
|
||||
const char* channel,
|
||||
FlutterDesktopMessageCallback callback,
|
||||
void* user_data) {
|
||||
messenger->engine->message_dispatcher->SetMessageCallback(channel, callback,
|
||||
user_data);
|
||||
messenger->GetEngine()->message_dispatcher->SetMessageCallback(
|
||||
channel, callback, user_data);
|
||||
}
|
||||
|
||||
FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_DESKTOP_MESSENGER_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_DESKTOP_MESSENGER_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include "flutter/shell/platform/common/public/flutter_messenger.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class FlutterWindowsEngine;
|
||||
|
||||
/// A messenger object used to invoke platform messages.
|
||||
///
|
||||
/// On Windows, the message handler is essentially the |FlutterWindowsEngine|,
|
||||
/// this allows a handle to the |FlutterWindowsEngine| that will become
|
||||
/// invalidated if the |FlutterWindowsEngine| is destroyed.
|
||||
class FlutterDesktopMessenger {
|
||||
public:
|
||||
FlutterDesktopMessenger() = default;
|
||||
|
||||
/// Convert to FlutterDesktopMessengerRef.
|
||||
FlutterDesktopMessengerRef ToRef() {
|
||||
return reinterpret_cast<FlutterDesktopMessengerRef>(this);
|
||||
}
|
||||
|
||||
/// Convert from FlutterDesktopMessengerRef.
|
||||
static FlutterDesktopMessenger* FromRef(FlutterDesktopMessengerRef ref) {
|
||||
return reinterpret_cast<FlutterDesktopMessenger*>(ref);
|
||||
}
|
||||
|
||||
/// Getter for the engine field.
|
||||
flutter::FlutterWindowsEngine* GetEngine() const { return engine; }
|
||||
|
||||
/// Setter for the engine field.
|
||||
/// Thread-safe.
|
||||
void SetEngine(flutter::FlutterWindowsEngine* arg_engine) {
|
||||
std::scoped_lock lock(mutex_);
|
||||
engine = arg_engine;
|
||||
}
|
||||
|
||||
/// Increments the reference count.
|
||||
///
|
||||
/// Thread-safe.
|
||||
FlutterDesktopMessenger* AddRef() {
|
||||
ref_count_.fetch_add(1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Decrements the reference count and deletes the object if the count has
|
||||
/// gone to zero.
|
||||
///
|
||||
/// Thread-safe.
|
||||
void Release() {
|
||||
int32_t old_count = ref_count_.fetch_sub(1);
|
||||
if (old_count <= 1) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the mutex associated with the |FlutterDesktopMessenger|.
|
||||
///
|
||||
/// This mutex is used to synchronize reading or writing state inside the
|
||||
/// |FlutterDesktopMessenger| (ie |engine|).
|
||||
std::mutex& GetMutex() { return mutex_; }
|
||||
|
||||
FlutterDesktopMessenger(const FlutterDesktopMessenger& value) = delete;
|
||||
FlutterDesktopMessenger& operator=(const FlutterDesktopMessenger& value) =
|
||||
delete;
|
||||
|
||||
private:
|
||||
// The engine that owns this state object.
|
||||
flutter::FlutterWindowsEngine* engine = nullptr;
|
||||
std::mutex mutex_;
|
||||
std::atomic<int32_t> ref_count_ = 0;
|
||||
};
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOW_STATE_H_
|
||||
@@ -262,8 +262,9 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger,
|
||||
const size_t message_size,
|
||||
const FlutterDesktopBinaryReply reply,
|
||||
void* user_data) {
|
||||
return messenger->engine->SendPlatformMessage(channel, message, message_size,
|
||||
reply, user_data);
|
||||
return flutter::FlutterDesktopMessenger::FromRef(messenger)
|
||||
->GetEngine()
|
||||
->SendPlatformMessage(channel, message, message_size, reply, user_data);
|
||||
}
|
||||
|
||||
bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger,
|
||||
@@ -279,15 +280,45 @@ void FlutterDesktopMessengerSendResponse(
|
||||
const FlutterDesktopMessageResponseHandle* handle,
|
||||
const uint8_t* data,
|
||||
size_t data_length) {
|
||||
messenger->engine->SendPlatformMessageResponse(handle, data, data_length);
|
||||
flutter::FlutterDesktopMessenger::FromRef(messenger)
|
||||
->GetEngine()
|
||||
->SendPlatformMessageResponse(handle, data, data_length);
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
|
||||
const char* channel,
|
||||
FlutterDesktopMessageCallback callback,
|
||||
void* user_data) {
|
||||
messenger->engine->message_dispatcher()->SetMessageCallback(channel, callback,
|
||||
user_data);
|
||||
flutter::FlutterDesktopMessenger::FromRef(messenger)
|
||||
->GetEngine()
|
||||
->message_dispatcher()
|
||||
->SetMessageCallback(channel, callback, user_data);
|
||||
}
|
||||
|
||||
FlutterDesktopMessengerRef FlutterDesktopMessengerAddRef(
|
||||
FlutterDesktopMessengerRef messenger) {
|
||||
return flutter::FlutterDesktopMessenger::FromRef(messenger)
|
||||
->AddRef()
|
||||
->ToRef();
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerRelease(FlutterDesktopMessengerRef messenger) {
|
||||
flutter::FlutterDesktopMessenger::FromRef(messenger)->Release();
|
||||
}
|
||||
|
||||
bool FlutterDesktopMessengerIsAvailable(FlutterDesktopMessengerRef messenger) {
|
||||
return flutter::FlutterDesktopMessenger::FromRef(messenger)->GetEngine() !=
|
||||
nullptr;
|
||||
}
|
||||
|
||||
FlutterDesktopMessengerRef FlutterDesktopMessengerLock(
|
||||
FlutterDesktopMessengerRef messenger) {
|
||||
flutter::FlutterDesktopMessenger::FromRef(messenger)->GetMutex().lock();
|
||||
return messenger;
|
||||
}
|
||||
|
||||
void FlutterDesktopMessengerUnlock(FlutterDesktopMessengerRef messenger) {
|
||||
flutter::FlutterDesktopMessenger::FromRef(messenger)->GetMutex().unlock();
|
||||
}
|
||||
|
||||
FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(
|
||||
|
||||
@@ -179,14 +179,16 @@ FlutterWindowsEngine::FlutterWindowsEngine(
|
||||
});
|
||||
|
||||
// Set up the legacy structs backing the API handles.
|
||||
messenger_ = std::make_unique<FlutterDesktopMessenger>();
|
||||
messenger_->engine = this;
|
||||
messenger_ =
|
||||
fml::RefPtr<FlutterDesktopMessenger>(new FlutterDesktopMessenger());
|
||||
messenger_->SetEngine(this);
|
||||
plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
|
||||
plugin_registrar_->engine = this;
|
||||
|
||||
messenger_wrapper_ = std::make_unique<BinaryMessengerImpl>(messenger_.get());
|
||||
messenger_wrapper_ =
|
||||
std::make_unique<BinaryMessengerImpl>(messenger_->ToRef());
|
||||
message_dispatcher_ =
|
||||
std::make_unique<IncomingMessageDispatcher>(messenger_.get());
|
||||
std::make_unique<IncomingMessageDispatcher>(messenger_->ToRef());
|
||||
message_dispatcher_->SetMessageCallback(
|
||||
kAccessibilityChannelName,
|
||||
[](FlutterDesktopMessengerRef messenger,
|
||||
@@ -210,6 +212,7 @@ FlutterWindowsEngine::FlutterWindowsEngine(
|
||||
}
|
||||
|
||||
FlutterWindowsEngine::~FlutterWindowsEngine() {
|
||||
messenger_->SetEngine(nullptr);
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "flutter/shell/platform/common/incoming_message_dispatcher.h"
|
||||
#include "flutter/shell/platform/embedder/embedder.h"
|
||||
#include "flutter/shell/platform/windows/angle_surface_manager.h"
|
||||
#include "flutter/shell/platform/windows/flutter_desktop_messenger.h"
|
||||
#include "flutter/shell/platform/windows/flutter_project_bundle.h"
|
||||
#include "flutter/shell/platform/windows/flutter_windows_texture_registrar.h"
|
||||
#include "flutter/shell/platform/windows/public/flutter_windows.h"
|
||||
@@ -124,7 +125,7 @@ class FlutterWindowsEngine {
|
||||
// Sets switches member to the given switches.
|
||||
void SetSwitches(const std::vector<std::string>& switches);
|
||||
|
||||
FlutterDesktopMessengerRef messenger() { return messenger_.get(); }
|
||||
FlutterDesktopMessengerRef messenger() { return messenger_->ToRef(); }
|
||||
|
||||
IncomingMessageDispatcher* message_dispatcher() {
|
||||
return message_dispatcher_.get();
|
||||
@@ -283,7 +284,7 @@ class FlutterWindowsEngine {
|
||||
std::unique_ptr<TaskRunner> task_runner_;
|
||||
|
||||
// The plugin messenger handle given to API clients.
|
||||
std::unique_ptr<FlutterDesktopMessenger> messenger_;
|
||||
fml::RefPtr<flutter::FlutterDesktopMessenger> messenger_;
|
||||
|
||||
// A wrapper around messenger_ for interacting with client_wrapper-level APIs.
|
||||
std::unique_ptr<BinaryMessengerImpl> messenger_wrapper_;
|
||||
|
||||
@@ -311,6 +311,60 @@ TEST_F(FlutterWindowsEngineTest, PlatformMessageRoundTrip) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FlutterWindowsEngineTest, PlatformMessageRespondOnDifferentThread) {
|
||||
FlutterDesktopEngineProperties properties = {};
|
||||
properties.assets_path = GetContext().GetAssetsPath().c_str();
|
||||
properties.icu_data_path = GetContext().GetIcuDataPath().c_str();
|
||||
properties.dart_entrypoint = "hiPlatformChannels";
|
||||
|
||||
FlutterProjectBundle project(properties);
|
||||
auto engine = std::make_unique<FlutterWindowsEngine>(project);
|
||||
|
||||
EngineModifier modifier(engine.get());
|
||||
modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
|
||||
|
||||
auto binary_messenger =
|
||||
std::make_unique<BinaryMessengerImpl>(engine->messenger());
|
||||
|
||||
engine->Run();
|
||||
bool did_call_callback = false;
|
||||
bool did_call_reply = false;
|
||||
bool did_call_dart_reply = false;
|
||||
std::string channel = "hi";
|
||||
std::unique_ptr<std::thread> reply_thread;
|
||||
binary_messenger->SetMessageHandler(
|
||||
channel,
|
||||
[&did_call_callback, &did_call_dart_reply, &reply_thread](
|
||||
const uint8_t* message, size_t message_size, BinaryReply reply) {
|
||||
if (message_size == 5) {
|
||||
EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
|
||||
reply_thread.reset(new std::thread([reply = std::move(reply)]() {
|
||||
char response[] = {'b', 'y', 'e'};
|
||||
reply(reinterpret_cast<uint8_t*>(response), 3);
|
||||
}));
|
||||
did_call_callback = true;
|
||||
} else {
|
||||
EXPECT_EQ(message_size, 3);
|
||||
EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
|
||||
did_call_dart_reply = true;
|
||||
}
|
||||
});
|
||||
char payload[] = {'h', 'e', 'l', 'l', 'o'};
|
||||
binary_messenger->Send(
|
||||
channel, reinterpret_cast<uint8_t*>(payload), 5,
|
||||
[&did_call_reply](const uint8_t* reply, size_t reply_size) {
|
||||
EXPECT_EQ(reply_size, 5);
|
||||
EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
|
||||
did_call_reply = true;
|
||||
});
|
||||
// Rely on timeout mechanism in CI.
|
||||
while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
|
||||
engine->task_runner()->ProcessTasks();
|
||||
}
|
||||
ASSERT_TRUE(reply_thread);
|
||||
reply_thread->join();
|
||||
}
|
||||
|
||||
TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithResponse) {
|
||||
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
|
||||
EngineModifier modifier(engine.get());
|
||||
|
||||
@@ -181,6 +181,12 @@ FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine,
|
||||
const char* plugin_name);
|
||||
|
||||
// Returns the messenger associated with the engine.
|
||||
//
|
||||
// This does not provide an owning reference, so should *not* be balanced with a
|
||||
// call to |FlutterDesktopMessengerRelease|.
|
||||
//
|
||||
// Callers should use |FlutterDesktopMessengerAddRef| if the returned pointer
|
||||
// will potentially outlive 'engine', such as when passing it to another thread.
|
||||
FLUTTER_EXPORT FlutterDesktopMessengerRef
|
||||
FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine);
|
||||
|
||||
|
||||
@@ -33,11 +33,4 @@ struct FlutterDesktopPluginRegistrar {
|
||||
flutter::FlutterWindowsEngine* engine = nullptr;
|
||||
};
|
||||
|
||||
// Wrapper to distinguish the messenger ref from the engine ref given out
|
||||
// in the C API.
|
||||
struct FlutterDesktopMessenger {
|
||||
// The engine that owns this state object.
|
||||
flutter::FlutterWindowsEngine* engine = nullptr;
|
||||
};
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOW_STATE_H_
|
||||
|
||||
Reference in New Issue
Block a user