Skip to content

Commit

Permalink
If one method of finding Dart VM fails for CoreDevice, wait for the o…
Browse files Browse the repository at this point in the history
…ther method (flutter#139754)

For CoreDevices we use a combination of mDNS and device logs to find the Dart VM url. If mDNS fails first, it will cause the launch to fail even though the device logs may be able to find the url. So if one of the methods fails, wait for the other method before failing the launch.

Fixes flutter#139685.
  • Loading branch information
vashworth committed Dec 8, 2023
1 parent 0c0b77f commit 82bc9ca
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/flutter_tools/lib/src/ios/devices.dart
Expand Up @@ -680,6 +680,14 @@ class IOSDevice extends Device {
localUri = await Future.any(
<Future<Uri?>>[vmUrlFromMDns, vmUrlFromLogs]
);

// If the first future to return is null, wait for the other to complete.
if (localUri == null) {
final List<Uri?> vmUrls = await Future.wait(
<Future<Uri?>>[vmUrlFromMDns, vmUrlFromLogs]
);
localUri = vmUrls.where((Uri? vmUrl) => vmUrl != null).firstOrNull;
}
} else {
localUri = await vmServiceDiscovery?.uri;
// If the `ios-deploy` debugger loses connection before it finds the
Expand Down
Expand Up @@ -904,6 +904,68 @@ void main() {
}, overrides: <Type, Generator>{
MDnsVmServiceDiscovery: () => FakeMDnsVmServiceDiscovery(),
});

group('IOSDevice.startApp attaches in debug mode via device logging', () {
late FakeMDnsVmServiceDiscovery mdnsDiscovery;
setUp(() {
mdnsDiscovery = FakeMDnsVmServiceDiscovery(returnsNull: true);
});

testUsingContext('when mDNS fails', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.empty();

final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0');
final Directory bundleLocation = fileSystem.currentDirectory;
final IOSDevice device = setUpIOSDevice(
processManager: processManager,
fileSystem: fileSystem,
isCoreDevice: true,
coreDeviceControl: FakeIOSCoreDeviceControl(),
xcodeDebug: FakeXcodeDebug(
expectedProject: XcodeDebugProject(
scheme: 'Runner',
xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'),
xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'),
hostAppProjectName: 'Runner',
),
expectedDeviceId: '123',
expectedLaunchArguments: <String>['--enable-dart-profiling'],
expectedBundlePath: bundleLocation.path,
)
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
uncompressedBundle: bundleLocation,
applicationPackage: bundleLocation,
);
final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();

device.portForwarder = const NoOpDevicePortForwarder();
device.setLogReader(iosApp, deviceLogReader);

unawaited(mdnsDiscovery.completer.future.whenComplete(() {
// Start writing messages to the log reader.
Timer.run(() {
deviceLogReader.addLine('Foo');
deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456');
});
}));

final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
);

expect(launchResult.started, true);
expect(launchResult.hasVmService, true);
expect(await device.stopApp(iosApp), true);
}, overrides: <Type, Generator>{
MDnsVmServiceDiscovery: () => mdnsDiscovery,
});
});
});
});
}
Expand Down Expand Up @@ -974,6 +1036,10 @@ class FakeDevicePortForwarder extends Fake implements DevicePortForwarder {
}

class FakeMDnsVmServiceDiscovery extends Fake implements MDnsVmServiceDiscovery {
FakeMDnsVmServiceDiscovery({this.returnsNull = false});
bool returnsNull;

Completer<void> completer = Completer<void>();
@override
Future<Uri?> getVMServiceUriForLaunch(
String applicationId,
Expand All @@ -984,6 +1050,11 @@ class FakeMDnsVmServiceDiscovery extends Fake implements MDnsVmServiceDiscovery
bool useDeviceIPAsHost = false,
Duration timeout = Duration.zero,
}) async {
completer.complete();
if (returnsNull) {
return null;
}

return Uri.tryParse('http://0.0.0.0:1234');
}
}
Expand Down

0 comments on commit 82bc9ca

Please sign in to comment.