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

Commit 9e9bb48

Browse files
committed
Refactor platform message logic
This laids the groundwork for sending messages through ChannelBuffers with channel-specific callbacks rather than a single onPlatformMessage callback. This allows us to remove the logic from the framework that puts data back into the channel buffers. Right now (before this PR) the logic for messages from plugins to the framework is bidirectional: ``` ** * Plugins -> Engine -> ChannelBuffers <- Framework <---+-. | | | | | '------> via drain ----' | | | '----------------- onPlatformMessage ---' * = when the listener is null on the framework side ** = when onPlatformMessage is null ``` This ends up with weird race conditions and is generally less than completely clear. With this PR, we lay the groundwork for eventually reaching this model: ``` Plugins -> Engine -> ChannelBuffers -> Framework ``` ...which is significantly simpler.
1 parent e4dffc1 commit 9e9bb48

File tree

14 files changed

+1421
-404
lines changed

14 files changed

+1421
-404
lines changed

lib/ui/channel_buffers.dart

Lines changed: 473 additions & 144 deletions
Large diffs are not rendered by default.

lib/ui/hooks.dart

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ void _invoke(void Function()? callback, Zone zone) {
159159
}
160160

161161
/// Invokes [callback] inside the given [zone] passing it [arg].
162+
///
163+
/// The 1 in the name refers to the number of arguments expected by
164+
/// the callback (and thus passed to this function, in addition to the
165+
/// callback itself and the zone in which the callback is executed).
162166
void _invoke1<A>(void Function(A a)? callback, Zone zone, A arg) {
163167
if (callback == null) {
164168
return;
@@ -173,14 +177,33 @@ void _invoke1<A>(void Function(A a)? callback, Zone zone, A arg) {
173177
}
174178
}
175179

180+
/// Invokes [callback] inside the given [zone] passing it [arg1] and [arg2].
181+
///
182+
/// The 2 in the name refers to the number of arguments expected by
183+
/// the callback (and thus passed to this function, in addition to the
184+
/// callback itself and the zone in which the callback is executed).
185+
void _invoke2<A1, A2>(void Function(A1 a1, A2 a2)? callback, Zone zone, A1 arg1, A2 arg2) {
186+
if (callback == null) {
187+
return;
188+
}
189+
190+
assert(zone != null); // ignore: unnecessary_null_comparison
191+
192+
if (identical(zone, Zone.current)) {
193+
callback(arg1, arg2);
194+
} else {
195+
zone.runGuarded(() {
196+
callback(arg1, arg2);
197+
});
198+
}
199+
}
200+
176201
/// Invokes [callback] inside the given [zone] passing it [arg1], [arg2], and [arg3].
177-
void _invoke3<A1, A2, A3>(
178-
void Function(A1 a1, A2 a2, A3 a3)? callback,
179-
Zone zone,
180-
A1 arg1,
181-
A2 arg2,
182-
A3 arg3,
183-
) {
202+
///
203+
/// The 3 in the name refers to the number of arguments expected by
204+
/// the callback (and thus passed to this function, in addition to the
205+
/// callback itself and the zone in which the callback is executed).
206+
void _invoke3<A1, A2, A3>(void Function(A1 a1, A2 a2, A3 a3)? callback, Zone zone, A1 arg1, A2 arg2, A3 arg3) {
184207
if (callback == null) {
185208
return;
186209
}

lib/ui/platform_dispatcher.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef SemanticsActionCallback = void Function(int id, SemanticsAction action,
3838
typedef PlatformMessageResponseCallback = void Function(ByteData? data);
3939

4040
/// Signature for [PlatformDispatcher.onPlatformMessage].
41+
// TODO(ianh): deprecate once framework uses [ChannelBuffers.setListener].
4142
typedef PlatformMessageCallback = void Function(String name, ByteData? data, PlatformMessageResponseCallback? callback);
4243

4344
// Signature for _setNeedsReportTimings.
@@ -413,6 +414,8 @@ class PlatformDispatcher {
413414
///
414415
/// The framework invokes this callback in the same zone in which the callback
415416
/// was set.
417+
// TODO(ianh): Deprecate onPlatformMessage once the framework is moved over
418+
// to using channel buffers exclusively.
416419
PlatformMessageCallback? get onPlatformMessage => _onPlatformMessage;
417420
PlatformMessageCallback? _onPlatformMessage;
418421
Zone _onPlatformMessageZone = Zone.root;
@@ -442,13 +445,15 @@ class PlatformDispatcher {
442445
};
443446
}
444447

445-
// Called from the engine, via hooks.dart
448+
/// Send a message to the framework using the [ChannelBuffers].
449+
///
450+
/// This method constructs the appropriate callback to respond
451+
/// with the given `responseId`. It should only be called for messages
452+
/// from the platform.
446453
void _dispatchPlatformMessage(String name, ByteData? data, int responseId) {
447454
if (name == ChannelBuffers.kControlChannelName) {
448455
try {
449456
channelBuffers.handleMessage(data!);
450-
} catch (ex) {
451-
_printDebug('Message to "$name" caused exception $ex');
452457
} finally {
453458
_respondToPlatformMessage(responseId, null);
454459
}
@@ -458,7 +463,7 @@ class PlatformDispatcher {
458463
_onPlatformMessageZone,
459464
name,
460465
data,
461-
(ByteData? responseData) {
466+
(ByteData? responseData) {
462467
_respondToPlatformMessage(responseId, responseData);
463468
},
464469
);

lib/ui/text.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,11 +2273,18 @@ final ByteData _fontChangeMessage = utf8.encoder.convert(
22732273
).buffer.asByteData();
22742274

22752275
FutureOr<void> _sendFontChangeMessage() async {
2276-
PlatformDispatcher.instance.onPlatformMessage?.call(
2277-
'flutter/system',
2278-
_fontChangeMessage,
2279-
(_) {},
2280-
);
2276+
const String kSystemChannelName = 'flutter/system';
2277+
if (PlatformDispatcher.instance.onPlatformMessage != null) {
2278+
_invoke3<String, ByteData?, PlatformMessageResponseCallback>(
2279+
PlatformDispatcher.instance.onPlatformMessage,
2280+
PlatformDispatcher.instance._onPlatformMessageZone,
2281+
kSystemChannelName,
2282+
_fontChangeMessage,
2283+
(ByteData? responseData) { },
2284+
);
2285+
} else {
2286+
channelBuffers.push(kSystemChannelName, _fontChangeMessage, (ByteData? responseData) { });
2287+
}
22812288
}
22822289

22832290
String _loadFontFromList(Uint8List list, _Callback<void> callback, String? fontFamily) native 'loadFontFromList';

lib/ui/window.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ class SingletonFlutterWindow extends FlutterWindow {
696696
///
697697
/// The framework invokes this callback in the same zone in which the
698698
/// callback was set.
699+
// TODO(ianh): deprecate once framework uses [ChannelBuffers.setListener].
699700
PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage;
700701
set onPlatformMessage(PlatformMessageCallback? callback) {
701702
platformDispatcher.onPlatformMessage = callback;

lib/web_ui/lib/src/engine/keyboard.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,6 @@ class Keyboard {
8181

8282
final html.KeyboardEvent keyboardEvent = event;
8383

84-
if (EnginePlatformDispatcher.instance._onPlatformMessage == null) {
85-
return;
86-
}
87-
8884
if (_shouldPreventDefault(event)) {
8985
event.preventDefault();
9086
}

lib/web_ui/lib/src/engine/navigation/history.dart

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,15 @@ class MultiEntriesBrowserHistory extends BrowserHistory {
151151
currentPath);
152152
}
153153
_lastSeenSerialCount = _currentSerialCount;
154-
if (EnginePlatformDispatcher.instance._onPlatformMessage != null) {
155-
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
156-
'flutter/navigation',
157-
const JSONMethodCodec().encodeMethodCall(
158-
MethodCall('pushRouteInformation', <dynamic, dynamic>{
159-
'location': currentPath,
160-
'state': event.state?['state'],
161-
})),
162-
(_) {},
163-
);
164-
}
154+
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
155+
'flutter/navigation',
156+
const JSONMethodCodec().encodeMethodCall(
157+
MethodCall('pushRouteInformation', <dynamic, dynamic>{
158+
'location': currentPath,
159+
'state': event.state?['state'],
160+
})),
161+
(_) {},
162+
);
165163
}
166164

167165
@override
@@ -272,13 +270,11 @@ class SingleEntryBrowserHistory extends BrowserHistory {
272270
_setupFlutterEntry(urlStrategy!);
273271

274272
// 2. Send a 'popRoute' platform message so the app can handle it accordingly.
275-
if (EnginePlatformDispatcher.instance._onPlatformMessage != null) {
276-
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
277-
'flutter/navigation',
278-
const JSONMethodCodec().encodeMethodCall(_popRouteMethodCall),
279-
(_) {},
280-
);
281-
}
273+
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
274+
'flutter/navigation',
275+
const JSONMethodCodec().encodeMethodCall(_popRouteMethodCall),
276+
(_) {},
277+
);
282278
} else if (_isFlutterEntry(event.state)) {
283279
// We get into this scenario when the user changes the url manually. It
284280
// causes a new entry to be pushed on top of our "flutter" one. When this
@@ -291,15 +287,13 @@ class SingleEntryBrowserHistory extends BrowserHistory {
291287
_userProvidedRouteName = null;
292288

293289
// Send a 'pushRoute' platform message so the app handles it accordingly.
294-
if (EnginePlatformDispatcher.instance._onPlatformMessage != null) {
295-
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
296-
'flutter/navigation',
297-
const JSONMethodCodec().encodeMethodCall(
298-
MethodCall('pushRoute', newRouteName),
299-
),
300-
(_) {},
301-
);
302-
}
290+
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
291+
'flutter/navigation',
292+
const JSONMethodCodec().encodeMethodCall(
293+
MethodCall('pushRoute', newRouteName),
294+
),
295+
(_) {},
296+
);
303297
} else {
304298
// The user has pushed a new entry on top of our flutter entry. This could
305299
// happen when the user modifies the hash part of the url directly, for

0 commit comments

Comments
 (0)