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. (flutter#9655)

Fixes flutter#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.