From 82bc9ca3273b70996910bcfd68b4841ec4284b23 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:39:08 -0600 Subject: [PATCH] If one method of finding Dart VM fails for CoreDevice, wait for the other method (#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 https://github.com/flutter/flutter/issues/139685. --- .../flutter_tools/lib/src/ios/devices.dart | 8 +++ .../ios/ios_device_start_prebuilt_test.dart | 71 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 52f586390a..394f5a39a9 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -680,6 +680,14 @@ class IOSDevice extends Device { localUri = await Future.any( >[vmUrlFromMDns, vmUrlFromLogs] ); + + // If the first future to return is null, wait for the other to complete. + if (localUri == null) { + final List vmUrls = await Future.wait( + >[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 diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 117888a844..0e03fb9329 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -904,6 +904,68 @@ void main() { }, overrides: { 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: ['--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: {}, + ); + + expect(launchResult.started, true); + expect(launchResult.hasVmService, true); + expect(await device.stopApp(iosApp), true); + }, overrides: { + MDnsVmServiceDiscovery: () => mdnsDiscovery, + }); + }); }); }); } @@ -974,6 +1036,10 @@ class FakeDevicePortForwarder extends Fake implements DevicePortForwarder { } class FakeMDnsVmServiceDiscovery extends Fake implements MDnsVmServiceDiscovery { + FakeMDnsVmServiceDiscovery({this.returnsNull = false}); + bool returnsNull; + + Completer completer = Completer(); @override Future getVMServiceUriForLaunch( String applicationId, @@ -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'); } }