Skip to content

Commit

Permalink
createPerformanceModeRequest returns a PerformanceModeRequestHandle
Browse files Browse the repository at this point in the history
  • Loading branch information
iskakaushik committed Aug 31, 2022
1 parent 5042ced commit 327c3ec
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 37 deletions.
54 changes: 40 additions & 14 deletions packages/flutter/lib/src/scheduler/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,33 @@ enum SchedulerPhase {
postFrameCallbacks,
}

/// This callback invoked when a request for [DartPerformanceMode] is disposed.
///
/// See: [PerformanceModeRequestHandle].
typedef PerformanceModeCleaupCallback = void Function();

/// An opaque handle that keeps a request for [DartPerformanceMode] active until
/// disposed.
///
/// To create a [PerformanceModeHandle], use `createPerformanceModeRequest`. The
/// component that makes the request is responsible for disposing the handle.
class PerformanceModeRequestHandle {
PerformanceModeRequestHandle._(PerformanceModeCleaupCallback this._cleanup);

PerformanceModeCleaupCallback? _cleanup;

/// Call this method to signal to [SchedulerBinding] that a request for a [DartPerformanceMode]
/// is no longer needed.
///
/// This method must only be called once per object.
void dispose() {
assert(_cleanup != null);
_cleanup!();
_cleanup = null;
}

}

/// Scheduler for running the following:
///
/// * _Transient callbacks_, triggered by the system's
Expand Down Expand Up @@ -1098,32 +1125,31 @@ mixin SchedulerBinding on BindingBase {
}
}

final Map<dynamic, DartPerformanceMode> _performanceModes = <Object, DartPerformanceMode>{};
final Map<Object, DartPerformanceMode> _performanceModes = <Object, DartPerformanceMode>{};

/// Request a specific [DartPerformanceMode]. `requestor` is the handle to
/// component making the request, typically the component itself. Returns
/// `true` is the request was successfully made to the engine, `false` otherwise.
/// Even if the result is `true`, the engine may choose to ignore the request or
/// the performance mode may not be guaranteed to be the one requested.
/// Request a specific [DartPerformanceMode].
///
/// If conflicting requests are made, only the first request will be honored.
bool createPerformanceModeRequest(Object requestor, DartPerformanceMode mode) {
/// Requestor passes a handle (`requestor`) when making the request, this is typically
/// the component itself. Returns `null` if the request was not successful due to
/// conflicting performance mode requests. Requestor is responsible for calling
/// [PerformanceModeRequestHandle.dispose] when it no longer requires the performance mode.
PerformanceModeRequestHandle? createPerformanceModeRequest(Object requestor, DartPerformanceMode mode) {
if (_performanceModes.isNotEmpty) {
final DartPerformanceMode oldRequest = _performanceModes.entries.first.value;
if (oldRequest != mode) {
return false;
return null;
}
}
_performanceModes[requestor] = mode;
PlatformDispatcher.instance.requestDartPerformanceMode(mode);
return true;
return PerformanceModeRequestHandle._(() => _disposePerformanceModeRequest(requestor));
}

/// Remove a request for a specific [DartPerformanceMode]. `requestor` is the
/// handle to component making the request, typically the component itself. If
/// all the pending requests have been disposed, the engine will revert to the
/// Remove a request for a specific [DartPerformanceMode].
///
/// If all the pending requests have been disposed, the engine will revert to the
/// [DartPerformanceMode.balanced] performance mode.
void disposePerformanceModeRequest(Object requestor) {
void _disposePerformanceModeRequest(Object requestor) {
_performanceModes.remove(requestor);
if (_performanceModes.isEmpty) {
PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.balanced);
Expand Down
13 changes: 11 additions & 2 deletions packages/flutter/lib/src/widgets/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
Future<T?> get completed => _transitionCompleter.future;
final Completer<T?> _transitionCompleter = Completer<T?>();

/// Handle to the performance mode request.
///
/// When the route is installed, the performance mode is requested, and this is
/// then disposed when the route is disposed. Requesting [DartPerformanceMode.latency]
/// indicated to the engine that the transition is latency sensitive and to delay
/// non-essential work while this handle is active.
PerformanceModeRequestHandle? _performanceModeRequestHandle;

/// {@template flutter.widgets.TransitionRoute.transitionDuration}
/// The duration the transition going forwards.
///
Expand Down Expand Up @@ -249,7 +257,8 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
_animation = createAnimation()
..addStatusListener(_handleStatusChanged);
assert(_animation != null, '$runtimeType.createAnimation() returned null.');
SchedulerBinding.instance.createPerformanceModeRequest(this, ui.DartPerformanceMode.latency);
_performanceModeRequestHandle =
SchedulerBinding.instance.createPerformanceModeRequest(this, ui.DartPerformanceMode.latency);
super.install();
if (_animation!.isCompleted && overlayEntries.isNotEmpty) {
overlayEntries.first.opaque = opaque;
Expand Down Expand Up @@ -465,7 +474,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
@override
void dispose() {
assert(!_transitionCompleter.isCompleted, 'Cannot dispose a $runtimeType twice.');
SchedulerBinding.instance.disposePerformanceModeRequest(this);
_performanceModeRequestHandle?.dispose();
_animation?.removeStatusListener(_handleStatusChanged);
if (willDisposeAnimationController) {
_controller?.dispose();
Expand Down
40 changes: 19 additions & 21 deletions packages/flutter/test/scheduler/performance_mode_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import 'dart:ui';

import 'package:flutter/scheduler.dart';
import 'package:flutter/src/foundation/constants.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

Expand All @@ -19,45 +18,44 @@ void main() {

test('PerformanceModeHandler make one request', () async {
const int handle1 = 1;
final bool success = binding.createPerformanceModeRequest(handle1, DartPerformanceMode.latency);
expect(success, isTrue);
final PerformanceModeRequestHandle? requestHandle = binding.createPerformanceModeRequest(handle1, DartPerformanceMode.latency);
expect(requestHandle, isNotNull);
expect(binding.getRequestedPerformanceMode(), equals(DartPerformanceMode.latency));

binding.disposePerformanceModeRequest(handle1);
requestHandle?.dispose();
expect(binding.getRequestedPerformanceMode(), isNull);
}, skip: kIsWeb); // [intended] performance mode handling is not supported on web.
});

test('PerformanceModeHandler make conflicting requests', () async {
const int handle1 = 1;
final bool success1 = binding.createPerformanceModeRequest(handle1, DartPerformanceMode.latency);
expect(success1, isTrue);
final PerformanceModeRequestHandle? requestHandle1 = binding.createPerformanceModeRequest(handle1, DartPerformanceMode.latency);
expect(requestHandle1, isNotNull);

const int handle2 = 2;
final bool success2 = binding.createPerformanceModeRequest(handle2, DartPerformanceMode.throughput);
expect(success2, isFalse);
final PerformanceModeRequestHandle? requestHandle2 = binding.createPerformanceModeRequest(handle2, DartPerformanceMode.throughput);
expect(requestHandle2, isNull);

expect(binding.getRequestedPerformanceMode(), equals(DartPerformanceMode.latency));

binding.disposePerformanceModeRequest(handle1);
requestHandle1?.dispose();
expect(binding.getRequestedPerformanceMode(), isNull);
}, skip: kIsWeb); // [intended] performance mode handling is not supported on web.
});

test('PerformanceModeHandler revert only after last requestor disposed', () async {
test('PerformanceModeHandler revert only after last requestor disposed',
() async {
const int handle1 = 1;
final bool success1 = binding.createPerformanceModeRequest(handle1, DartPerformanceMode.latency);
expect(success1, isTrue);
final PerformanceModeRequestHandle? requestHandle1 = binding.createPerformanceModeRequest(handle1, DartPerformanceMode.latency);
expect(requestHandle1, isNotNull);

expect(binding.getRequestedPerformanceMode(), equals(DartPerformanceMode.latency));

const int handle2 = 2;
final bool success2 = binding.createPerformanceModeRequest(handle2, DartPerformanceMode.latency);
expect(success2, isTrue);
final PerformanceModeRequestHandle? requestHandle2 = binding.createPerformanceModeRequest(handle2, DartPerformanceMode.latency);
expect(requestHandle2, isNotNull);

expect(binding.getRequestedPerformanceMode(), equals(DartPerformanceMode.latency));
binding.disposePerformanceModeRequest(handle1);
requestHandle1?.dispose();
expect(binding.getRequestedPerformanceMode(), equals(DartPerformanceMode.latency));
binding.disposePerformanceModeRequest(handle2);
requestHandle2?.dispose();
expect(binding.getRequestedPerformanceMode(), isNull);
}, skip: kIsWeb); // [intended] performance mode handling is not supported on web.

});
}

0 comments on commit 327c3ec

Please sign in to comment.