Skip to content

Commit 32973bf

Browse files
bparrishMinesandroidseb
authored andcommitted
[pigeon] Fixes potential race condition caused by a ProxyApi constructor message call being made in an async method (flutter#8656)
Host api calls now declare a `Future` variable from `channel.send` first. Then it `await`s the future immedieately or inside of a async method. Part of fixing webview_flutter_wkwebview issue: flutter/flutter#162437
1 parent 1730363 commit 32973bf

18 files changed

Lines changed: 982 additions & 424 deletions

packages/pigeon/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 24.2.1
2+
3+
* [dart] Fixes potential race condition caused by a ProxyApi constructor message call being made in
4+
an async method.
5+
16
## 24.2.0
27

38
* Adjusts task queues to use a shared task queue for all methods in a single

packages/pigeon/example/app/lib/src/messages.g.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,9 @@ class ExampleHostApi {
126126
pigeonChannelCodec,
127127
binaryMessenger: pigeonVar_binaryMessenger,
128128
);
129+
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
129130
final List<Object?>? pigeonVar_replyList =
130-
await pigeonVar_channel.send(null) as List<Object?>?;
131+
await pigeonVar_sendFuture as List<Object?>?;
131132
if (pigeonVar_replyList == null) {
132133
throw _createConnectionError(pigeonVar_channelName);
133134
} else if (pigeonVar_replyList.length > 1) {
@@ -155,8 +156,10 @@ class ExampleHostApi {
155156
pigeonChannelCodec,
156157
binaryMessenger: pigeonVar_binaryMessenger,
157158
);
159+
final Future<Object?> pigeonVar_sendFuture =
160+
pigeonVar_channel.send(<Object?>[a, b]);
158161
final List<Object?>? pigeonVar_replyList =
159-
await pigeonVar_channel.send(<Object?>[a, b]) as List<Object?>?;
162+
await pigeonVar_sendFuture as List<Object?>?;
160163
if (pigeonVar_replyList == null) {
161164
throw _createConnectionError(pigeonVar_channelName);
162165
} else if (pigeonVar_replyList.length > 1) {
@@ -184,8 +187,10 @@ class ExampleHostApi {
184187
pigeonChannelCodec,
185188
binaryMessenger: pigeonVar_binaryMessenger,
186189
);
190+
final Future<Object?> pigeonVar_sendFuture =
191+
pigeonVar_channel.send(<Object?>[message]);
187192
final List<Object?>? pigeonVar_replyList =
188-
await pigeonVar_channel.send(<Object?>[message]) as List<Object?>?;
193+
await pigeonVar_sendFuture as List<Object?>?;
189194
if (pigeonVar_replyList == null) {
190195
throw _createConnectionError(pigeonVar_channelName);
191196
} else if (pigeonVar_replyList.length > 1) {

packages/pigeon/lib/src/dart/dart_generator.dart

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,7 @@ if (wrapped == null) {
11151115
required Iterable<Parameter> parameters,
11161116
required TypeDeclaration returnType,
11171117
required bool addSuffixVariable,
1118+
bool insideAsyncMethod = true,
11181119
}) {
11191120
String sendArgument = 'null';
11201121
if (parameters.isNotEmpty) {
@@ -1152,9 +1153,21 @@ if (wrapped == null) {
11521153
}
11531154
returnStatement = '$returnStatement;';
11541155

1156+
const String sendFutureVar = '${varNamePrefix}sendFuture';
1157+
indent.writeln(
1158+
'final Future<Object?> $sendFutureVar = ${varNamePrefix}channel.send($sendArgument);',
1159+
);
1160+
1161+
// If the message call is not made inside of an async method, this creates
1162+
// an anonymous function to handle the send future.
1163+
if (!insideAsyncMethod) {
1164+
indent.writeln('() async {');
1165+
indent.inc();
1166+
}
1167+
11551168
indent.format('''
11561169
final List<Object?>? ${varNamePrefix}replyList =
1157-
\t\tawait ${varNamePrefix}channel.send($sendArgument) as List<Object?>?;
1170+
\t\tawait $sendFutureVar as List<Object?>?;
11581171
if (${varNamePrefix}replyList == null) {
11591172
\tthrow _createConnectionError(${varNamePrefix}channelName);
11601173
} else if (${varNamePrefix}replyList.length > 1) {
@@ -1178,6 +1191,11 @@ if (${varNamePrefix}replyList == null) {
11781191
} else {
11791192
\t$returnStatement
11801193
}''');
1194+
1195+
if (!insideAsyncMethod) {
1196+
indent.dec();
1197+
indent.writeln('}();');
1198+
}
11811199
}
11821200

11831201
void _writeFlutterMethodMessageHandler(
@@ -1398,6 +1416,7 @@ if (${varNamePrefix}replyList == null) {
13981416
Indent(messageCallSink),
13991417
addSuffixVariable: false,
14001418
channelName: channelName,
1419+
insideAsyncMethod: false,
14011420
parameters: <Parameter>[
14021421
Parameter(
14031422
name: '${varNamePrefix}instanceIdentifier',
@@ -1426,9 +1445,7 @@ if (${varNamePrefix}replyList == null) {
14261445
cb.Code(
14271446
'final BinaryMessenger? ${varNamePrefix}binaryMessenger = ${binaryMessengerParameter.name};',
14281447
),
1429-
const cb.Code('() async {'),
14301448
cb.Code(messageCallSink.toString()),
1431-
const cb.Code('}();'),
14321449
]);
14331450
},
14341451
);

packages/pigeon/lib/src/generator_tools.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import 'ast.dart';
1414
/// The current version of pigeon.
1515
///
1616
/// This must match the version in pubspec.yaml.
17-
const String pigeonVersion = '24.2.0';
17+
const String pigeonVersion = '24.2.1';
1818

1919
/// Read all the content from [stdin] to a String.
2020
String readStdin() {

packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/background_platform_channels.gen.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,12 @@ class BackgroundApi2Host {
6464
pigeonChannelCodec,
6565
binaryMessenger: pigeonVar_binaryMessenger,
6666
);
67+
final Future<Object?> pigeonVar_sendFuture =
68+
pigeonVar_channel.send(<Object?>[
69+
<Object?>[x, y]
70+
]);
6771
final List<Object?>? pigeonVar_replyList =
68-
await pigeonVar_channel.send(<Object?>[x, y]) as List<Object?>?;
72+
await pigeonVar_sendFuture as List<Object?>?;
6973
if (pigeonVar_replyList == null) {
7074
throw _createConnectionError(pigeonVar_channelName);
7175
} else if (pigeonVar_replyList.length > 1) {

0 commit comments

Comments
 (0)