mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Android] Expose channel buffer resize and overflow calls (flutter/engine#44434)
## Description This PR updates the Android engine in order to provide a more efficient implementation for `BasicMessageChannel.resizeChannelBuffer` (helper to call the `resize` control command). It also adds a new helper called`BasicMessageChannel.allowChannelBufferOverflow` to call the `overflow` control command. ## Related Issue Fixes https://github.com/flutter/flutter/issues/132048 Android implementation for https://github.com/flutter/flutter/issues/132386 ## Tests Adds 2 tests.
This commit is contained in:
parent
216984de1a
commit
4f50825d26
@ -12,8 +12,7 @@ import io.flutter.Log;
|
||||
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
|
||||
import io.flutter.plugin.common.BinaryMessenger.BinaryReply;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A named channel for communicating with the Flutter application using basic, asynchronous message
|
||||
@ -143,13 +142,56 @@ public final class BasicMessageChannel<T> {
|
||||
resizeChannelBuffer(messenger, name, newSize);
|
||||
}
|
||||
|
||||
static void resizeChannelBuffer(
|
||||
@NonNull BinaryMessenger messenger, @NonNull String channel, int newSize) {
|
||||
Charset charset = Charset.forName("UTF-8");
|
||||
String messageString = String.format(Locale.US, "resize\r%s\r%d", channel, newSize);
|
||||
final byte[] bytes = messageString.getBytes(charset);
|
||||
/**
|
||||
* Toggles whether the channel should show warning messages when discarding messages due to
|
||||
* overflow. When 'allowed' is true the channel is expected to overflow and warning messages will
|
||||
* not be shown.
|
||||
*/
|
||||
public void allowChannelBufferOverflow(boolean allowed) {
|
||||
allowChannelBufferOverflow(messenger, name, allowed);
|
||||
}
|
||||
|
||||
private static ByteBuffer packetFromEncodedMessage(ByteBuffer message) {
|
||||
// Create a bytes array using the buffer content (messages.array() can not be used here).
|
||||
message.flip();
|
||||
final byte[] bytes = new byte[message.remaining()];
|
||||
message.get(bytes);
|
||||
|
||||
// The current Android Java/JNI platform message implementation assumes
|
||||
// that all buffers passed to native are direct buffers.
|
||||
ByteBuffer packet = ByteBuffer.allocateDirect(bytes.length);
|
||||
packet.put(bytes);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the number of messages that will get buffered when sending messages to channels that
|
||||
* aren't fully set up yet. For example, the engine isn't running yet or the channel's message
|
||||
* handler isn't set up on the Dart side yet.
|
||||
*/
|
||||
public static void resizeChannelBuffer(
|
||||
@NonNull BinaryMessenger messenger, @NonNull String channel, int newSize) {
|
||||
final StandardMethodCodec codec = StandardMethodCodec.INSTANCE;
|
||||
Object[] arguments = {channel, newSize};
|
||||
MethodCall methodCall = new MethodCall("resize", Arrays.asList(arguments));
|
||||
ByteBuffer message = codec.encodeMethodCall(methodCall);
|
||||
ByteBuffer packet = packetFromEncodedMessage(message);
|
||||
messenger.send(BasicMessageChannel.CHANNEL_BUFFERS_CHANNEL, packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether the channel should show warning messages when discarding messages due to
|
||||
* overflow. When 'allowed' is true the channel is expected to overflow and warning messages will
|
||||
* not be shown.
|
||||
*/
|
||||
public static void allowChannelBufferOverflow(
|
||||
@NonNull BinaryMessenger messenger, @NonNull String channel, boolean allowed) {
|
||||
final StandardMethodCodec codec = StandardMethodCodec.INSTANCE;
|
||||
Object[] arguments = {channel, allowed};
|
||||
MethodCall methodCall = new MethodCall("overflow", Arrays.asList(arguments));
|
||||
ByteBuffer message = codec.encodeMethodCall(methodCall);
|
||||
ByteBuffer packet = packetFromEncodedMessage(message);
|
||||
messenger.send(BasicMessageChannel.CHANNEL_BUFFERS_CHANNEL, packet);
|
||||
}
|
||||
|
||||
|
||||
@ -157,6 +157,15 @@ public class MethodChannel {
|
||||
BasicMessageChannel.resizeChannelBuffer(messenger, name, newSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether the channel should show warning messages when discarding messages due to
|
||||
* overflow. When 'allowed' is true the channel is expected to overflow and warning messages will
|
||||
* not be shown.
|
||||
*/
|
||||
public void allowChannelBufferOverflow(boolean allowed) {
|
||||
BasicMessageChannel.allowChannelBufferOverflow(messenger, name, allowed);
|
||||
}
|
||||
|
||||
/** A handler of incoming method calls. */
|
||||
public interface MethodCallHandler {
|
||||
/**
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package io.flutter.plugin.common;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
@ -11,17 +12,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@Config(manifest = Config.NONE)
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MethodChannelTest {
|
||||
@Test
|
||||
public void methodChannel_resizeChannelBuffer() {
|
||||
public void resizeChannelBufferMessageIsWellformed() {
|
||||
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
|
||||
DartExecutor dartExecutor = new DartExecutor(mockFlutterJNI, mock(AssetManager.class));
|
||||
String channel = "flutter/test";
|
||||
@ -30,15 +30,68 @@ public class MethodChannelTest {
|
||||
int newSize = 3;
|
||||
rawChannel.resizeChannelBuffer(newSize);
|
||||
|
||||
Charset charset = Charset.forName("UTF-8");
|
||||
String messageString = String.format(Locale.US, "resize\r%s\r%d", channel, newSize);
|
||||
final byte[] bytes = messageString.getBytes(charset);
|
||||
ByteBuffer packet = ByteBuffer.allocateDirect(bytes.length);
|
||||
packet.put(bytes);
|
||||
// Created from the following Dart code:
|
||||
// MethodCall methodCall = const MethodCall('resize', ['flutter/test', 3]);
|
||||
// const StandardMethodCodec().encodeMethodCall(methodCall).buffer.asUint8List();
|
||||
final byte[] expected = {
|
||||
7, 6, 114, 101, 115, 105, 122, 101, 12, 2, 7, 12, 102, 108, 117, 116, 116, 101, 114, 47, 116,
|
||||
101, 115, 116, 3, 3, 0, 0, 0
|
||||
};
|
||||
|
||||
// Verify that DartExecutor sent the correct message to FlutterJNI.
|
||||
// Verify that the correct message was sent to FlutterJNI.
|
||||
ArgumentMatcher<ByteBuffer> packetMatcher =
|
||||
new ByteBufferContentMatcher(ByteBuffer.wrap(expected));
|
||||
verify(mockFlutterJNI, times(1))
|
||||
.dispatchPlatformMessage(
|
||||
eq(BasicMessageChannel.CHANNEL_BUFFERS_CHANNEL), eq(packet), anyInt(), anyInt());
|
||||
eq(BasicMessageChannel.CHANNEL_BUFFERS_CHANNEL),
|
||||
argThat(packetMatcher),
|
||||
anyInt(),
|
||||
anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overflowChannelBufferMessageIsWellformed() {
|
||||
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
|
||||
DartExecutor dartExecutor = new DartExecutor(mockFlutterJNI, mock(AssetManager.class));
|
||||
String channel = "flutter/test";
|
||||
MethodChannel rawChannel = new MethodChannel(dartExecutor, channel);
|
||||
|
||||
rawChannel.allowChannelBufferOverflow(true);
|
||||
|
||||
// Created from the following Dart code:
|
||||
// MethodCall methodCall = const MethodCall('overflow', ['flutter/test', true]);
|
||||
// const StandardMethodCodec().encodeMethodCall(methodCall).buffer.asUint8List();
|
||||
final byte[] expected = {
|
||||
7, 8, 111, 118, 101, 114, 102, 108, 111, 119, 12, 2, 7, 12, 102, 108, 117, 116, 116, 101, 114,
|
||||
47, 116, 101, 115, 116, 1
|
||||
};
|
||||
|
||||
// Verify that the correct message was sent to FlutterJNI.
|
||||
ArgumentMatcher<ByteBuffer> packetMatcher =
|
||||
new ByteBufferContentMatcher(ByteBuffer.wrap(expected));
|
||||
verify(mockFlutterJNI, times(1))
|
||||
.dispatchPlatformMessage(
|
||||
eq(BasicMessageChannel.CHANNEL_BUFFERS_CHANNEL),
|
||||
argThat(packetMatcher),
|
||||
anyInt(),
|
||||
anyInt());
|
||||
}
|
||||
}
|
||||
|
||||
// Custom ByteBuffer matcher which calls rewind on both buffers before calling equals.
|
||||
// ByteBuffer.equals might return true when comparing byte buffers with different content if
|
||||
// both have no remaining elements.
|
||||
class ByteBufferContentMatcher implements ArgumentMatcher<ByteBuffer> {
|
||||
private ByteBuffer expected;
|
||||
|
||||
public ByteBufferContentMatcher(ByteBuffer expected) {
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ByteBuffer received) {
|
||||
expected.rewind();
|
||||
received.rewind();
|
||||
return received.equals(expected);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user