Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 8e439b1

Browse files
authored
Revert "android platform channels: moved to direct buffers for c <-> java interop (#26331)" (#26470)
This reverts commit a6eb224.
1 parent 32f4b73 commit 8e439b1

File tree

8 files changed

+27
-141
lines changed

8 files changed

+27
-141
lines changed

shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformM
814814
@SuppressWarnings("unused")
815815
@VisibleForTesting
816816
public void handlePlatformMessage(
817-
@NonNull final String channel, ByteBuffer message, final int replyId) {
817+
@NonNull final String channel, byte[] message, final int replyId) {
818818
if (platformMessageHandler != null) {
819819
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
820820
}
@@ -825,7 +825,7 @@ public void handlePlatformMessage(
825825
// Called by native to respond to a platform message that we sent.
826826
// TODO(mattcarroll): determine if reply is nonull or nullable
827827
@SuppressWarnings("unused")
828-
private void handlePlatformMessageResponse(int replyId, ByteBuffer reply) {
828+
private void handlePlatformMessageResponse(int replyId, byte[] reply) {
829829
if (platformMessageHandler != null) {
830830
platformMessageHandler.handlePlatformMessageResponse(replyId, reply);
831831
}

shell/platform/android/io/flutter/embedding/engine/dart/DartMessenger.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,14 @@ public void send(
7575

7676
@Override
7777
public void handleMessageFromDart(
78-
@NonNull final String channel, @Nullable ByteBuffer message, final int replyId) {
78+
@NonNull final String channel, @Nullable byte[] message, final int replyId) {
7979
Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
8080
BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
8181
if (handler != null) {
8282
try {
8383
Log.v(TAG, "Deferring to registered handler to process message.");
84-
handler.onMessage(message, new Reply(flutterJNI, replyId));
85-
if (message != null && message.isDirect()) {
86-
// This ensures that if a user retains an instance to the ByteBuffer and it happens to
87-
// be direct they will get a deterministic error.
88-
message.limit(0);
89-
}
84+
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
85+
handler.onMessage(buffer, new Reply(flutterJNI, replyId));
9086
} catch (Exception ex) {
9187
Log.e(TAG, "Uncaught exception in binary message listener", ex);
9288
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
@@ -100,18 +96,13 @@ public void handleMessageFromDart(
10096
}
10197

10298
@Override
103-
public void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply) {
99+
public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) {
104100
Log.v(TAG, "Received message reply from Dart.");
105101
BinaryMessenger.BinaryReply callback = pendingReplies.remove(replyId);
106102
if (callback != null) {
107103
try {
108104
Log.v(TAG, "Invoking registered callback for reply from Dart.");
109-
callback.reply(reply);
110-
if (reply != null && reply.isDirect()) {
111-
// This ensures that if a user retains an instance to the ByteBuffer and it happens to
112-
// be direct they will get a deterministic error.
113-
reply.limit(0);
114-
}
105+
callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
115106
} catch (Exception ex) {
116107
Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
117108
} catch (Error err) {

shell/platform/android/io/flutter/embedding/engine/dart/PlatformMessageHandler.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66

77
import androidx.annotation.NonNull;
88
import androidx.annotation.Nullable;
9-
import java.nio.ByteBuffer;
109

1110
/** Handler that receives messages from Dart code. */
1211
public interface PlatformMessageHandler {
1312
void handleMessageFromDart(
14-
@NonNull final String channel, @Nullable ByteBuffer message, final int replyId);
13+
@NonNull final String channel, @Nullable byte[] message, final int replyId);
1514

16-
void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply);
15+
void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply);
1716
}

shell/platform/android/io/flutter/plugin/common/BinaryCodec.java

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,8 @@
1818
public final class BinaryCodec implements MessageCodec<ByteBuffer> {
1919
// This codec must match the Dart codec of the same name in package flutter/services.
2020
public static final BinaryCodec INSTANCE = new BinaryCodec();
21-
/**
22-
* A BinaryCodec that returns direct ByteBuffers from `decodeMessage` for better performance.
23-
*
24-
* @see BinaryCodec.BinaryCodec(boolean)
25-
*/
26-
public static final BinaryCodec INSTANCE_DIRECT = new BinaryCodec(true);
2721

28-
private final boolean returnsDirectByteBufferFromDecoding;
29-
30-
private BinaryCodec() {
31-
this.returnsDirectByteBufferFromDecoding = false;
32-
}
33-
34-
/**
35-
* A constructor for BinaryCodec.
36-
*
37-
* @param returnsDirectByteBufferFromDecoding `true` means that the Codec will return direct
38-
* ByteBuffers from `decodeMessage`. Direct ByteBuffers will have better performance but will
39-
* be invalid beyond the scope of the `decodeMessage` call. `false` means Flutter will copy
40-
* the encoded message to Java's memory, so the ByteBuffer will be valid beyond the
41-
* decodeMessage call, at the cost of a copy.
42-
*/
43-
private BinaryCodec(boolean returnsDirectByteBufferFromDecoding) {
44-
this.returnsDirectByteBufferFromDecoding = returnsDirectByteBufferFromDecoding;
45-
}
22+
private BinaryCodec() {}
4623

4724
@Override
4825
public ByteBuffer encodeMessage(ByteBuffer message) {
@@ -51,13 +28,6 @@ public ByteBuffer encodeMessage(ByteBuffer message) {
5128

5229
@Override
5330
public ByteBuffer decodeMessage(ByteBuffer message) {
54-
if (returnsDirectByteBufferFromDecoding) {
55-
return message;
56-
} else {
57-
ByteBuffer result = ByteBuffer.allocate(message.capacity());
58-
result.put(message);
59-
result.rewind();
60-
return result;
61-
}
31+
return message;
6232
}
6333
}

shell/platform/android/io/flutter/plugin/common/MessageCodec.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ public interface MessageCodec<T> {
2626
/**
2727
* Decodes the specified message from binary.
2828
*
29-
* <p><b>Warning:</b> The ByteBuffer is "direct" and it won't be valid beyond this call. Storing
30-
* the ByteBuffer and using it later and will lead to a {@code java.nio.BufferUnderflowException}.
31-
* If you want to retain the data you'll need to copy it.
32-
*
3329
* @param message the {@link ByteBuffer} message, possibly null.
3430
* @return a T value representation of the bytes between the given buffer's current position and
3531
* its limit, or null, if message is null.

shell/platform/android/platform_view_android_jni_impl.cc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -828,16 +828,15 @@ bool RegisterApi(JNIEnv* env) {
828828

829829
g_handle_platform_message_method =
830830
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
831-
"(Ljava/lang/String;Ljava/nio/ByteBuffer;I)V");
831+
"(Ljava/lang/String;[BI)V");
832832

833833
if (g_handle_platform_message_method == nullptr) {
834834
FML_LOG(ERROR) << "Could not locate handlePlatformMessage method";
835835
return false;
836836
}
837837

838838
g_handle_platform_message_response_method = env->GetMethodID(
839-
g_flutter_jni_class->obj(), "handlePlatformMessageResponse",
840-
"(ILjava/nio/ByteBuffer;)V");
839+
g_flutter_jni_class->obj(), "handlePlatformMessageResponse", "(I[B)V");
841840

842841
if (g_handle_platform_message_response_method == nullptr) {
843842
FML_LOG(ERROR) << "Could not locate handlePlatformMessageResponse method";
@@ -1108,10 +1107,11 @@ void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage(
11081107
fml::jni::StringToJavaString(env, message->channel());
11091108

11101109
if (message->hasData()) {
1111-
fml::jni::ScopedJavaLocalRef<jobject> message_array(
1112-
env, env->NewDirectByteBuffer(
1113-
const_cast<uint8_t*>(message->data().GetMapping()),
1114-
message->data().GetSize()));
1110+
fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(
1111+
env, env->NewByteArray(message->data().GetSize()));
1112+
env->SetByteArrayRegion(
1113+
message_array.obj(), 0, message->data().GetSize(),
1114+
reinterpret_cast<const jbyte*>(message->data().GetMapping()));
11151115
env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method,
11161116
java_channel.obj(), message_array.obj(), responseId);
11171117
} else {
@@ -1141,9 +1141,10 @@ void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessageResponse(
11411141
nullptr);
11421142
} else {
11431143
// Convert the vector to a Java byte array.
1144-
fml::jni::ScopedJavaLocalRef<jobject> data_array(
1145-
env, env->NewDirectByteBuffer(const_cast<uint8_t*>(data->GetMapping()),
1146-
data->GetSize()));
1144+
fml::jni::ScopedJavaLocalRef<jbyteArray> data_array(
1145+
env, env->NewByteArray(data->GetSize()));
1146+
env->SetByteArrayRegion(data_array.obj(), 0, data->GetSize(),
1147+
reinterpret_cast<const jbyte*>(data->GetMapping()));
11471148

11481149
env->CallVoidMethod(java_object.obj(),
11491150
g_handle_platform_message_response_method, responseId,
Lines changed: 1 addition & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package io.flutter.embedding.engine.dart;
22

3-
import static junit.framework.TestCase.assertEquals;
43
import static junit.framework.TestCase.assertNotNull;
54
import static junit.framework.TestCase.assertTrue;
65
import static org.mockito.Matchers.any;
76
import static org.mockito.Mockito.mock;
87

98
import io.flutter.embedding.engine.FlutterJNI;
10-
import io.flutter.plugin.common.BinaryMessenger;
119
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
1210
import java.nio.ByteBuffer;
1311
import org.junit.Test;
@@ -48,80 +46,9 @@ public void itHandlesErrors() {
4846
.onMessage(any(ByteBuffer.class), any(DartMessenger.Reply.class));
4947

5048
messenger.setMessageHandler("test", throwingHandler);
51-
messenger.handleMessageFromDart("test", ByteBuffer.allocate(0), 0);
49+
messenger.handleMessageFromDart("test", new byte[] {}, 0);
5250
assertNotNull(reportingHandler.latestException);
5351
assertTrue(reportingHandler.latestException instanceof AssertionError);
5452
currentThread.setUncaughtExceptionHandler(savedHandler);
5553
}
56-
57-
@Test
58-
public void givesDirectByteBuffer() {
59-
// Setup test.
60-
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
61-
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
62-
final String channel = "foobar";
63-
final boolean[] wasDirect = {false};
64-
final BinaryMessenger.BinaryMessageHandler handler =
65-
(message, reply) -> {
66-
wasDirect[0] = message.isDirect();
67-
};
68-
messenger.setMessageHandler(channel, handler);
69-
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
70-
message.rewind();
71-
message.putChar('a');
72-
message.putChar('b');
73-
message.putChar('c');
74-
message.putChar('d');
75-
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123);
76-
assertTrue(wasDirect[0]);
77-
}
78-
79-
@Test
80-
public void directByteBufferLimitZeroAfterUsage() {
81-
// Setup test.
82-
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
83-
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
84-
final String channel = "foobar";
85-
final ByteBuffer[] byteBuffers = {null};
86-
final int bufferSize = 4 * 2;
87-
final BinaryMessenger.BinaryMessageHandler handler =
88-
(message, reply) -> {
89-
byteBuffers[0] = message;
90-
assertEquals(bufferSize, byteBuffers[0].limit());
91-
};
92-
messenger.setMessageHandler(channel, handler);
93-
final ByteBuffer message = ByteBuffer.allocateDirect(bufferSize);
94-
message.rewind();
95-
message.putChar('a');
96-
message.putChar('b');
97-
message.putChar('c');
98-
message.putChar('d');
99-
messenger.handleMessageFromDart(channel, message, /*replyId=*/ 123);
100-
assertNotNull(byteBuffers[0]);
101-
assertTrue(byteBuffers[0].isDirect());
102-
assertEquals(0, byteBuffers[0].limit());
103-
}
104-
105-
@Test
106-
public void directByteBufferLimitZeroAfterReply() {
107-
// Setup test.
108-
final FlutterJNI fakeFlutterJni = mock(FlutterJNI.class);
109-
final DartMessenger messenger = new DartMessenger(fakeFlutterJni);
110-
final ByteBuffer message = ByteBuffer.allocateDirect(4 * 2);
111-
final String channel = "foobar";
112-
message.rewind();
113-
message.putChar('a');
114-
message.putChar('b');
115-
message.putChar('c');
116-
message.putChar('d');
117-
final ByteBuffer[] byteBuffers = {null};
118-
BinaryMessenger.BinaryReply callback =
119-
(reply) -> {
120-
assertTrue(reply.isDirect());
121-
byteBuffers[0] = reply;
122-
};
123-
messenger.send(channel, null, callback);
124-
messenger.handlePlatformMessageResponse(1, message);
125-
assertEquals(0, byteBuffers[0].limit());
126-
}
12754
}

shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,10 +630,12 @@ public void checkInputConnectionProxy__falseIfViewIsNull() {
630630
assertFalse(shouldProxying);
631631
}
632632

633-
private static ByteBuffer encodeMethodCall(MethodCall call) {
633+
private static byte[] encodeMethodCall(MethodCall call) {
634634
final ByteBuffer buffer = StandardMethodCodec.INSTANCE.encodeMethodCall(call);
635635
buffer.rewind();
636-
return buffer;
636+
final byte[] dest = new byte[buffer.remaining()];
637+
buffer.get(dest);
638+
return dest;
637639
}
638640

639641
private static void createPlatformView(

0 commit comments

Comments
 (0)