Skip to content

Conversation

@yaakovschectman
Copy link
Contributor

Send a platform message to the engine when the ServiceBinding is registered. Framework side of flutter/engine#41733

Addresses #126033

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@yaakovschectman yaakovschectman added platform-windows Building on or for Windows specifically a: desktop Running on desktop labels May 4, 2023
@yaakovschectman yaakovschectman self-assigned this May 4, 2023
@flutter-dashboard flutter-dashboard bot added the framework flutter/packages/flutter repository. See also f: labels. label May 4, 2023
@yaakovschectman
Copy link
Contributor Author

I think this will need a test, but as it tests the initialization of the binding, I will need to determine exactly how to write it.

Copy link
Contributor

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, but yes, does need a test.

@yaakovschectman
Copy link
Contributor Author

@gspencergoog How would we be able to test that the framework sends a certain platform message to the engine upon initializing the ServiceBinding? Do we have a way to mock engine-side message handling from within framework tests? It looks like we only mock the framework-side.

@gspencergoog
Copy link
Contributor

It could be an integration test that has a plugin that registers to receive those platform messages, maybe. That's a lot to set up, though.

Maybe just verifying that the framework tries to send the message is enough: you could modify the TestPlatformDispatcher in the test binding to log the messages sent and verify them , maybe?

_platformDispatcher.sendPlatformMessage(name, data, callback);

@yaakovschectman
Copy link
Contributor Author

@gspencergoog I am unclear on what TestPlatformDispatcher you're referring to with regards to this test binding (where ServiceBinding is tested):

class TestBinding extends BindingBase with SchedulerBinding, ServicesBinding {

@gspencergoog
Copy link
Contributor

Yeah, you're right, it's not available at that layer. Maybe it needs to be a test run with the tests for WidgetsBinding.

@yaakovschectman
Copy link
Contributor Author

Are you referring to

?
What is available at that layer that seems useful to this prospective test?

@gspencergoog
Copy link
Contributor

The TestWidgetsFlutterBinding uses a TestPlatformDispatcher, which includes an implementation of sendPlatformMessage that I thought might be used to watch messages sent to the engine.

Unfortunately, I don't think that will work because we don't use the injected instance when we send messages to the engine:

ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {

@yaakovschectman yaakovschectman marked this pull request as ready for review May 4, 2023 18:51
SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object));
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
SystemChannels.platform.setMethodCallHandler(_handlePlatformMessage);
_registerBindingWithEngine();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to leverage this as a generic "the ServicesBinding is fully initialized" message in the future. Should we make this be the last step in initInstances?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, it seems weird to require an app to send a System.registerBinding if it wants to listen to application lifecycle events. For example, a dart:ui app may want to listen to app lifecycle events without using ServicesBinding. Perhaps we should use a different name like System.enableApplicationLifecycle?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's that weird. Having something that happens after the binding is initialized seems like something you might want to use for other things besides enabling application lifecycle events too, so it doesn't seem too odd to have a "we're done initializing the binding" message to start things off. It does increase the boilerplate for such an app, however, which is too bad, but I think anyone building an app at that level is expecting some level of boilerplate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, I'm fine with the boilerplate. I disliked the previous message name System.registerBinding for a raw dart:ui app.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about initializationComplete? Is that really true at the point the message is sent?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be fine with System.initializationComplete too, but what would be the best way to document its implications? (Namely that the app now needs to respond to System.requestAppExit)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for now that is all it implies: that it's ready to respond to System.requestAppExit requests, but to the embedding, it also represents the point at which the framework's bindings are registered, so it can feel free to communicate with the bindings. I also wonder if there are other parts of the engine that assume the binding will respond to a method call which would benefit from waiting until the binding is ready?

@yaakovschectman
Copy link
Contributor Author

What are your thoughts on adding to the windows_startup_test integration test to ensure that the platform message is sent by binding initialization?

@gspencergoog
Copy link
Contributor

What are your thoughts on adding to the windows_startup_test integration test to ensure that the platform message is sent by binding initialization?

That sounds reasonable.

@yaakovschectman
Copy link
Contributor Author

I'm running into some difficulty setting the handler for the platform message on the C++ side, because it has a reference to the standard method codec instance, but not the JSON method codec, which is what the platform channel uses, and I do not currently see a way to ensure the platform channel message is sent without registering a handler that responds to it in some way.

/// Alert the engine that the binding is registered. This instructs the engine to
/// register its top level window handler on Windows.
Future<void> enableApplicationLifecycle() async {
SystemChannels.platform.invokeMethod('System.enableApplicationLifecycle');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loïc and I discussed making this "System.initializationComplete" so that this wouldn't be so tied to app lifecycle, but could be used as a more generic signal. That's what I currently have in my implementations for macOS and Linux.

@yaakovschectman
Copy link
Contributor Author

I've reworked the test. Instead of using the integration test, we are now using a unit test. initializationComplete is now protected but exposed by TestWidgetsFlutterBinding.

);
}

/// Expose this method for testing.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exposes the method for every test (not only ours, but also for all our customers). Since there should never be a reason for anyone to call this, we shouldn't do that. You'll have to create a custom binding subclass that's only used for your test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As only one binding can be active at a time, to my knowledge, I've put this test into a new file so that the custom binding it uses can be used exclusively by this test.

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@yaakovschectman yaakovschectman merged commit 130944e into flutter:master May 16, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 16, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 16, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 16, 2023
auto-submit bot pushed a commit to flutter/engine that referenced this pull request May 16, 2023
…mework (#41782)

## Description

Similar to #41733 and #41753 this causes the linux embedding to wait until it hears that the scheduler binding has registered itself before proceeding to send termination requests to the framework.

This allows applications that don't use the framework (just use `dart:ui` directly) to exit automatically when the last window is closed.  Without this change, the app does not exit when the window is closed.

Depends on framework PR flutter/flutter#126075 landing first.

## Related PRs
 - #41733
 - #41753

## Related Issues
 - flutter/flutter#126033.

## Tests
 - Added a test to make sure that it doesn't send a termination request if the binding hasn't notified that it is ready yet.
gspencergoog added a commit to flutter/engine that referenced this pull request May 16, 2023
…mework (#41753)

Similar to #41733 and
#41782, this causes the macos
embedding to wait until it hears that the scheduler binding has
registered itself before proceeding to send termination requests to the
framework.

This allows applications that don't use the framework (just use
`dart:ui` directly) to exit automatically when the last window is
closed. Without this change, the last window closes, but the app does
not exit.

Depends on framework PR flutter/flutter#126075
landing first.
CaseyHillers pushed a commit to CaseyHillers/flutter that referenced this pull request May 24, 2023
Send a platform message to the engine when the `ServiceBinding` is
registered. Framework side of
flutter/engine#41733

Addresses flutter#126033

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat

---------

Co-authored-by: Greg Spencer <[email protected]>
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 16, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: desktop Running on desktop framework flutter/packages/flutter repository. See also f: labels. platform-windows Building on or for Windows specifically

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants