这是indexloc提供的服务,不要输入任何密码
Skip to content

Change iOS device discovery from polling to long-running observation #58137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 1, 2020

Conversation

jmagman
Copy link
Member

@jmagman jmagman commented May 28, 2020

Description

For daemon iOS device polling, change periodic xcdevice list calls to a long-running xcdevice observe call.

Related Issues

Fixes #56826

Tests

  • xcdevice.observedDeviceEvents tests
  • start polling devices test
  • ItemListNotifier tests

Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I signed the [CLA].
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

  • No, no existing tests failed, so this is not a breaking change.
  • Yes, this is a breaking change. If not, delete the remainder of this section.

@jmagman jmagman added platform-ios iOS applications specifically tool Affects the "flutter" command-line tool. See also t: labels. t: xcode "xcodebuild" on iOS and general Xcode project management labels May 28, 2020
@jmagman jmagman self-assigned this May 28, 2020
Comment on lines 338 to 339
// Run in interactive mode (via script) to convince
// xcdevice it has a terminal attached and pipe stdout.
Copy link
Member Author

Choose a reason for hiding this comment

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

Timer _timer;

Future<List<Device>> pollingGetDevices({ Duration timeout });

void startPolling() {
Future<void> startPolling() async {
Copy link
Member Author

Choose a reason for hiding this comment

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

g3 PollingDeviceDiscovery subclasses don't override startPolling or stopPolling.

@jmagman jmagman force-pushed the observe-attaches branch 2 times, most recently from 6740b4a to 941b59c Compare May 28, 2020 23:58

@protected
@visibleForTesting
ItemListNotifier<Device> deviceNotifier;
Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed _items -> deviceNotifier

@jmagman jmagman requested review from jonahwilliams and zanderso May 29, 2020 00:00
@jmagman jmagman marked this pull request as ready for review May 29, 2020 00:00
}, onDone: () {
// If the xcdevice process is killed, restart it.
_logger.printTrace('xcdevice observe stopped, restarting');
startPolling();
Copy link
Contributor

Choose a reason for hiding this comment

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

So I'm understanding this correctly: since we're relying on a single long running process now, it needs to restart in case it goes down unexpectedly, otherwise IDEs wouldn't be able to discover new iOS devices without restarting - right?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's it.

_logger.printTrace('xcdevice observe stopped, restarting');

// If the xcdevice process is killed, give it a few seconds and restart it.
Timer(const Duration(seconds: 1), () {
Copy link
Contributor

Choose a reason for hiding this comment

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

What if the device discovery exits immediately on start up (something is broken). Will this keep scheduling work in a loop? Likewise if this is killed as part of tear down.

Copy link
Member Author

Choose a reason for hiding this comment

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

PollingDeviceDiscovery polling currently schedules a timer every 4 seconds to call device-specific discovery code, so that's the existing behavior. It depends what we want the behavior to be. If I killall xcdevice (exits 137), I would expect it to get rescheduled and the IDE not to need to be restarted. However if it just fails in some other way, rerunning it probably won't help? @zanderso What do you think?

Restarting after stopPolling is bad though...

Copy link
Contributor

Choose a reason for hiding this comment

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

Its a bit of a tricky situation. How common is it for this process to go down during an IDE session? It might be less risky to log a message and move on

Copy link
Member Author

Choose a reason for hiding this comment

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

I never saw it organically go down in my testing, but I also never saw my hard drive fill up with xcdevice caches described in #56826.

Good opportunity for metrics?

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, if we're not sure lets measure

Copy link
Member

Choose a reason for hiding this comment

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

It looks like close() on the StreamController for this Stream isn't called, so how does the 'onDone' callback get invoked?

Copy link
Member Author

Choose a reason for hiding this comment

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

It is now. See comment at #58137 (comment).

_logger.printTrace('xcdevice observe stopped, restarting');

// If the xcdevice process is killed, give it a few seconds and restart it.
Timer(const Duration(seconds: 1), () {
Copy link
Member

Choose a reason for hiding this comment

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

It looks like close() on the StreamController for this Stream isn't called, so how does the 'onDone' callback get invoked?

Comment on lines +245 to +252
void _setupDeviceIdentifierByEventStream() {
// _deviceIdentifierByEvent Should always be available for listeners
// in case polling needs to be stopped and restarted.
_deviceIdentifierByEvent = StreamController<Map<XCDeviceEvent, String>>.broadcast(
onListen: _startObservingTetheredIOSDevices,
onCancel: _stopObservingTetheredIOSDevices,
);
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This was the piece I was missing when I wasn't closing _deviceIdentifierByEvent on the last commit. I want polling to be able to be started, stopped, and re-started. Before, I was avoiding closing it so it could be re-listened to, but I guess it should be closed when no one is listening.

Really I want to be able to pause the subscription and resume it, but the pause() documentation says:

   * To avoid buffering events on a broadcast stream, it is better to
   * cancel this subscription, and start to listen again when events
   * are needed, if the intermediate events are not important.

'xcrun',
'xcdevice',
'observe',
'--both',
Copy link
Member Author

Choose a reason for hiding this comment

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

I also changed this to --both to reflect what I just did in https://github.com/flutter/flutter/pull/58257/files#diff-8d108d6a887a4f5b74f7c7d77003e795R97. Wireless devices aren't being sufaced yet, so if one attaches it will kick off an unnecessary fetch. Should be rare.

Copy link
Member

@zanderso zanderso left a comment

Choose a reason for hiding this comment

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

lgtm after addressing @jonahwilliams comments.

@jmagman jmagman force-pushed the observe-attaches branch from ff18b4d to 29bdefb Compare June 1, 2020 18:31
Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

LGTM

_items ??= ItemListNotifier<Device>();
return _items.onRemoved;
deviceNotifier ??= ItemListNotifier<Device>();
return deviceNotifier.onRemoved;
}

void dispose() => stopPolling();
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be async now?

super('iOS devices');

@override
void dispose() {
_observedDeviceEventsSubscription?.cancel();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this not call super.dispose()?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, if the super signature was async, this would just be await stopPolling()

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
platform-ios iOS applications specifically t: xcode "xcodebuild" on iOS and general Xcode project management tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

xcdevice is generating a dyld_shared_cache_arm64 recovered file every ~30 seconds while IDE open
6 participants