Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.google.common.util.concurrent.SettableFuture;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.plugin.common.BinaryMessenger;
Expand All @@ -32,8 +33,15 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {

@NonNull private final FlutterJNI flutterJNI;

/**
* Maps a channel name to an object that contains the task queue and the handler associated with
* the channel.
*/
@NonNull private final ConcurrentHashMap<String, HandlerInfo> messageHandlers;

/** Maps a channel name to a future that resolves when the channel is defined. */
@NonNull private final ConcurrentHashMap<String, SettableFuture<Void>> definedChannels;

@NonNull private final Map<Integer, BinaryMessenger.BinaryReply> pendingReplies;
private int nextReplyId = 1;

Expand All @@ -46,6 +54,7 @@ class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
DartMessenger(@NonNull FlutterJNI flutterJNI, @NonNull TaskQueueFactory taskQueueFactory) {
this.flutterJNI = flutterJNI;
this.messageHandlers = new ConcurrentHashMap<>();
this.definedChannels = new ConcurrentHashMap<>();
this.pendingReplies = new HashMap<>();
this.createdTaskQueues = new WeakHashMap<TaskQueue, DartMessengerTaskQueue>();
this.taskQueueFactory = taskQueueFactory;
Expand Down Expand Up @@ -124,18 +133,22 @@ public void setMessageHandler(
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).");
}
return;
}
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));
}
Log.v(TAG, "Setting handler for channel '" + channel + "'");
if (!definedChannels.has(channel)) {
definedChannels.put(channel, SettableFuture.create());
}
definedChannels.get(channel).set(Void.TYPE);
messageHandlers.put(channel, new HandlerInfo(handler, dartMessengerTaskQueue));
}

@Override
Expand Down Expand Up @@ -189,6 +202,38 @@ public void handleMessageFromDart(
long messageData) {
// Called from the ui thread.
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");

if (!messageHandlers.has(channel)) {
// The channel is not defined when the Dart VM sends a message before the channels are
// registered.
//
// This is possible if the Dart VM starts before channel registration, and if the thread that
// registers the channels is busy or slow at registering the channel handlers.
//
// In such cases, wait for a limited time, and exit with error if the time is exceeded.
// This is effectively acting as a lock, so the current thread (Dart UI thread) is blocked
// until the lock is released.
if (!definedChannels.has(channel)) {
definedChannels.put(channel, SettableFuture.create());
}
final SettableFuture<Boolean> future = definedChannels.get(channel);
try {
future.get(10, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException ex) {
Log.e(TAG, "Undefined channel " + channel + ".", ex);
return;
} catch (TimeoutException ex) {
Log.e(
TAG,
"Channel "
+ channel
+ " was not defined in time. "
+ "This likely means that the handler was never defined, or that the thread "
+ "that defines the handler has been busy for an extended period of time.",
ex);
return;
}
}
@Nullable final HandlerInfo handlerInfo = messageHandlers.get(channel);
@Nullable
final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null;
Expand Down