3
3
// found in the LICENSE file.
4
4
5
5
import 'dart:async' ;
6
+ import 'dart:developer' ;
7
+ import 'dart:ui' show PlatformMessageResponseCallback;
6
8
7
9
import 'package:flutter/foundation.dart' ;
8
10
9
11
import 'binary_messenger.dart' ;
10
12
import 'binding.dart' ;
13
+ import 'debug.dart' show debugProfilePlatformChannels;
11
14
import 'message_codec.dart' ;
12
15
import 'message_codecs.dart' ;
13
16
17
+ bool _debugProfilePlatformChannelsIsRunning = false ;
18
+ const Duration _debugProfilePlatformChannelsRate = Duration (seconds: 1 );
19
+ final Expando <BinaryMessenger > _debugBinaryMessengers = Expando <BinaryMessenger >();
20
+
21
+ class _ProfiledBinaryMessenger implements BinaryMessenger {
22
+ const _ProfiledBinaryMessenger (this .proxy, this .channelTypeName, this .codecTypeName);
23
+ final BinaryMessenger proxy;
24
+ final String channelTypeName;
25
+ final String codecTypeName;
26
+
27
+ @override
28
+ Future <void > handlePlatformMessage (String channel, ByteData ? data, PlatformMessageResponseCallback ? callback) {
29
+ return proxy.handlePlatformMessage (channel, data, callback);
30
+ }
31
+
32
+ Future <ByteData ?>? sendWithPostfix (String channel, String postfix, ByteData ? message) async {
33
+ final TimelineTask task = TimelineTask ();
34
+ _debugRecordUpStream (channelTypeName, '$channel $postfix ' , codecTypeName, message);
35
+ task.start ('Platform Channel send $channel $postfix ' );
36
+ final ByteData ? result;
37
+ try {
38
+ result = await proxy.send (channel, message);
39
+ } finally {
40
+ task.finish ();
41
+ }
42
+ _debugRecordDownStream (channelTypeName, '$channel $postfix ' , codecTypeName, result);
43
+ return result;
44
+ }
45
+
46
+ @override
47
+ Future <ByteData ?>? send (String channel, ByteData ? message) =>
48
+ sendWithPostfix (channel, '' , message);
49
+
50
+ @override
51
+ void setMessageHandler (String channel, MessageHandler ? handler) {
52
+ proxy.setMessageHandler (channel, handler);
53
+ }
54
+ }
55
+
56
+ class _PlatformChannelStats {
57
+ _PlatformChannelStats (this .channel, this .codec, this .type);
58
+
59
+ final String channel;
60
+ final String codec;
61
+ final String type;
62
+
63
+ int _upCount = 0 ;
64
+ int _upBytes = 0 ;
65
+ int get upBytes => _upBytes;
66
+ void addUpStream (int bytes) {
67
+ _upCount += 1 ;
68
+ _upBytes += bytes;
69
+ }
70
+
71
+ int _downCount = 0 ;
72
+ int _downBytes = 0 ;
73
+ int get downBytes => _downBytes;
74
+ void addDownStream (int bytes) {
75
+ _downCount += 1 ;
76
+ _downBytes += bytes;
77
+ }
78
+
79
+ double get averageUpPayload => _upBytes / _upCount;
80
+ double get averageDownPayload => _downBytes / _downCount;
81
+ }
82
+
83
+ final Map <String , _PlatformChannelStats > _debugProfilePlatformChannelsStats = < String , _PlatformChannelStats > {};
84
+
85
+ Future <void > _debugLaunchProfilePlatformChannels () async {
86
+ if (! _debugProfilePlatformChannelsIsRunning) {
87
+ _debugProfilePlatformChannelsIsRunning = true ;
88
+ await Future <dynamic >.delayed (_debugProfilePlatformChannelsRate);
89
+ _debugProfilePlatformChannelsIsRunning = false ;
90
+ final StringBuffer log = StringBuffer ();
91
+ log.writeln ('Platform Channel Stats:' );
92
+ final List <_PlatformChannelStats > allStats =
93
+ _debugProfilePlatformChannelsStats.values.toList ();
94
+ // Sort highest combined bandwidth first.
95
+ allStats.sort ((_PlatformChannelStats x, _PlatformChannelStats y) =>
96
+ (y.upBytes + y.downBytes) - (x.upBytes + x.downBytes));
97
+ for (final _PlatformChannelStats stats in allStats) {
98
+ log.writeln (
99
+ ' (name:"${stats .channel }" type:"${stats .type }" codec:"${stats .codec }" upBytes:${stats .upBytes } upBytes_avg:${stats .averageUpPayload .toStringAsFixed (1 )} downBytes:${stats .downBytes } downBytes_avg:${stats .averageDownPayload .toStringAsFixed (1 )})' );
100
+ }
101
+ debugPrint (log.toString ());
102
+ _debugProfilePlatformChannelsStats.clear ();
103
+ }
104
+ }
105
+
106
+ void _debugRecordUpStream (String channelTypeName, String name,
107
+ String codecTypeName, ByteData ? bytes) {
108
+ final _PlatformChannelStats stats =
109
+ _debugProfilePlatformChannelsStats[name] ?? =
110
+ _PlatformChannelStats (name, codecTypeName, channelTypeName);
111
+ stats.addUpStream (bytes? .lengthInBytes ?? 0 );
112
+ _debugLaunchProfilePlatformChannels ();
113
+ }
114
+
115
+ void _debugRecordDownStream (String channelTypeName, String name,
116
+ String codecTypeName, ByteData ? bytes) {
117
+ final _PlatformChannelStats stats =
118
+ _debugProfilePlatformChannelsStats[name] ?? =
119
+ _PlatformChannelStats (name, codecTypeName, channelTypeName);
120
+ stats.addDownStream (bytes? .lengthInBytes ?? 0 );
121
+ _debugLaunchProfilePlatformChannels ();
122
+ }
123
+
14
124
/// A named channel for communicating with platform plugins using asynchronous
15
125
/// message passing.
16
126
///
@@ -49,7 +159,15 @@ class BasicMessageChannel<T> {
49
159
final MessageCodec <T > codec;
50
160
51
161
/// The messenger which sends the bytes for this channel, not null.
52
- BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding .instance.defaultBinaryMessenger;
162
+ BinaryMessenger get binaryMessenger {
163
+ final BinaryMessenger result =
164
+ _binaryMessenger ?? ServicesBinding .instance.defaultBinaryMessenger;
165
+ return ! kReleaseMode && debugProfilePlatformChannels
166
+ ? _debugBinaryMessengers[this ] ?? = _ProfiledBinaryMessenger (
167
+ // ignore: no_runtimetype_tostring
168
+ result, runtimeType.toString (), codec.runtimeType.toString ())
169
+ : result;
170
+ }
53
171
final BinaryMessenger ? _binaryMessenger;
54
172
55
173
/// Sends the specified [message] to the platform plugins on this channel.
@@ -129,7 +247,15 @@ class MethodChannel {
129
247
/// The messenger used by this channel to send platform messages.
130
248
///
131
249
/// The messenger may not be null.
132
- BinaryMessenger get binaryMessenger => _binaryMessenger ?? ServicesBinding .instance.defaultBinaryMessenger;
250
+ BinaryMessenger get binaryMessenger {
251
+ final BinaryMessenger result =
252
+ _binaryMessenger ?? ServicesBinding .instance.defaultBinaryMessenger;
253
+ return ! kReleaseMode && debugProfilePlatformChannels
254
+ ? _debugBinaryMessengers[this ] ?? = _ProfiledBinaryMessenger (
255
+ // ignore: no_runtimetype_tostring
256
+ result, runtimeType.toString (), codec.runtimeType.toString ())
257
+ : result;
258
+ }
133
259
final BinaryMessenger ? _binaryMessenger;
134
260
135
261
/// Backend implementation of [invokeMethod] .
@@ -154,10 +280,11 @@ class MethodChannel {
154
280
@optionalTypeArgs
155
281
Future <T ?> _invokeMethod <T >(String method, { required bool missingOk, dynamic arguments }) async {
156
282
assert (method != null );
157
- final ByteData ? result = await binaryMessenger.send (
158
- name,
159
- codec.encodeMethodCall (MethodCall (method, arguments)),
160
- );
283
+ final ByteData input = codec.encodeMethodCall (MethodCall (method, arguments));
284
+ final ByteData ? result =
285
+ ! kReleaseMode && debugProfilePlatformChannels ?
286
+ await (binaryMessenger as _ProfiledBinaryMessenger ).sendWithPostfix (name, '#$method ' , input) :
287
+ await binaryMessenger.send (name, input);
161
288
if (result == null ) {
162
289
if (missingOk) {
163
290
return null ;
0 commit comments