Revert "Android Background Platform Channels (#29147)" (flutter/engine#29344)

This reverts commit c40f7670e7.
This commit is contained in:
Dan Field
2021-10-26 14:52:13 -07:00
committed by GitHub
parent af0a43db41
commit d5c36f87f5
35 changed files with 183 additions and 833 deletions

View File

@@ -708,7 +708,6 @@ FILE: ../../../flutter/shell/common/persistent_cache_unittests.cc
FILE: ../../../flutter/shell/common/pipeline.cc
FILE: ../../../flutter/shell/common/pipeline.h
FILE: ../../../flutter/shell/common/pipeline_unittests.cc
FILE: ../../../flutter/shell/common/platform_message_handler.h
FILE: ../../../flutter/shell/common/platform_view.cc
FILE: ../../../flutter/shell/common/platform_view.h
FILE: ../../../flutter/shell/common/pointer_data_dispatcher.cc
@@ -842,7 +841,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/Flutte
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/DartExecutor.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/dart/PlatformTaskQueue.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/DeferredComponentManager.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/loader/ApplicationInfoLoader.java
@@ -940,8 +938,6 @@ FILE: ../../../flutter/shell/platform/android/jni/jni_mock_unittest.cc
FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.cc
FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.h
FILE: ../../../flutter/shell/platform/android/library_loader.cc
FILE: ../../../flutter/shell/platform/android/platform_message_handler_android.cc
FILE: ../../../flutter/shell/platform/android/platform_message_handler_android.h
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h
FILE: ../../../flutter/shell/platform/android/platform_view_android.cc

View File

@@ -73,7 +73,6 @@ source_set("common") {
"engine.h",
"pipeline.cc",
"pipeline.h",
"platform_message_handler.h",
"platform_view.cc",
"platform_view.h",
"pointer_data_dispatcher.cc",

View File

@@ -1,39 +0,0 @@
// 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 SHELL_COMMON_PLATFORM_MESSAGE_HANDLER_H_
#define SHELL_COMMON_PLATFORM_MESSAGE_HANDLER_H_
#include <memory>
#include "flutter/lib/ui/window/platform_message.h"
namespace flutter {
/// An interface over the ability to handle PlatformMessages that are being sent
/// from Flutter to the host platform.
class PlatformMessageHandler {
public:
virtual ~PlatformMessageHandler() = default;
/// Ultimately sends the PlatformMessage to the host platform.
/// This method is invoked on the ui thread.
virtual void HandlePlatformMessage(
std::unique_ptr<PlatformMessage> message) = 0;
/// Performs the return procedure for an associated call to
/// HandlePlatformMessage.
/// This method should be thread-safe and able to be invoked on any thread.
virtual void InvokePlatformMessageResponseCallback(
int response_id,
std::unique_ptr<fml::Mapping> mapping) = 0;
/// Performs the return procedure for an associated call to
/// HandlePlatformMessage where there is no return value.
/// This method should be thread-safe and able to be invoked on any thread.
virtual void InvokePlatformMessageEmptyResponseCallback(int response_id) = 0;
};
} // namespace flutter
#endif // SHELL_COMMON_PLATFORM_MESSAGE_HANDLER_H_

View File

@@ -184,9 +184,4 @@ PlatformView::CreateSnapshotSurfaceProducer() {
return nullptr;
}
std::shared_ptr<PlatformMessageHandler>
PlatformView::GetPlatformMessageHandler() const {
return nullptr;
}
} // namespace flutter

View File

@@ -22,7 +22,6 @@
#include "flutter/lib/ui/window/pointer_data_packet.h"
#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
#include "flutter/lib/ui/window/viewport_metrics.h"
#include "flutter/shell/common/platform_message_handler.h"
#include "flutter/shell/common/pointer_data_dispatcher.h"
#include "flutter/shell/common/vsync_waiter.h"
#include "third_party/skia/include/core/SkSize.h"
@@ -811,17 +810,6 @@ class PlatformView {
virtual std::unique_ptr<SnapshotSurfaceProducer>
CreateSnapshotSurfaceProducer();
//--------------------------------------------------------------------------
/// @brief Specifies a delegate that will receive PlatformMessages from
/// Flutter to the host platform.
///
/// @details If this returns `null` that means PlatformMessages should be sent
/// to the PlatformView. That is to protect legacy behavior, any embedder
/// that wants to support executing Platform Channel handlers on background
/// threads should be returing a thread-safe PlatformMessageHandler instead.
virtual std::shared_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
const;
protected:
PlatformView::Delegate& delegate_;
const TaskRunners task_runners_;

View File

@@ -625,7 +625,6 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
}
platform_view_ = std::move(platform_view);
platform_message_handler_ = platform_view_->GetPlatformMessageHandler();
engine_ = std::move(engine);
rasterizer_ = std::move(rasterizer);
io_manager_ = std::move(io_manager);
@@ -1193,17 +1192,13 @@ void Shell::OnEngineHandlePlatformMessage(
return;
}
if (platform_message_handler_) {
platform_message_handler_->HandlePlatformMessage(std::move(message));
} else {
task_runners_.GetPlatformTaskRunner()->PostTask(
fml::MakeCopyable([view = platform_view_->GetWeakPtr(),
message = std::move(message)]() mutable {
if (view) {
view->HandlePlatformMessage(std::move(message));
}
}));
}
task_runners_.GetPlatformTaskRunner()->PostTask(
fml::MakeCopyable([view = platform_view_->GetWeakPtr(),
message = std::move(message)]() mutable {
if (view) {
view->HandlePlatformMessage(std::move(message));
}
}));
}
void Shell::HandleEngineSkiaMessage(std::unique_ptr<PlatformMessage> message) {
@@ -1872,9 +1867,4 @@ fml::TimePoint Shell::GetCurrentTimePoint() {
return fml::TimePoint::Now();
}
const std::shared_ptr<PlatformMessageHandler>&
Shell::GetPlatformMessageHandler() const {
return platform_message_handler_;
}
} // namespace flutter

View File

@@ -395,12 +395,6 @@ class Shell final : public PlatformView::Delegate,
/// @see `CreateCompatibleGenerator`
void RegisterImageDecoder(ImageGeneratorFactory factory, int32_t priority);
//----------------------------------------------------------------------------
/// @brief Returns the delegate object that handles PlatformMessage's from
/// Flutter to the host platform (and its responses).
const std::shared_ptr<PlatformMessageHandler>& GetPlatformMessageHandler()
const;
private:
using ServiceProtocolHandler =
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
@@ -418,7 +412,6 @@ class Shell final : public PlatformView::Delegate,
std::unique_ptr<ShellIOManager> io_manager_; // on IO task runner
std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch_;
std::shared_ptr<VolatilePathTracker> volatile_path_tracker_;
std::shared_ptr<PlatformMessageHandler> platform_message_handler_;
fml::WeakPtr<Engine> weak_engine_; // to be shared across threads
fml::TaskRunnerAffineWeakPtr<Rasterizer>

View File

@@ -325,8 +325,7 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder,
bool is_gpu_disabled,
ShellTestPlatformView::BackendType rendering_backend,
Shell::CreateCallback<PlatformView> platform_view_create_callback) {
ShellTestPlatformView::BackendType rendering_backend) {
const auto vsync_clock = std::make_shared<ShellTestVsyncClock>();
CreateVsyncWaiter create_vsync_waiter = [&]() {
@@ -339,21 +338,21 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
}
};
if (!platform_view_create_callback) {
platform_view_create_callback = [vsync_clock, //
&create_vsync_waiter, //
shell_test_external_view_embedder, //
rendering_backend //
](Shell& shell) {
return ShellTestPlatformView::Create(shell, //
shell.GetTaskRunners(), //
vsync_clock, //
std::move(create_vsync_waiter), //
rendering_backend, //
shell_test_external_view_embedder //
);
};
}
Shell::CreateCallback<PlatformView> platfrom_view_create_callback =
[vsync_clock, //
&create_vsync_waiter, //
shell_test_external_view_embedder, //
rendering_backend //
](Shell& shell) {
return ShellTestPlatformView::Create(
shell, //
shell.GetTaskRunners(), //
vsync_clock, //
std::move(create_vsync_waiter), //
rendering_backend, //
shell_test_external_view_embedder //
);
};
Shell::CreateCallback<Rasterizer> rasterizer_create_callback =
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); };
@@ -361,7 +360,7 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
return Shell::Create(flutter::PlatformData(), //
task_runners, //
settings, //
platform_view_create_callback, //
platfrom_view_create_callback, //
rasterizer_create_callback, //
is_gpu_disabled //
);

View File

@@ -43,9 +43,7 @@ class ShellTest : public FixtureTest {
shell_test_external_view_embedder = nullptr,
bool is_gpu_disabled = false,
ShellTestPlatformView::BackendType rendering_backend =
ShellTestPlatformView::BackendType::kDefaultBackend,
Shell::CreateCallback<PlatformView> platform_view_create_callback =
nullptr);
ShellTestPlatformView::BackendType::kDefaultBackend);
void DestroyShell(std::unique_ptr<Shell> shell);
void DestroyShell(std::unique_ptr<Shell> shell, TaskRunners task_runners);
TaskRunners GetTaskRunnersForFixture();

View File

@@ -45,10 +45,6 @@
namespace flutter {
namespace testing {
using ::testing::_;
using ::testing::Return;
namespace {
class MockPlatformViewDelegate : public PlatformView::Delegate {
MOCK_METHOD1(OnPlatformViewCreated, void(std::unique_ptr<Surface> surface));
@@ -123,27 +119,6 @@ class MockPlatformView : public PlatformView {
MockPlatformView(MockPlatformViewDelegate& delegate, TaskRunners task_runners)
: PlatformView(delegate, task_runners) {}
MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr<Surface>());
MOCK_CONST_METHOD0(GetPlatformMessageHandler,
std::shared_ptr<PlatformMessageHandler>());
};
class MockPlatformMessageHandler : public PlatformMessageHandler {
public:
MOCK_METHOD1(HandlePlatformMessage,
void(std::unique_ptr<PlatformMessage> message));
MOCK_METHOD2(InvokePlatformMessageResponseCallback,
void(int response_id, std::unique_ptr<fml::Mapping> mapping));
MOCK_METHOD1(InvokePlatformMessageEmptyResponseCallback,
void(int response_id));
};
class MockPlatformMessageResponse : public PlatformMessageResponse {
public:
static fml::RefPtr<MockPlatformMessageResponse> Create() {
return fml::AdoptRef(new MockPlatformMessageResponse());
}
MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
MOCK_METHOD0(CompleteEmpty, void());
};
} // namespace
@@ -3187,52 +3162,7 @@ TEST_F(ShellTest, UIWorkAfterOnPlatformViewDestroyed) {
shell->GetTaskRunners().GetUITaskRunner(),
[&ui_flush_latch]() { ui_flush_latch.Signal(); });
ui_flush_latch.Wait();
DestroyShell(std::move(shell));
}
TEST_F(ShellTest, UsesPlatformMessageHandler) {
TaskRunners task_runners = GetTaskRunnersForFixture();
auto settings = CreateSettingsForFixture();
MockPlatformViewDelegate platform_view_delegate;
auto platform_message_handler =
std::make_shared<MockPlatformMessageHandler>();
int message_id = 1;
EXPECT_CALL(*platform_message_handler, HandlePlatformMessage(_));
EXPECT_CALL(*platform_message_handler,
InvokePlatformMessageEmptyResponseCallback(message_id));
Shell::CreateCallback<PlatformView> platform_view_create_callback =
[&platform_view_delegate, task_runners,
platform_message_handler](flutter::Shell& shell) {
auto result = std::make_unique<MockPlatformView>(platform_view_delegate,
task_runners);
EXPECT_CALL(*result, GetPlatformMessageHandler())
.WillOnce(Return(platform_message_handler));
return result;
};
auto shell = CreateShell(
/*settings=*/std::move(settings),
/*task_runners=*/task_runners,
/*simulate_vsync=*/false,
/*shell_test_external_view_embedder=*/nullptr,
/*is_gpu_disabled=*/false,
/*rendering_backend=*/
ShellTestPlatformView::BackendType::kDefaultBackend,
/*platform_view_create_callback=*/platform_view_create_callback);
EXPECT_EQ(platform_message_handler, shell->GetPlatformMessageHandler());
PostSync(task_runners.GetUITaskRunner(), [&shell]() {
size_t data_size = 4;
fml::MallocMapping bytes =
fml::MallocMapping(static_cast<uint8_t*>(malloc(data_size)), data_size);
fml::RefPtr<MockPlatformMessageResponse> response =
MockPlatformMessageResponse::Create();
auto message = std::make_unique<PlatformMessage>(
/*channel=*/"foo", /*data=*/std::move(bytes), /*response=*/response);
(static_cast<Engine::Delegate*>(shell.get()))
->OnEngineHandlePlatformMessage(std::move(message));
});
shell->GetPlatformMessageHandler()
->InvokePlatformMessageEmptyResponseCallback(message_id);
DestroyShell(std::move(shell));
}

View File

@@ -79,8 +79,6 @@ source_set("flutter_shell_native_src") {
"flutter_main.cc",
"flutter_main.h",
"library_loader.cc",
"platform_message_handler_android.cc",
"platform_message_handler_android.h",
"platform_message_response_android.cc",
"platform_message_response_android.h",
"platform_view_android.cc",
@@ -188,7 +186,6 @@ android_java_sources = [
"io/flutter/embedding/engine/dart/DartExecutor.java",
"io/flutter/embedding/engine/dart/DartMessenger.java",
"io/flutter/embedding/engine/dart/PlatformMessageHandler.java",
"io/flutter/embedding/engine/dart/PlatformTaskQueue.java",
"io/flutter/embedding/engine/deferredcomponents/DeferredComponentManager.java",
"io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java",
"io/flutter/embedding/engine/loader/ApplicationInfoLoader.java",

View File

@@ -16,7 +16,6 @@
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
#include "flutter/shell/platform/android/platform_message_handler_android.h"
#include "flutter/shell/platform/android/platform_view_android.h"
namespace flutter {
@@ -97,11 +96,6 @@ class AndroidShellHolder {
void NotifyLowMemoryWarning();
const std::shared_ptr<PlatformMessageHandler>& GetPlatformMessageHandler()
const {
return shell_->GetPlatformMessageHandler();
}
private:
const flutter::Settings settings_;
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;

View File

@@ -7,7 +7,6 @@ namespace flutter {
namespace testing {
namespace {
class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI {
public:
MOCK_METHOD2(FlutterViewHandlePlatformMessage,
void(std::unique_ptr<flutter::PlatformMessage> message,
int responseId));
@@ -52,15 +51,6 @@ class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI {
MOCK_METHOD0(GetDisplayRefreshRate, double());
MOCK_METHOD1(RequestDartDeferredLibrary, bool(int loading_unit_id));
};
class MockPlatformMessageResponse : public PlatformMessageResponse {
public:
static fml::RefPtr<MockPlatformMessageResponse> Create() {
return fml::AdoptRef(new MockPlatformMessageResponse());
}
MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
MOCK_METHOD0(CompleteEmpty, void());
};
} // namespace
TEST(AndroidShellHolder, Create) {
@@ -75,34 +65,5 @@ TEST(AndroidShellHolder, Create) {
nullptr, /*is_fake_window=*/true);
holder->GetPlatformView()->NotifyCreated(window);
}
TEST(AndroidShellHolder, HandlePlatformMessage) {
Settings settings;
settings.enable_software_rendering = false;
auto jni = std::make_shared<MockPlatformViewAndroidJNI>();
auto holder = std::make_unique<AndroidShellHolder>(settings, jni);
EXPECT_NE(holder.get(), nullptr);
EXPECT_TRUE(holder->IsValid());
EXPECT_NE(holder->GetPlatformView().get(), nullptr);
auto window = fml::MakeRefCounted<AndroidNativeWindow>(
nullptr, /*is_fake_window=*/true);
holder->GetPlatformView()->NotifyCreated(window);
EXPECT_TRUE(holder->GetPlatformMessageHandler());
size_t data_size = 4;
fml::MallocMapping bytes =
fml::MallocMapping(static_cast<uint8_t*>(malloc(data_size)), data_size);
fml::RefPtr<MockPlatformMessageResponse> response =
MockPlatformMessageResponse::Create();
auto message = std::make_unique<PlatformMessage>(
/*channel=*/"foo", /*data=*/std::move(bytes), /*response=*/response);
int response_id = 1;
EXPECT_CALL(*jni,
FlutterViewHandlePlatformMessage(::testing::_, response_id));
EXPECT_CALL(*response, CompleteEmpty());
holder->GetPlatformMessageHandler()->HandlePlatformMessage(
std::move(message));
holder->GetPlatformMessageHandler()
->InvokePlatformMessageEmptyResponseCallback(response_id);
}
} // namespace testing
} // namespace flutter

View File

@@ -41,7 +41,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Interface between Flutter embedding's Java code and Flutter engine's C/C++ code.
@@ -99,12 +98,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
@Keep
public class FlutterJNI {
private static final String TAG = "FlutterJNI";
// This serializes the invocation of platform message responses and the
// attachment and detachment of the shell holder. This ensures that we don't
// detach FlutterJNI on the platform thread while a background thread invokes
// a message response. Typically accessing the shell holder happens on the
// platform thread and doesn't require locking.
private ReentrantReadWriteLock shellHolderLock = new ReentrantReadWriteLock();
// BEGIN Methods related to loading for FlutterLoader.
/**
@@ -311,12 +304,7 @@ public class FlutterJNI {
public void attachToNative() {
ensureRunningOnMainThread();
ensureNotAttachedToNative();
shellHolderLock.writeLock().lock();
try {
nativeShellHolderId = performNativeAttach(this);
} finally {
shellHolderLock.writeLock().unlock();
}
nativeShellHolderId = performNativeAttach(this);
}
@VisibleForTesting
@@ -380,13 +368,8 @@ public class FlutterJNI {
public void detachFromNativeAndReleaseResources() {
ensureRunningOnMainThread();
ensureAttachedToNative();
shellHolderLock.writeLock().lock();
try {
nativeDestroy(nativeShellHolderId);
nativeShellHolderId = null;
} finally {
shellHolderLock.writeLock().unlock();
}
nativeDestroy(nativeShellHolderId);
nativeShellHolderId = null;
}
private native void nativeDestroy(long nativeShellHolderId);
@@ -875,33 +858,14 @@ public class FlutterJNI {
this.platformMessageHandler = platformMessageHandler;
}
private native void nativeCleanupMessageData(long messageData);
/**
* Destroys the resources provided sent to `handlePlatformMessage`.
*
* <p>This can be called on any thread.
*
* @param messageData the argument sent to handlePlatformMessage.
*/
public void cleanupMessageData(long messageData) {
// This doesn't rely on being attached like other methods.
nativeCleanupMessageData(messageData);
}
// Called by native on the ui thread.
// Called by native.
// TODO(mattcarroll): determine if message is nonull or nullable
@SuppressWarnings("unused")
@VisibleForTesting
public void handlePlatformMessage(
@NonNull final String channel,
ByteBuffer message,
final int replyId,
final long messageData) {
@NonNull final String channel, ByteBuffer message, final int replyId) {
if (platformMessageHandler != null) {
platformMessageHandler.handleMessageFromDart(channel, message, replyId, messageData);
} else {
nativeCleanupMessageData(messageData);
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
// TODO(mattcarroll): log dropped messages when in debug mode
// (https://github.com/flutter/flutter/issues/25391)
@@ -967,20 +931,16 @@ public class FlutterJNI {
int responseId);
// TODO(mattcarroll): differentiate between channel responses and platform responses.
@UiThread
public void invokePlatformMessageEmptyResponseCallback(int responseId) {
// Called on any thread.
shellHolderLock.readLock().lock();
try {
if (isAttached()) {
nativeInvokePlatformMessageEmptyResponseCallback(nativeShellHolderId, responseId);
} else {
Log.w(
TAG,
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
+ responseId);
}
} finally {
shellHolderLock.readLock().unlock();
ensureRunningOnMainThread();
if (isAttached()) {
nativeInvokePlatformMessageEmptyResponseCallback(nativeShellHolderId, responseId);
} else {
Log.w(
TAG,
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
+ responseId);
}
}
@@ -989,25 +949,21 @@ public class FlutterJNI {
long nativeShellHolderId, int responseId);
// TODO(mattcarroll): differentiate between channel responses and platform responses.
@UiThread
public void invokePlatformMessageResponseCallback(
int responseId, @NonNull ByteBuffer message, int position) {
// Called on any thread.
ensureRunningOnMainThread();
if (!message.isDirect()) {
throw new IllegalArgumentException("Expected a direct ByteBuffer.");
}
shellHolderLock.readLock().lock();
try {
if (isAttached()) {
nativeInvokePlatformMessageResponseCallback(
nativeShellHolderId, responseId, message, position);
} else {
Log.w(
TAG,
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
+ responseId);
}
} finally {
shellHolderLock.readLock().unlock();
if (isAttached()) {
nativeInvokePlatformMessageResponseCallback(
nativeShellHolderId, responseId, message, position);
} else {
Log.w(
TAG,
"Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: "
+ responseId);
}
}

View File

@@ -59,7 +59,7 @@ public class DartExecutor implements BinaryMessenger {
this.flutterJNI = flutterJNI;
this.assetManager = assetManager;
this.dartMessenger = new DartMessenger(flutterJNI);
dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler, null);
dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
// The JNI might already be attached if coming from a spawned engine. If so, correctly report
// that this DartExecutor is already running.
@@ -168,14 +168,6 @@ public class DartExecutor implements BinaryMessenger {
}
// ------ START BinaryMessenger (Deprecated: use getBinaryMessenger() instead) -----
/** @deprecated Use {@link #getBinaryMessenger()} instead. */
@Deprecated
@UiThread
@Override
public TaskQueue makeBackgroundTaskQueue() {
return binaryMessenger.makeBackgroundTaskQueue();
}
/** @deprecated Use {@link #getBinaryMessenger()} instead. */
@Deprecated
@Override
@@ -200,10 +192,8 @@ public class DartExecutor implements BinaryMessenger {
@Override
@UiThread
public void setMessageHandler(
@NonNull String channel,
@Nullable BinaryMessenger.BinaryMessageHandler handler,
@Nullable TaskQueue taskQueue) {
binaryMessenger.setMessageHandler(channel, handler, taskQueue);
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
binaryMessenger.setMessageHandler(channel, handler);
}
// ------ END BinaryMessenger -----
@@ -381,10 +371,6 @@ public class DartExecutor implements BinaryMessenger {
this.messenger = messenger;
}
public TaskQueue makeBackgroundTaskQueue() {
return messenger.makeBackgroundTaskQueue();
}
/**
* Sends the given {@code message} from Android to Dart over the given {@code channel}.
*
@@ -427,10 +413,8 @@ public class DartExecutor implements BinaryMessenger {
@Override
@UiThread
public void setMessageHandler(
@NonNull String channel,
@Nullable BinaryMessenger.BinaryMessageHandler handler,
@Nullable TaskQueue taskQueue) {
messenger.setMessageHandler(channel, handler, taskQueue);
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
messenger.setMessageHandler(channel, handler);
}
}
}

View File

@@ -13,11 +13,6 @@ import io.flutter.plugin.common.BinaryMessenger;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -31,104 +26,25 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
private static final String TAG = "DartMessenger";
@NonNull private final FlutterJNI flutterJNI;
@NonNull private final ConcurrentHashMap<String, HandlerInfo> messageHandlers;
@NonNull private final Map<String, BinaryMessenger.BinaryMessageHandler> messageHandlers;
@NonNull private final Map<Integer, BinaryMessenger.BinaryReply> pendingReplies;
private int nextReplyId = 1;
@NonNull private final DartMessengerTaskQueue platformTaskQueue = new PlatformTaskQueue();
@NonNull private WeakHashMap<TaskQueue, DartMessengerTaskQueue> createdTaskQueues;
@NonNull private TaskQueueFactory taskQueueFactory;
DartMessenger(@NonNull FlutterJNI flutterJNI, @NonNull TaskQueueFactory taskQueueFactory) {
this.flutterJNI = flutterJNI;
this.messageHandlers = new ConcurrentHashMap<>();
this.pendingReplies = new HashMap<>();
this.createdTaskQueues = new WeakHashMap<TaskQueue, DartMessengerTaskQueue>();
this.taskQueueFactory = taskQueueFactory;
}
DartMessenger(@NonNull FlutterJNI flutterJNI) {
this(flutterJNI, new DefaultTaskQueueFactory());
}
private static class TaskQueueToken implements TaskQueue {}
interface DartMessengerTaskQueue {
void dispatch(@NonNull Runnable runnable);
}
interface TaskQueueFactory {
DartMessengerTaskQueue makeBackgroundTaskQueue();
}
private static class DefaultTaskQueueFactory implements TaskQueueFactory {
public DartMessengerTaskQueue makeBackgroundTaskQueue() {
return new DefaultTaskQueue();
}
}
private static class HandlerInfo {
@NonNull public final BinaryMessenger.BinaryMessageHandler handler;
@Nullable public final DartMessengerTaskQueue taskQueue;
HandlerInfo(
@NonNull BinaryMessenger.BinaryMessageHandler handler,
@Nullable DartMessengerTaskQueue taskQueue) {
this.handler = handler;
this.taskQueue = taskQueue;
}
}
private static class DefaultTaskQueue implements DartMessengerTaskQueue {
@NonNull private final ExecutorService executor;
DefaultTaskQueue() {
// TODO(gaaclarke): Use a shared thread pool with serial queues instead of
// making a thread for each TaskQueue.
ThreadFactory threadFactory =
(Runnable runnable) -> {
return new Thread(runnable, "DartMessenger.DefaultTaskQueue");
};
this.executor = Executors.newSingleThreadExecutor(threadFactory);
}
@Override
public void dispatch(@NonNull Runnable runnable) {
executor.execute(runnable);
}
}
@Override
public TaskQueue makeBackgroundTaskQueue() {
DartMessengerTaskQueue taskQueue = taskQueueFactory.makeBackgroundTaskQueue();
TaskQueueToken token = new TaskQueueToken();
createdTaskQueues.put(token, taskQueue);
return token;
this.flutterJNI = flutterJNI;
this.messageHandlers = new HashMap<>();
this.pendingReplies = new HashMap<>();
}
@Override
public void setMessageHandler(
@NonNull String channel,
@Nullable BinaryMessenger.BinaryMessageHandler handler,
@Nullable TaskQueue taskQueue) {
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
if (handler == null) {
Log.v(TAG, "Removing handler for channel '" + channel + "'");
messageHandlers.remove(channel);
} else {
DartMessengerTaskQueue dartMessengerTaskQueue = null;
if (taskQueue != null) {
dartMessengerTaskQueue = createdTaskQueues.get(taskQueue);
if (dartMessengerTaskQueue == null) {
throw new IllegalArgumentException(
"Unrecognized TaskQueue, use BinaryMessenger to create your TaskQueue (ex makeBackgroundTaskQueue).");
}
}
Log.v(TAG, "Setting handler for channel '" + channel + "'");
messageHandlers.put(channel, new HandlerInfo(handler, dartMessengerTaskQueue));
messageHandlers.put(channel, handler);
}
}
@@ -156,13 +72,20 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
}
}
private void invokeHandler(
@Nullable HandlerInfo handlerInfo, @Nullable ByteBuffer message, final int replyId) {
// Called from any thread.
if (handlerInfo != null) {
@Override
public void handleMessageFromDart(
@NonNull final String channel, @Nullable ByteBuffer message, final int replyId) {
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
if (handler != null) {
try {
Log.v(TAG, "Deferring to registered handler to process message.");
handlerInfo.handler.onMessage(message, new Reply(flutterJNI, replyId));
handler.onMessage(message, new Reply(flutterJNI, replyId));
if (message != null && message.isDirect()) {
// This ensures that if a user retains an instance to the ByteBuffer and it happens to
// be direct they will get a deterministic error.
message.limit(0);
}
} catch (Exception ex) {
Log.e(TAG, "Uncaught exception in binary message listener", ex);
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
@@ -175,37 +98,6 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
}
}
@Override
public void handleMessageFromDart(
@NonNull final String channel,
@Nullable ByteBuffer message,
final int replyId,
long messageData) {
// Called from the ui thread.
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
@Nullable final HandlerInfo handlerInfo = messageHandlers.get(channel);
@Nullable
final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null;
Runnable myRunnable =
() -> {
try {
invokeHandler(handlerInfo, message, replyId);
if (message != null && message.isDirect()) {
// This ensures that if a user retains an instance to the ByteBuffer and it happens to
// be direct they will get a deterministic error.
message.limit(0);
}
} finally {
// This is deleting the data underneath the message object.
flutterJNI.cleanupMessageData(messageData);
}
};
@NonNull
final DartMessengerTaskQueue nonnullTaskQueue =
taskQueue == null ? platformTaskQueue : taskQueue;
nonnullTaskQueue.dispatch(myRunnable);
}
@Override
public void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply) {
Log.v(TAG, "Received message reply from Dart.");

View File

@@ -11,10 +11,7 @@ import java.nio.ByteBuffer;
/** Handler that receives messages from Dart code. */
public interface PlatformMessageHandler {
void handleMessageFromDart(
@NonNull final String channel,
@Nullable ByteBuffer message,
final int replyId,
long messageData);
@NonNull final String channel, @Nullable ByteBuffer message, final int replyId);
void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply);
}

View File

@@ -1,19 +0,0 @@
// 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.
package io.flutter.embedding.engine.dart;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
/** A BinaryMessenger.TaskQueue that posts to the platform thread (aka main thread). */
public class PlatformTaskQueue implements DartMessenger.DartMessengerTaskQueue {
@NonNull private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void dispatch(@NonNull Runnable runnable) {
handler.post(runnable);
}
}

View File

@@ -36,7 +36,6 @@ public final class BasicMessageChannel<T> {
@NonNull private final BinaryMessenger messenger;
@NonNull private final String name;
@NonNull private final MessageCodec<T> codec;
@Nullable private final BinaryMessenger.TaskQueue taskQueue;
/**
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
@@ -48,25 +47,6 @@ public final class BasicMessageChannel<T> {
*/
public BasicMessageChannel(
@NonNull BinaryMessenger messenger, @NonNull String name, @NonNull MessageCodec<T> codec) {
this(messenger, name, codec, null);
}
/**
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
* specified name and {@link MessageCodec}.
*
* @param messenger a {@link BinaryMessenger}.
* @param name a channel name String.
* @param codec a {@link MessageCodec}.
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
* the handler. Specifying null means execute on the platform thread. See also {@link
* BinaryMessenger#makeBackgroundTaskQueue()}.
*/
public BasicMessageChannel(
@NonNull BinaryMessenger messenger,
@NonNull String name,
@NonNull MessageCodec<T> codec,
BinaryMessenger.TaskQueue taskQueue) {
if (BuildConfig.DEBUG) {
if (messenger == null) {
Log.e(TAG, "Parameter messenger must not be null.");
@@ -81,7 +61,6 @@ public final class BasicMessageChannel<T> {
this.messenger = messenger;
this.name = name;
this.codec = codec;
this.taskQueue = taskQueue;
}
/**
@@ -122,8 +101,7 @@ public final class BasicMessageChannel<T> {
*/
@UiThread
public void setMessageHandler(@Nullable final MessageHandler<T> handler) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMessageHandler(handler), taskQueue);
messenger.setMessageHandler(name, handler == null ? null : new IncomingMessageHandler(handler));
}
/**

View File

@@ -26,24 +26,6 @@ import java.nio.ByteBuffer;
* @see EventChannel , which supports communication using event streams.
*/
public interface BinaryMessenger {
/**
* An abstraction over the threading policy used to invoke message handlers.
*
* <p>These are generated by calling methods like {@link
* BinaryMessenger#makeBackgroundTaskQueue()} and can be passed into platform channels'
* constructors to control the threading policy for handling platform channels' messages.
*/
public interface TaskQueue {}
/**
* Creates a TaskQueue that executes the tasks serially on a background thread.
*
* <p>There is no guarantee that the tasks will execute on the same thread, just that execution is
* serial.
*/
@UiThread
TaskQueue makeBackgroundTaskQueue();
/**
* Sends a binary message to the Flutter application.
*
@@ -80,14 +62,9 @@ public interface BinaryMessenger {
*
* @param channel the name {@link String} of the channel.
* @param handler a {@link BinaryMessageHandler} to be invoked on incoming messages, or null.
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
* the handler. Specifying null means execute on the platform thread.
*/
@UiThread
void setMessageHandler(
@NonNull String channel,
@Nullable BinaryMessageHandler handler,
@Nullable TaskQueue taskQueue);
void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler);
/** Handler for incoming binary messages from Flutter. */
interface BinaryMessageHandler {
@@ -120,6 +97,7 @@ public interface BinaryMessenger {
* outgoing replies must place the reply bytes between position zero and current position.
* Reply receivers can read from the buffer directly.
*/
@UiThread
void reply(@Nullable ByteBuffer reply);
}
}

View File

@@ -4,7 +4,6 @@
package io.flutter.plugin.common;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import io.flutter.BuildConfig;
import io.flutter.Log;
@@ -35,7 +34,6 @@ public final class EventChannel {
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;
@Nullable private final BinaryMessenger.TaskQueue taskQueue;
/**
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
@@ -57,25 +55,6 @@ public final class EventChannel {
* @param codec a {@link MessageCodec}.
*/
public EventChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
this(messenger, name, codec, null);
}
/**
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
* specified name and {@link MethodCodec}.
*
* @param messenger a {@link BinaryMessenger}.
* @param name a channel name String.
* @param codec a {@link MessageCodec}.
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
* the handler. Specifying null means execute on the platform thread. See also {@link
* BinaryMessenger#makeBackgroundTaskQueue()}.
*/
public EventChannel(
BinaryMessenger messenger,
String name,
MethodCodec codec,
BinaryMessenger.TaskQueue taskQueue) {
if (BuildConfig.DEBUG) {
if (messenger == null) {
Log.e(TAG, "Parameter messenger must not be null.");
@@ -90,7 +69,6 @@ public final class EventChannel {
this.messenger = messenger;
this.name = name;
this.codec = codec;
this.taskQueue = taskQueue;
}
/**
@@ -106,7 +84,7 @@ public final class EventChannel {
@UiThread
public void setStreamHandler(final StreamHandler handler) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingStreamRequestHandler(handler), taskQueue);
name, handler == null ? null : new IncomingStreamRequestHandler(handler));
}
/**

View File

@@ -35,7 +35,6 @@ public class MethodChannel {
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;
private final BinaryMessenger.TaskQueue taskQueue;
/**
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
@@ -57,25 +56,6 @@ public class MethodChannel {
* @param codec a {@link MessageCodec}.
*/
public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
this(messenger, name, codec, null);
}
/**
* Creates a new channel associated with the specified {@link BinaryMessenger} and with the
* specified name and {@link MethodCodec}.
*
* @param messenger a {@link BinaryMessenger}.
* @param name a channel name String.
* @param codec a {@link MessageCodec}.
* @param taskQueue a {@link BinaryMessenger.TaskQueue} that specifies what thread will execute
* the handler. Specifying null means execute on the platform thread. See also {@link
* BinaryMessenger#makeBackgroundTaskQueue()}.
*/
public MethodChannel(
BinaryMessenger messenger,
String name,
MethodCodec codec,
@Nullable BinaryMessenger.TaskQueue taskQueue) {
if (BuildConfig.DEBUG) {
if (messenger == null) {
Log.e(TAG, "Parameter messenger must not be null.");
@@ -90,7 +70,6 @@ public class MethodChannel {
this.messenger = messenger;
this.name = name;
this.codec = codec;
this.taskQueue = taskQueue;
}
/**
@@ -138,7 +117,7 @@ public class MethodChannel {
@UiThread
public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMethodCallHandler(handler), taskQueue);
name, handler == null ? null : new IncomingMethodCallHandler(handler));
}
/**

View File

@@ -124,12 +124,6 @@ public class FlutterNativeView implements BinaryMessenger {
return FlutterJNI.getObservatoryUri();
}
@Override
@UiThread
public TaskQueue makeBackgroundTaskQueue() {
return dartExecutor.getBinaryMessenger().makeBackgroundTaskQueue();
}
@Override
@UiThread
public void send(String channel, ByteBuffer message) {
@@ -149,8 +143,8 @@ public class FlutterNativeView implements BinaryMessenger {
@Override
@UiThread
public void setMessageHandler(String channel, BinaryMessageHandler handler, TaskQueue taskQueue) {
dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler, taskQueue);
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler);
}
/*package*/ FlutterJNI getFlutterJNI() {

View File

@@ -822,12 +822,6 @@ public class FlutterView extends SurfaceView
return PointerIcon.getSystemIcon(getContext(), type);
}
@Override
@UiThread
public TaskQueue makeBackgroundTaskQueue() {
return null;
}
@Override
@UiThread
public void send(String channel, ByteBuffer message) {
@@ -846,8 +840,8 @@ public class FlutterView extends SurfaceView
@Override
@UiThread
public void setMessageHandler(String channel, BinaryMessageHandler handler, TaskQueue taskQueue) {
mNativeView.setMessageHandler(channel, handler, taskQueue);
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
mNativeView.setMessageHandler(channel, handler);
}
/** Listener will be called on the Android UI thread once when Flutter renders the first frame. */

View File

@@ -1,64 +0,0 @@
#include "flutter/shell/platform/android/platform_message_handler_android.h"
namespace flutter {
PlatformMessageHandlerAndroid::PlatformMessageHandlerAndroid(
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade)
: jni_facade_(jni_facade) {}
void PlatformMessageHandlerAndroid::InvokePlatformMessageResponseCallback(
int response_id,
std::unique_ptr<fml::Mapping> mapping) {
// Called from any thread.
if (!response_id) {
return;
}
// TODO(gaaclarke): Move the jump to the ui thread here from
// PlatformMessageResponseDart so we won't need to use a mutex anymore.
fml::RefPtr<flutter::PlatformMessageResponse> message_response;
{
std::lock_guard lock(pending_responses_mutex_);
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
message_response = std::move(it->second);
pending_responses_.erase(it);
}
message_response->Complete(std::move(mapping));
}
void PlatformMessageHandlerAndroid::InvokePlatformMessageEmptyResponseCallback(
int response_id) {
// Called from any thread.
if (!response_id) {
return;
}
fml::RefPtr<flutter::PlatformMessageResponse> message_response;
{
std::lock_guard lock(pending_responses_mutex_);
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
message_response = std::move(it->second);
pending_responses_.erase(it);
}
message_response->CompleteEmpty();
}
// |PlatformView|
void PlatformMessageHandlerAndroid::HandlePlatformMessage(
std::unique_ptr<flutter::PlatformMessage> message) {
// Called from the ui thread.
int response_id = next_response_id_++;
if (auto response = message->response()) {
std::lock_guard lock(pending_responses_mutex_);
pending_responses_[response_id] = response;
}
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
jni_facade_->FlutterViewHandlePlatformMessage(std::move(message),
response_id);
}
} // namespace flutter

View File

@@ -1,38 +0,0 @@
// 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 SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_HANDLER_H_
#define SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_HANDLER_H_
#include <jni.h>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/shell/common/platform_message_handler.h"
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
namespace flutter {
class PlatformMessageHandlerAndroid : public PlatformMessageHandler {
public:
PlatformMessageHandlerAndroid(
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade);
void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;
void InvokePlatformMessageResponseCallback(
int response_id,
std::unique_ptr<fml::Mapping> mapping) override;
void InvokePlatformMessageEmptyResponseCallback(int response_id) override;
private:
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
int next_response_id_ = 1;
std::unordered_map<int, fml::RefPtr<flutter::PlatformMessageResponse>>
pending_responses_;
std::mutex pending_responses_mutex_;
};
} // namespace flutter
#endif

View File

@@ -73,8 +73,7 @@ PlatformViewAndroid::PlatformViewAndroid(
: PlatformView(delegate, std::move(task_runners)),
jni_facade_(jni_facade),
android_context_(std::move(android_context)),
platform_view_android_delegate_(jni_facade),
platform_message_handler_(new PlatformMessageHandlerAndroid(jni_facade)) {
platform_view_android_delegate_(jni_facade) {
// TODO(dnfield): always create a pbuffer surface for background use to
// resolve https://github.com/flutter/flutter/issues/73675
if (android_context_) {
@@ -191,11 +190,51 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env,
std::move(response)));
}
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
JNIEnv* env,
jint response_id,
jobject java_response_data,
jint java_response_position) {
if (!response_id)
return;
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
uint8_t* response_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
FML_DCHECK(response_data != nullptr);
std::vector<uint8_t> response = std::vector<uint8_t>(
response_data, response_data + java_response_position);
auto message_response = std::move(it->second);
pending_responses_.erase(it);
message_response->Complete(
std::make_unique<fml::DataMapping>(std::move(response)));
}
void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback(
JNIEnv* env,
jint response_id) {
if (!response_id)
return;
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
auto message_response = std::move(it->second);
pending_responses_.erase(it);
message_response->CompleteEmpty();
}
// |PlatformView|
void PlatformViewAndroid::HandlePlatformMessage(
std::unique_ptr<flutter::PlatformMessage> message) {
// Called from the ui thread.
platform_message_handler_->HandlePlatformMessage(std::move(message));
int response_id = next_response_id_++;
if (auto response = message->response()) {
pending_responses_[response_id] = response;
}
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
jni_facade_->FlutterViewHandlePlatformMessage(std::move(message),
response_id);
message = nullptr;
}
// |PlatformView|

View File

@@ -17,7 +17,6 @@
#include "flutter/shell/common/snapshot_surface_producer.h"
#include "flutter/shell/platform/android/context/android_context.h"
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
#include "flutter/shell/platform/android/platform_message_handler_android.h"
#include "flutter/shell/platform/android/platform_view_android_delegate/platform_view_android_delegate.h"
#include "flutter/shell/platform/android/surface/android_native_window.h"
#include "flutter/shell/platform/android/surface/android_surface.h"
@@ -80,6 +79,14 @@ class PlatformViewAndroid final : public PlatformView {
std::string name,
jint response_id);
void InvokePlatformMessageResponseCallback(JNIEnv* env,
jint response_id,
jobject java_response_data,
jint java_response_position);
void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env,
jint response_id);
void DispatchSemanticsAction(JNIEnv* env,
jint id,
jint action,
@@ -109,11 +116,6 @@ class PlatformViewAndroid final : public PlatformView {
return android_context_;
}
std::shared_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
const override {
return platform_message_handler_;
}
private:
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
std::shared_ptr<AndroidContext> android_context_;
@@ -122,7 +124,11 @@ class PlatformViewAndroid final : public PlatformView {
PlatformViewAndroidDelegate platform_view_android_delegate_;
std::unique_ptr<AndroidSurface> android_surface_;
std::shared_ptr<PlatformMessageHandlerAndroid> platform_message_handler_;
// We use id 0 to mean that no response is expected.
int next_response_id_ = 1;
std::unordered_map<int, fml::RefPtr<flutter::PlatformMessageResponse>>
pending_responses_;
// |PlatformView|
void UpdateSemantics(

View File

@@ -405,13 +405,6 @@ static void DispatchEmptyPlatformMessage(JNIEnv* env,
);
}
static void CleanupMessageData(JNIEnv* env,
jobject jcaller,
jlong message_data) {
// Called from any thread.
free(reinterpret_cast<void*>(message_data));
}
static void DispatchPointerDataPacket(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
@@ -490,21 +483,22 @@ static void InvokePlatformMessageResponseCallback(JNIEnv* env,
jint responseId,
jobject message,
jint position) {
uint8_t* response_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(message));
FML_DCHECK(response_data != nullptr);
auto mapping = std::make_unique<fml::MallocMapping>(
fml::MallocMapping::Copy(response_data, response_data + position));
ANDROID_SHELL_HOLDER->GetPlatformMessageHandler()
->InvokePlatformMessageResponseCallback(responseId, std::move(mapping));
ANDROID_SHELL_HOLDER->GetPlatformView()
->InvokePlatformMessageResponseCallback(env, //
responseId, //
message, //
position //
);
}
static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jint responseId) {
ANDROID_SHELL_HOLDER->GetPlatformMessageHandler()
->InvokePlatformMessageEmptyResponseCallback(responseId);
ANDROID_SHELL_HOLDER->GetPlatformView()
->InvokePlatformMessageEmptyResponseCallback(env, //
responseId //
);
}
static void NotifyLowMemoryWarning(JNIEnv* env,
@@ -644,11 +638,6 @@ bool RegisterApi(JNIEnv* env) {
.signature = "(JLjava/lang/String;I)V",
.fnPtr = reinterpret_cast<void*>(&DispatchEmptyPlatformMessage),
},
{
.name = "nativeCleanupMessageData",
.signature = "(J)V",
.fnPtr = reinterpret_cast<void*>(&CleanupMessageData),
},
{
.name = "nativeDispatchPlatformMessage",
.signature = "(JLjava/lang/String;Ljava/nio/ByteBuffer;II)V",
@@ -830,7 +819,7 @@ bool RegisterApi(JNIEnv* env) {
g_handle_platform_message_method =
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
"(Ljava/lang/String;Ljava/nio/ByteBuffer;IJ)V");
"(Ljava/lang/String;Ljava/nio/ByteBuffer;I)V");
if (g_handle_platform_message_method == nullptr) {
FML_LOG(ERROR) << "Could not locate handlePlatformMessage method";
@@ -1113,7 +1102,6 @@ PlatformViewAndroidJNIImpl::~PlatformViewAndroidJNIImpl() = default;
void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage(
std::unique_ptr<flutter::PlatformMessage> message,
int responseId) {
// Called from the ui thread.
JNIEnv* env = fml::jni::AttachCurrentThread();
auto java_object = java_object_.get(env);
@@ -1129,14 +1117,11 @@ void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage(
env, env->NewDirectByteBuffer(
const_cast<uint8_t*>(message->data().GetMapping()),
message->data().GetSize()));
// Message data is deleted in CleanupMessageData.
fml::MallocMapping mapping = message->releaseData();
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
java_channel.obj(), message_array.obj(), responseId,
mapping.Release());
java_channel.obj(), message_array.obj(), responseId);
} else {
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
java_channel.obj(), nullptr, responseId, nullptr);
java_channel.obj(), nullptr, responseId);
}
FML_CHECK(fml::jni::CheckException(env));

View File

@@ -10,7 +10,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.dart.DartMessenger.DartMessengerTaskQueue;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
import java.nio.ByteBuffer;
@@ -23,8 +22,6 @@ import org.robolectric.annotation.Config;
@Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class)
public class DartMessengerTest {
SynchronousTaskQueue synchronousTaskQueue = new SynchronousTaskQueue();
private static class ReportingUncaughtExceptionHandler
implements Thread.UncaughtExceptionHandler {
public Throwable latestException;
@@ -35,12 +32,6 @@ public class DartMessengerTest {
}
}
private static class SynchronousTaskQueue implements DartMessengerTaskQueue {
public void dispatch(Runnable runnable) {
runnable.run();
}
}
@Test
public void itHandlesErrors() {
// Setup test.
@@ -53,14 +44,14 @@ public class DartMessengerTest {
currentThread.setUncaughtExceptionHandler(reportingHandler);
// Create object under test.
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
final BinaryMessageHandler throwingHandler = mock(BinaryMessageHandler.class);
Mockito.doThrow(AssertionError.class)
.when(throwingHandler)
.onMessage(any(ByteBuffer.class), any(DartMessenger.Reply.class));
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
messenger.setMessageHandler("test", throwingHandler, taskQueue);
messenger.handleMessageFromDart("test", ByteBuffer.allocate(0), 0, 0);
messenger.setMessageHandler("test", throwingHandler);
messenger.handleMessageFromDart("test", ByteBuffer.allocate(0), 0);
assertNotNull(reportingHandler.latestException);
assertTrue(reportingHandler.latestException instanceof AssertionError);
currentThread.setUncaughtExceptionHandler(savedHandler);
@@ -70,22 +61,21 @@ public class DartMessengerTest {
public void givesDirectByteBuffer() {
// Setup test.
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
final String channel = "foobar";
final boolean[] wasDirect = {false};
final BinaryMessenger.BinaryMessageHandler handler =
(message, reply) -> {
wasDirect[0] = message.isDirect();
};
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
messenger.setMessageHandler(channel, handler, taskQueue);
messenger.setMessageHandler(channel, handler);
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
message.rewind();
message.putChar('a');
message.putChar('b');
message.putChar('c');
message.putChar('d');
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123, 0);
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123);
assertTrue(wasDirect[0]);
}
@@ -93,7 +83,7 @@ public class DartMessengerTest {
public void directByteBufferLimitZeroAfterUsage() {
// Setup test.
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
final String channel = "foobar";
final ByteBuffer[] byteBuffers = {null};
final int bufferSize = 4 * 2;
@@ -102,15 +92,14 @@ public class DartMessengerTest {
byteBuffers[0] = message;
assertEquals(bufferSize, byteBuffers[0].limit());
};
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
messenger.setMessageHandler(channel, handler, taskQueue);
messenger.setMessageHandler(channel, handler);
final ByteBuffer message = ByteBuffer.allocateDirect(bufferSize);
message.rewind();
message.putChar('a');
message.putChar('b');
message.putChar('c');
message.putChar('d');
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123, 0);
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123);
assertNotNull(byteBuffers[0]);
assertTrue(byteBuffers[0].isDirect());
assertEquals(0, byteBuffers[0].limit());
@@ -150,40 +139,4 @@ public class DartMessengerTest {
messenger.send(channel, null, null);
verify(fakeFlutterJni, times(1)).dispatchEmptyPlatformMessage(eq("foobar"), eq(2));
}
@Test
public void cleansUpMessageData() throws InterruptedException {
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
String channel = "foobar";
BinaryMessenger.BinaryMessageHandler handler =
(ByteBuffer message, BinaryMessenger.BinaryReply reply) -> {
reply.reply(null);
};
messenger.setMessageHandler(channel, handler, taskQueue);
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
int replyId = 1;
long messageData = 1234;
messenger.handleMessageFromDart(channel, message, replyId, messageData);
verify(fakeFlutterJni).cleanupMessageData(eq(messageData));
}
@Test
public void cleansUpMessageDataOnError() throws InterruptedException {
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
final DartMessenger messenger = new DartMessenger(fakeFlutterJni, () -> synchronousTaskQueue);
BinaryMessenger.TaskQueue taskQueue = messenger.makeBackgroundTaskQueue();
String channel = "foobar";
BinaryMessenger.BinaryMessageHandler handler =
(ByteBuffer message, BinaryMessenger.BinaryReply reply) -> {
throw new RuntimeException("hello");
};
messenger.setMessageHandler(channel, handler, taskQueue);
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
int replyId = 1;
long messageData = 1234;
messenger.handleMessageFromDart(channel, message, replyId, messageData);
verify(fakeFlutterJni).cleanupMessageData(eq(messageData));
}
}

View File

@@ -1884,7 +1884,7 @@ public class TextInputPluginTest {
textInputChannel.setTextInputMethodHandler(mockHandler);
verify(mockBinaryMessenger, times(1))
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture(), eq(null));
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
binaryMessageHandlerCaptor.getValue();
@@ -1917,7 +1917,7 @@ public class TextInputPluginTest {
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
verify(mockBinaryMessenger, times(1))
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture(), eq(null));
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
JSONObject arguments = new JSONObject();
arguments.put("action", "actionCommand");
@@ -1948,7 +1948,7 @@ public class TextInputPluginTest {
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
verify(mockBinaryMessenger, times(1))
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture(), eq(null));
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
JSONObject arguments = new JSONObject();
arguments.put("action", "actionCommand");

View File

@@ -218,7 +218,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void getPlatformViewById__hybridComposition() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -246,7 +246,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void createPlatformViewMessage__initializesAndroidView() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -268,7 +268,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void createPlatformViewMessage__throwsIfViewIsNull() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -296,7 +296,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void onDetachedFromJNI_clearsPlatformViewContext() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -326,7 +326,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void onPreEngineRestart_clearsPlatformViewContext() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -356,7 +356,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void createPlatformViewMessage__throwsIfViewHasParent() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -386,7 +386,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void disposeAndroidView__hybridComposition() {
PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -427,12 +427,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(
shadows = {
ShadowFlutterSurfaceView.class,
ShadowFlutterJNI.class,
ShadowPlatformTaskQueue.class
})
@Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
public void onEndFrame__destroysOverlaySurfaceAfterFrameOnFlutterSurfaceView() {
final PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -530,12 +525,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(
shadows = {
ShadowFlutterSurfaceView.class,
ShadowFlutterJNI.class,
ShadowPlatformTaskQueue.class
})
@Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
public void onEndFrame__removesPlatformViewParent() {
final PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -573,12 +563,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(
shadows = {
ShadowFlutterSurfaceView.class,
ShadowFlutterJNI.class,
ShadowPlatformTaskQueue.class
})
@Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
public void detach__destroysOverlaySurfaces() {
final PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -710,7 +695,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void convertPlatformViewRenderSurfaceAsDefault() {
final PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -756,7 +741,7 @@ public class PlatformViewsControllerTest {
}
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
@Config(shadows = {ShadowFlutterJNI.class})
public void dontConverRenderSurfaceWhenFlagIsTrue() {
final PlatformViewsController platformViewsController = new PlatformViewsController();
@@ -827,10 +812,7 @@ public class PlatformViewsControllerTest {
new MethodCall("create", platformViewCreateArguments);
jni.handlePlatformMessage(
"flutter/platform_views",
encodeMethodCall(platformCreateMethodCall),
/*replyId=*/ 0,
/*messageData=*/ 0);
"flutter/platform_views", encodeMethodCall(platformCreateMethodCall), /*replyId=*/ 0);
}
private static void disposePlatformView(
@@ -844,10 +826,7 @@ public class PlatformViewsControllerTest {
new MethodCall("dispose", platformViewDisposeArguments);
jni.handlePlatformMessage(
"flutter/platform_views",
encodeMethodCall(platformDisposeMethodCall),
/*replyId=*/ 0,
/*messageData=*/ 0);
"flutter/platform_views", encodeMethodCall(platformDisposeMethodCall), /*replyId=*/ 0);
}
private static void synchronizeToNativeViewHierarchy(
@@ -856,10 +835,7 @@ public class PlatformViewsControllerTest {
final MethodCall convertMethodCall = new MethodCall("synchronizeToNativeViewHierarchy", yes);
jni.handlePlatformMessage(
"flutter/platform_views",
encodeMethodCall(convertMethodCall),
/*replyId=*/ 0,
/*messageData=*/ 0);
"flutter/platform_views", encodeMethodCall(convertMethodCall), /*replyId=*/ 0);
}
private static FlutterView attach(
@@ -925,20 +901,6 @@ public class PlatformViewsControllerTest {
return view;
}
/**
* For convenience when writing tests, this allows us to make fake messages from Flutter via
* Platform Channels. Typically those calls happen on the ui thread which dispatches to the
* platform thread. Since tests run on the platform thread it makes it difficult to test without
* this, but isn't technically required.
*/
@Implements(io.flutter.embedding.engine.dart.PlatformTaskQueue.class)
public static class ShadowPlatformTaskQueue {
@Implementation
public void dispatch(Runnable runnable) {
runnable.run();
}
}
@Implements(FlutterJNI.class)
public static class ShadowFlutterJNI {
private static SparseArray<ByteBuffer> replies = new SparseArray<>();

View File

@@ -31,10 +31,7 @@ public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
flutterEngine
.getDartExecutor()
.getBinaryMessenger()
.setMessageHandler("finish", finishHandler, null);
flutterEngine.getDartExecutor().getBinaryMessenger().setMessageHandler("finish", finishHandler);
final boolean moved = moveTaskToBack(true);
if (!moved) {

View File

@@ -22,8 +22,7 @@ public class SpawnedEngineActivity extends TestActivity {
secondEngine
.getDartExecutor()
.setMessageHandler(
"take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered(), null);
.setMessageHandler("take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered());
return secondEngine;
}

View File

@@ -19,8 +19,7 @@ public abstract class TestableFlutterActivity extends FlutterActivity {
// registration will fail and print a scary exception in the logs.
flutterEngine
.getDartExecutor()
.setMessageHandler(
"take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered(), null);
.setMessageHandler("take_screenshot", (byteBuffer, binaryReply) -> notifyFlutterRendered());
}
protected void notifyFlutterRendered() {