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

[windows] Expose the binary messenger from FlutterEngine #20551

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,9 @@ FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.h
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/basic_message_channel_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/binary_messenger_impl.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/byte_buffer_streams.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/core_implementations.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/encodable_value_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/engine_method_result.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/event_channel_unittests.cc
Expand Down
6 changes: 4 additions & 2 deletions shell/platform/common/cpp/client_wrapper/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import("core_wrapper_files.gni")
# Client library build for internal use by the shell implementation.
source_set("client_wrapper") {
sources = core_cpp_client_wrapper_sources
public = core_cpp_client_wrapper_includes
public = core_cpp_client_wrapper_includes +
core_cpp_client_wrapper_internal_headers

deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ]

Expand All @@ -23,7 +24,8 @@ source_set("client_wrapper") {
# legacy version is removed.
source_set("client_wrapper_legacy_encodable_value") {
sources = core_cpp_client_wrapper_sources
public = core_cpp_client_wrapper_includes
public = core_cpp_client_wrapper_includes +
core_cpp_client_wrapper_internal_headers

deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ]

Expand Down
50 changes: 50 additions & 0 deletions shell/platform/common/cpp/client_wrapper/binary_messenger_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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_COMMON_CPP_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_

#include <flutter_messenger.h>

#include <map>
#include <string>

#include "include/flutter/binary_messenger.h"

namespace flutter {

// Wrapper around a FlutterDesktopMessengerRef that implements the
// BinaryMessenger API.
class BinaryMessengerImpl : public BinaryMessenger {
public:
explicit BinaryMessengerImpl(FlutterDesktopMessengerRef core_messenger);

virtual ~BinaryMessengerImpl();

// Prevent copying.
BinaryMessengerImpl(BinaryMessengerImpl const&) = delete;
BinaryMessengerImpl& operator=(BinaryMessengerImpl const&) = delete;

// |flutter::BinaryMessenger|
void Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const override;

// |flutter::BinaryMessenger|
void SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) override;

private:
// Handle for interacting with the C API.
FlutterDesktopMessengerRef messenger_;

// A map from channel names to the BinaryMessageHandler that should be called
// for incoming messages on that channel.
std::map<std::string, BinaryMessageHandler> handlers_;
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
150 changes: 150 additions & 0 deletions shell/platform/common/cpp/client_wrapper/core_implementations.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// 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.

// This file contains the implementations of any class in the wrapper that
// - is not fully inline, and
// - is necessary for all clients of the wrapper (either app or plugin).
// It exists instead of the usual structure of having some_class_name.cc files
// so that changes to the set of things that need non-header implementations
// are not breaking changes for the template.
//
// If https://github.com/flutter/flutter/issues/57146 is fixed, this can be
// removed in favor of the normal structure since templates will no longer
// manually include files.

#include <assert.h>

#include <iostream>

#include "binary_messenger_impl.h"
#include "include/flutter/engine_method_result.h"

namespace flutter {

// ========== binary_messenger_impl.h ==========

namespace {
// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along
// with a BinaryReply that will send a response on |message|'s response handle.
//
// This serves as an adaptor between the function-pointer-based message callback
// interface provided by the C API and the std::function-based message handler
// interface of BinaryMessenger.
void ForwardToHandler(FlutterDesktopMessengerRef messenger,
const FlutterDesktopMessage* message,
void* user_data) {
auto* response_handle = message->response_handle;
BinaryReply reply_handler = [messenger, response_handle](
const uint8_t* reply,
size_t reply_size) mutable {
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);
// The engine frees the response handle once
// FlutterDesktopSendMessageResponse is called.
response_handle = nullptr;
};

const BinaryMessageHandler& message_handler =
*static_cast<BinaryMessageHandler*>(user_data);

message_handler(message->message, message->message_size,
std::move(reply_handler));
}
} // namespace

BinaryMessengerImpl::BinaryMessengerImpl(
FlutterDesktopMessengerRef core_messenger)
: messenger_(core_messenger) {}

BinaryMessengerImpl::~BinaryMessengerImpl() = default;

void BinaryMessengerImpl::Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const {
if (reply == nullptr) {
FlutterDesktopMessengerSend(messenger_, channel.c_str(), message,
message_size);
return;
}
struct Captures {
BinaryReply reply;
};
auto captures = new Captures();
captures->reply = reply;

auto message_reply = [](const uint8_t* data, size_t data_size,
void* user_data) {
auto captures = reinterpret_cast<Captures*>(user_data);
captures->reply(data, data_size);
delete captures;
};
bool result = FlutterDesktopMessengerSendWithReply(
messenger_, channel.c_str(), message, message_size, message_reply,
captures);
if (!result) {
delete captures;
}
}

void BinaryMessengerImpl::SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) {
if (!handler) {
handlers_.erase(channel);
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(), nullptr,
nullptr);
return;
}
// Save the handler, to keep it alive.
handlers_[channel] = std::move(handler);
BinaryMessageHandler* message_handler = &handlers_[channel];
// Set an adaptor callback that will invoke the handler.
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(),
ForwardToHandler, message_handler);
}

// ========== engine_method_result.h ==========

namespace internal {

ReplyManager::ReplyManager(BinaryReply reply_handler)
: reply_handler_(std::move(reply_handler)) {
assert(reply_handler_);
}

ReplyManager::~ReplyManager() {
if (reply_handler_) {
// Warn, rather than send a not-implemented response, since the engine may
// no longer be valid at this point.
std::cerr
<< "Warning: Failed to respond to a message. This is a memory leak."
<< std::endl;
}
}

void ReplyManager::SendResponseData(const std::vector<uint8_t>* data) {
if (!reply_handler_) {
std::cerr
<< "Error: Only one of Success, Error, or NotImplemented can be "
"called,"
<< " and it can be called exactly once. Ignoring duplicate result."
<< std::endl;
return;
}

const uint8_t* message = data && !data->empty() ? data->data() : nullptr;
size_t message_size = data ? data->size() : 0;
reply_handler_(message, message_size);
reply_handler_ = nullptr;
}

} // namespace internal

} // namespace flutter
17 changes: 15 additions & 2 deletions shell/platform/common/cpp/client_wrapper/core_wrapper_files.gni
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,26 @@ core_cpp_client_wrapper_includes =
],
"abspath")

# Headers that aren't public for clients of the wrapper, but are considered
# public for the purpose of BUILD dependencies (e.g., to allow
# windows/client_wrapper implementation files to include them).
core_cpp_client_wrapper_internal_headers =
get_path_info([
"binary_messenger_impl.h",
"byte_buffer_streams.h",
],
"abspath")

# TODO: Once the wrapper API is more stable, consolidate to as few files as is
# reasonable (without forcing different kinds of clients to take unnecessary
# code) to simplify use.
core_cpp_client_wrapper_sources = get_path_info([
"byte_buffer_streams.h",
"engine_method_result.cc",
"core_implementations.cc",
"plugin_registrar.cc",
"standard_codec.cc",
],
"abspath")

# Temporary shim, published for backwards compatibility.
# See comment in the file for more detail.
temporary_shim_files = get_path_info([ "engine_method_result.cc" ], "abspath")
46 changes: 6 additions & 40 deletions shell/platform/common/cpp/client_wrapper/engine_method_result.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "include/flutter/engine_method_result.h"
// This file is deprecated in favor of core_implementations.cc. This is a
// temporary forwarding implementation so that the switch to
// core_implementations.cc isn't an immediate breaking change, allowing for the
// template to be updated to include it and update the template version before
// removing this file.

#include <assert.h>
#include <iostream>

namespace flutter {
namespace internal {

ReplyManager::ReplyManager(BinaryReply reply_handler)
: reply_handler_(std::move(reply_handler)) {
assert(reply_handler_);
}

ReplyManager::~ReplyManager() {
if (reply_handler_) {
// Warn, rather than send a not-implemented response, since the engine may
// no longer be valid at this point.
std::cerr
<< "Warning: Failed to respond to a message. This is a memory leak."
<< std::endl;
}
}

void ReplyManager::SendResponseData(const std::vector<uint8_t>* data) {
if (!reply_handler_) {
std::cerr
<< "Error: Only one of Success, Error, or NotImplemented can be "
"called,"
<< " and it can be called exactly once. Ignoring duplicate result."
<< std::endl;
return;
}

const uint8_t* message = data && !data->empty() ? data->data() : nullptr;
size_t message_size = data ? data->size() : 0;
reply_handler_(message, message_size);
reply_handler_ = nullptr;
}

} // namespace internal
} // namespace flutter
#include "core_implementations.cc"
Loading