Skip to content

Commit

Permalink
Allow embedders to add callbacks for responses to platform messages f…
Browse files Browse the repository at this point in the history
…rom the framework. (#9655)

Fixes #18852
  • Loading branch information
chinmaygarde committed Jul 3, 2019
1 parent 8dac2e9 commit b84f89b
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 9 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Expand Up @@ -768,6 +768,8 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_engine.h
FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.h
FILE: ../../../flutter/shell/platform/embedder/embedder_include.c
FILE: ../../../flutter/shell/platform/embedder/embedder_platform_message_response.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_platform_message_response.h
FILE: ../../../flutter/shell/platform/embedder/embedder_safe_access.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/embedder/BUILD.gn
Expand Up @@ -23,6 +23,8 @@ source_set("embedder") {
"embedder_external_texture_gl.cc",
"embedder_external_texture_gl.h",
"embedder_include.c",
"embedder_platform_message_response.cc",
"embedder_platform_message_response.h",
"embedder_safe_access.h",
"embedder_surface.cc",
"embedder_surface.h",
Expand All @@ -46,6 +48,7 @@ source_set("embedder") {
"$flutter_root/common",
"$flutter_root/flow",
"$flutter_root/fml",
"$flutter_root/lib/ui",
"$flutter_root/runtime:libdart",
"$flutter_root/shell/common",
"//third_party/dart/runtime/bin:dart_io_api",
Expand Down
52 changes: 51 additions & 1 deletion shell/platform/embedder/embedder.cc
Expand Up @@ -34,6 +34,7 @@ extern const intptr_t kPlatformStrongDillSize;
#include "flutter/shell/common/switches.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/embedder_engine.h"
#include "flutter/shell/platform/embedder/embedder_platform_message_response.h"
#include "flutter/shell/platform/embedder/embedder_safe_access.h"
#include "flutter/shell/platform/embedder/embedder_task_runner.h"
#include "flutter/shell/platform/embedder/embedder_thread_host.h"
Expand Down Expand Up @@ -818,19 +819,68 @@ FlutterEngineResult FlutterEngineSendPlatformMessage(
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

const FlutterPlatformMessageResponseHandle* response_handle =
SAFE_ACCESS(flutter_message, response_handle, nullptr);

fml::RefPtr<flutter::PlatformMessageResponse> response;
if (response_handle->message) {
response = response_handle->message->response();
}

auto message = fml::MakeRefCounted<flutter::PlatformMessage>(
flutter_message->channel,
std::vector<uint8_t>(
flutter_message->message,
flutter_message->message + flutter_message->message_size),
nullptr);
response);

return reinterpret_cast<flutter::EmbedderEngine*>(engine)
->SendPlatformMessage(std::move(message))
? kSuccess
: LOG_EMBEDDER_ERROR(kInvalidArguments);
}

FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(
FlutterEngine engine,
FlutterDataCallback data_callback,
void* user_data,
FlutterPlatformMessageResponseHandle** response_out) {
if (engine == nullptr || data_callback == nullptr ||
response_out == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

flutter::EmbedderPlatformMessageResponse::Callback response_callback =
[user_data, data_callback](const uint8_t* data, size_t size) {
data_callback(data, size, user_data);
};

auto platform_task_runner = reinterpret_cast<flutter::EmbedderEngine*>(engine)
->GetTaskRunners()
.GetPlatformTaskRunner();

auto handle = new FlutterPlatformMessageResponseHandle();

handle->message = fml::MakeRefCounted<flutter::PlatformMessage>(
"", // The channel is empty and unused as the response handle is going to
// referenced directly in the |FlutterEngineSendPlatformMessage| with
// the container message discarded.
fml::MakeRefCounted<flutter::EmbedderPlatformMessageResponse>(
std::move(platform_task_runner), response_callback));
*response_out = handle;
return kSuccess;
}

FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
FlutterEngine engine,
FlutterPlatformMessageResponseHandle* response) {
if (engine == nullptr || response == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}
delete response;
return kSuccess;
}

FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
FlutterEngine engine,
const FlutterPlatformMessageResponseHandle* handle,
Expand Down
40 changes: 35 additions & 5 deletions shell/platform/embedder/embedder.h
Expand Up @@ -373,12 +373,11 @@ typedef struct {
size_t struct_size;
const char* channel;
const uint8_t* message;
const size_t message_size;
size_t message_size;
// The response handle on which to invoke
// |FlutterEngineSendPlatformMessageResponse| when the response is ready. This
// field is ignored for messages being sent from the embedder to the
// framework. |FlutterEngineSendPlatformMessageResponse| must be called for
// all messages received by the embedder. Failure to call
// |FlutterEngineSendPlatformMessageResponse| when the response is ready.
// |FlutterEngineSendPlatformMessageResponse| must be called for all messages
// received by the embedder. Failure to call
// |FlutterEngineSendPlatformMessageResponse| will cause a memory leak. It is
// not safe to send multiple responses on a single response object.
const FlutterPlatformMessageResponseHandle* response_handle;
Expand All @@ -388,6 +387,10 @@ typedef void (*FlutterPlatformMessageCallback)(
const FlutterPlatformMessage* /* message*/,
void* /* user data */);

typedef void (*FlutterDataCallback)(const uint8_t* /* data */,
size_t /* size */,
void* /* user data */);

typedef struct {
double left;
double top;
Expand Down Expand Up @@ -707,6 +710,33 @@ FlutterEngineResult FlutterEngineSendPlatformMessage(
FlutterEngine engine,
const FlutterPlatformMessage* message);

// Creates a platform message response handle that allows the embedder to set a
// native callback for a response to a message. This handle may be set on the
// |response_handle| field of any |FlutterPlatformMessage| sent to the engine.
//
// The handle must be collected via a call to
// |FlutterPlatformMessageReleaseResponseHandle|. This may be done immediately
// after a call to |FlutterEngineSendPlatformMessage| with a platform message
// whose response handle contains the handle created using this call. In case a
// handle is created but never sent in a message, the release call must still be
// made. Not calling release on the handle results in a small memory leak.
//
// The user data baton passed to the data callback is the one specified in this
// call as the third argument.
FLUTTER_EXPORT
FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(
FlutterEngine engine,
FlutterDataCallback data_callback,
void* user_data,
FlutterPlatformMessageResponseHandle** response_out);

// Collects the handle created using
// |FlutterPlatformMessageCreateResponseHandle|.
FLUTTER_EXPORT
FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
FlutterEngine engine,
FlutterPlatformMessageResponseHandle* response);

FLUTTER_EXPORT
FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
FlutterEngine engine,
Expand Down
7 changes: 6 additions & 1 deletion shell/platform/embedder/embedder_engine.cc
Expand Up @@ -18,7 +18,8 @@ EmbedderEngine::EmbedderEngine(
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback)
: thread_host_(std::move(thread_host)),
shell_(Shell::Create(std::move(task_runners),
task_runners_(task_runners),
shell_(Shell::Create(task_runners_,
std::move(settings),
on_create_platform_view,
on_create_rasterizer)),
Expand All @@ -36,6 +37,10 @@ bool EmbedderEngine::IsValid() const {
return is_valid_;
}

const TaskRunners& EmbedderEngine::GetTaskRunners() const {
return task_runners_;
}

bool EmbedderEngine::NotifyCreated() {
if (!IsValid()) {
return false;
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/embedder/embedder_engine.h
Expand Up @@ -32,6 +32,8 @@ class EmbedderEngine {

~EmbedderEngine();

const TaskRunners& GetTaskRunners() const;

bool NotifyCreated();

bool NotifyDestroyed();
Expand Down Expand Up @@ -71,6 +73,7 @@ class EmbedderEngine {

private:
const std::unique_ptr<EmbedderThreadHost> thread_host_;
TaskRunners task_runners_;
std::unique_ptr<Shell> shell_;
const EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback_;
Expand Down
37 changes: 37 additions & 0 deletions shell/platform/embedder/embedder_platform_message_response.cc
@@ -0,0 +1,37 @@
// 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.

#include "flutter/shell/platform/embedder/embedder_platform_message_response.h"

#include "flutter/fml/make_copyable.h"

namespace flutter {

EmbedderPlatformMessageResponse::EmbedderPlatformMessageResponse(
fml::RefPtr<fml::TaskRunner> runner,
Callback callback)
: runner_(std::move(runner)), callback_(callback) {}

EmbedderPlatformMessageResponse::~EmbedderPlatformMessageResponse() = default;

// |PlatformMessageResponse|
void EmbedderPlatformMessageResponse::Complete(
std::unique_ptr<fml::Mapping> data) {
if (!data) {
CompleteEmpty();
return;
}

runner_->PostTask(
fml::MakeCopyable([data = std::move(data), callback = callback_]() {
callback(data->GetMapping(), data->GetSize());
}));
}

// |PlatformMessageResponse|
void EmbedderPlatformMessageResponse::CompleteEmpty() {
Complete(std::make_unique<fml::NonOwnedMapping>(nullptr, 0u));
}

} // namespace flutter
53 changes: 53 additions & 0 deletions shell/platform/embedder/embedder_platform_message_response.h
@@ -0,0 +1,53 @@
// 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_EMBEDDER_EMBEDDER_PLATFORM_MESSAGE_RESPONSE_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_PLATFORM_MESSAGE_RESPONSE_H_

#include "flutter/fml/macros.h"
#include "flutter/fml/task_runner.h"
#include "flutter/lib/ui/window/platform_message_response.h"

namespace flutter {

//------------------------------------------------------------------------------
/// @brief The platform message response subclass for responses to messages
/// from the embedder to the framework. Message responses are
/// fulfilled by the framework.
class EmbedderPlatformMessageResponse : public PlatformMessageResponse {
public:
using Callback = std::function<void(const uint8_t* data, size_t size)>;

//----------------------------------------------------------------------------
/// @param[in] runner The task runner on which to execute the callback.
/// The response will be initiated by the framework on
/// the UI thread.
/// @param[in] callback The callback that communicates to the embedder the
/// contents of the response sent by the framework back
/// to the emebder.
EmbedderPlatformMessageResponse(fml::RefPtr<fml::TaskRunner> runner,
Callback callback);

//----------------------------------------------------------------------------
/// @brief Destroys the message response. Can be called on any thread.
/// Does not execute unfulfilled callbacks.
///
~EmbedderPlatformMessageResponse() override;

private:
fml::RefPtr<fml::TaskRunner> runner_;
Callback callback_;

// |PlatformMessageResponse|
void Complete(std::unique_ptr<fml::Mapping> data) override;

// |PlatformMessageResponse|
void CompleteEmpty() override;

FML_DISALLOW_COPY_AND_ASSIGN(EmbedderPlatformMessageResponse);
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_PLATFORM_MESSAGE_RESPONSE_H_
9 changes: 9 additions & 0 deletions shell/platform/embedder/fixtures/main.dart
Expand Up @@ -144,3 +144,12 @@ void a11y_main() async { // ignore: non_constant_identifier_names
await semanticsChanged;
notifySemanticsEnabled(window.semanticsEnabled);
}


@pragma('vm:entry-point')
void platform_messages_response() {
window.onPlatformMessage = (String name, ByteData data, PlatformMessageResponseCallback callback) {
callback(data);
};
signalNativeTest();
}
3 changes: 2 additions & 1 deletion shell/platform/embedder/tests/embedder_test.cc
Expand Up @@ -27,12 +27,13 @@ EmbedderContext& EmbedderTest::GetEmbedderContext() {

// |testing::Test|
void EmbedderTest::SetUp() {
// Nothing to do here since we will lazily setup the context when asked.
ThreadTest::SetUp();
}

// |testing::Test|
void EmbedderTest::TearDown() {
embedder_context_.reset();
ThreadTest::TearDown();
}

} // namespace testing
Expand Down
3 changes: 2 additions & 1 deletion shell/platform/embedder/tests/embedder_test.h
Expand Up @@ -10,11 +10,12 @@
#include "flutter/fml/macros.h"
#include "flutter/shell/platform/embedder/tests/embedder_context.h"
#include "flutter/testing/testing.h"
#include "flutter/testing/thread_test.h"

namespace flutter {
namespace testing {

class EmbedderTest : public ::testing::Test {
class EmbedderTest : public ThreadTest {
public:
EmbedderTest();

Expand Down

0 comments on commit b84f89b

Please sign in to comment.