Add profilePlatformChannels service extension (#136051)

We will expose this from a button in DevTools.
https://github.com/flutter/devtools/issues/6166
This commit is contained in:
Kenzie Davisson 2023-10-11 10:45:06 -07:00 committed by GitHub
parent 6ff02dbc83
commit a047358c5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 4 deletions

View file

@ -12,8 +12,10 @@ import 'package:flutter/scheduler.dart';
import 'asset_bundle.dart';
import 'binary_messenger.dart';
import 'debug.dart';
import 'hardware_keyboard.dart';
import 'message_codec.dart';
import 'platform_channel.dart';
import 'restoration.dart';
import 'service_extensions.dart';
import 'system_channels.dart';
@ -224,6 +226,16 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
);
return true;
}());
if (!kReleaseMode) {
registerBoolServiceExtension(
name: ServicesServiceExtensions.profilePlatformChannels.name,
getter: () async => debugProfilePlatformChannels,
setter: (bool value) async {
debugProfilePlatformChannels = value;
},
);
}
}
/// Called in response to the `ext.flutter.evict` service extension.

View file

@ -41,3 +41,17 @@ bool debugAssertAllServicesVarsUnset(String reason) {
}());
return true;
}
/// Controls whether platform channel usage can be debugged in non-release mode.
///
/// This value is modified by calls to the
/// [ServicesServiceExtensions.profilePlatformChannels] service extension.
///
/// See also:
///
/// * [shouldProfilePlatformChannels], which checks both
/// [kProfilePlatformChannels] and [debugProfilePlatformChannels] for the
/// current run mode.
/// * [kProfilePlatformChannels], which determines whether platform channel
/// usage can be debugged in release mode.
bool debugProfilePlatformChannels = false;

View file

@ -12,6 +12,7 @@ import '_background_isolate_binary_messenger_io.dart'
import 'binary_messenger.dart';
import 'binding.dart';
import 'debug.dart';
import 'message_codec.dart';
import 'message_codecs.dart';
@ -32,6 +33,17 @@ export 'message_codec.dart' show MessageCodec, MethodCall, MethodCodec;
/// The statistics include the total bytes transmitted and the average number of
/// bytes per invocation in the last quantum. "Up" means in the direction of
/// Flutter to the host platform, "down" is the host platform to flutter.
bool get shouldProfilePlatformChannels => kProfilePlatformChannels || (!kReleaseMode && debugProfilePlatformChannels);
/// Controls whether platform channel usage can be debugged in release mode.
///
/// See also:
///
/// * [shouldProfilePlatformChannels], which checks both
/// [kProfilePlatformChannels] and [debugProfilePlatformChannels] for the
/// current run mode.
/// * [debugProfilePlatformChannels], which determines whether platform
/// channel usage can be debugged in non-release mode.
const bool kProfilePlatformChannels = false;
bool _profilePlatformChannelsIsRunning = false;
@ -190,7 +202,7 @@ class BasicMessageChannel<T> {
/// [BackgroundIsolateBinaryMessenger.ensureInitialized].
BinaryMessenger get binaryMessenger {
final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger();
return kProfilePlatformChannels
return shouldProfilePlatformChannels
? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
// ignore: no_runtimetype_tostring
result, runtimeType.toString(), codec.runtimeType.toString())
@ -279,7 +291,7 @@ class MethodChannel {
/// [BackgroundIsolateBinaryMessenger.ensureInitialized].
BinaryMessenger get binaryMessenger {
final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger();
return kProfilePlatformChannels
return shouldProfilePlatformChannels
? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
// ignore: no_runtimetype_tostring
result, runtimeType.toString(), codec.runtimeType.toString())
@ -310,7 +322,7 @@ class MethodChannel {
Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async {
final ByteData input = codec.encodeMethodCall(MethodCall(method, arguments));
final ByteData? result =
kProfilePlatformChannels ?
shouldProfilePlatformChannels ?
await (binaryMessenger as _ProfiledBinaryMessenger).sendWithPostfix(name, '#$method', input) :
await binaryMessenger.send(name, input);
if (result == null) {

View file

@ -11,6 +11,19 @@
/// The String value for each of these extension names should be accessed by
/// calling the `.name` property on the enum value.
enum ServicesServiceExtensions {
/// Name of service extension that, when called, will toggle whether
/// statistics about the usage of Platform Channels will be printed out
/// periodically to the console and Timeline events will show the time between
/// sending and receiving a message (encoding and decoding time excluded).
///
/// See also:
///
/// * [debugProfilePlatformChannels], which is the flag that this service
/// extension exposes.
/// * [ServicesBinding.initServiceExtensions], where the service extension is
/// registered.
profilePlatformChannels,
/// Name of service extension that, when called, will evict an image from the
/// rootBundle cache and cause the image cache to be cleared.
///

View file

@ -183,7 +183,7 @@ void main() {
// framework, excluding any that are for the widget inspector (see
// widget_inspector_test.dart for tests of the ext.flutter.inspector service
// extensions). Any test counted here must be tested in this file!
const int serviceExtensionCount = 29;
const int serviceExtensionCount = 30;
expect(binding.extensions.length, serviceExtensionCount + widgetInspectorExtensionCount - disabledExtensions);
expect(testedExtensions, hasLength(serviceExtensionCount));
@ -597,6 +597,34 @@ void main() {
testedExtensions.add(RenderingServiceExtensions.profileRenderObjectLayouts.name);
});
test('Service extensions - profilePlatformChannels', () async {
Map<String, dynamic> result;
expect(debugProfilePlatformChannels, false);
result = await binding.testExtension(ServicesServiceExtensions.profilePlatformChannels.name, <String, String>{});
expect(result, <String, String>{'enabled': 'false'});
expect(debugProfilePlatformChannels, false);
result = await binding.testExtension(ServicesServiceExtensions.profilePlatformChannels.name, <String, String>{'enabled': 'true'});
expect(result, <String, String>{'enabled': 'true'});
expect(debugProfilePlatformChannels, true);
result = await binding.testExtension(ServicesServiceExtensions.profilePlatformChannels.name, <String, String>{});
expect(result, <String, String>{'enabled': 'true'});
expect(debugProfilePlatformChannels, true);
result = await binding.testExtension(ServicesServiceExtensions.profilePlatformChannels.name, <String, String>{'enabled': 'false'});
expect(result, <String, String>{'enabled': 'false'});
expect(debugProfilePlatformChannels, false);
result = await binding.testExtension(ServicesServiceExtensions.profilePlatformChannels.name, <String, String>{});
expect(result, <String, String>{'enabled': 'false'});
expect(debugProfilePlatformChannels, false);
testedExtensions.add(ServicesServiceExtensions.profilePlatformChannels.name);
});
test('Service extensions - evict', () async {
Map<String, dynamic> result;
bool completed;