Unverified Commit 3e0d2741 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Detach debugger when VM connection fails on iOS (#68046)

parent 4dffc851
...@@ -468,10 +468,12 @@ class IOSDevice extends Device { ...@@ -468,10 +468,12 @@ class IOSDevice extends Device {
packageName: FlutterProject.current().manifest.appName, packageName: FlutterProject.current().manifest.appName,
); );
if (localUri == null) { if (localUri == null) {
iosDeployDebugger?.detach();
return LaunchResult.failed(); return LaunchResult.failed();
} }
return LaunchResult.succeeded(observatoryUri: localUri); return LaunchResult.succeeded(observatoryUri: localUri);
} on ProcessException catch (e) { } on ProcessException catch (e) {
iosDeployDebugger?.detach();
_logger.printError(e.message); _logger.printError(e.message);
return LaunchResult.failed(); return LaunchResult.failed();
} finally { } finally {
......
...@@ -25,6 +25,9 @@ const String noProvisioningProfileErrorTwo = 'Error 0xe8000067'; ...@@ -25,6 +25,9 @@ const String noProvisioningProfileErrorTwo = 'Error 0xe8000067';
const String deviceLockedError = 'e80000e2'; const String deviceLockedError = 'e80000e2';
const String unknownAppLaunchError = 'Error 0xe8000022'; const String unknownAppLaunchError = 'Error 0xe8000022';
// Another debugger instance is already attached?
const String processLaunchFailedError = 'error: process launch failed';
class IOSDeploy { class IOSDeploy {
IOSDeploy({ IOSDeploy({
@required Artifacts artifacts, @required Artifacts artifacts,
...@@ -412,6 +415,13 @@ Error launching app. Try launching from within Xcode via: ...@@ -412,6 +415,13 @@ Error launching app. Try launching from within Xcode via:
open ios/Runner.xcworkspace open ios/Runner.xcworkspace
Your Xcode version may be too old for your iOS version. Your Xcode version may be too old for your iOS version.
═══════════════════════════════════════════════════════════════════════════════════''',
emphasis: true);
} else if (stdout.contains(processLaunchFailedError)) {
logger.printError('''
═══════════════════════════════════════════════════════════════════════════════════
Could not attach the debugger.
Try uninstalling the app from your device and retrying.
═══════════════════════════════════════════════════════════════════════════════════''', ═══════════════════════════════════════════════════════════════════════════════════''',
emphasis: true); emphasis: true);
} }
......
...@@ -210,6 +210,21 @@ void main () { ...@@ -210,6 +210,21 @@ void main () {
await iosDeployDebugger.launchAndAttach(); await iosDeployDebugger.launchAndAttach();
expect(logger.errorText, contains('Try launching from within Xcode')); expect(logger.errorText, contains('Try launching from within Xcode'));
}); });
testWithoutContext('cannot attach', () async {
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['ios-deploy'],
stdout: 'error: process launch failed: timed out waiting for app to launch',
),
]);
final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
processManager: processManager,
logger: logger,
);
await iosDeployDebugger.launchAndAttach();
expect(logger.errorText, contains('Could not attach the debugger'));
});
}); });
testWithoutContext('detach', () async { testWithoutContext('detach', () async {
......
...@@ -411,6 +411,62 @@ void main() { ...@@ -411,6 +411,62 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => MockUsage(),
}); });
// Still uses context for analytics.
testUsingContext(
'IOSDevice.startApp detaches lldb when VM service connection fails',
() async {
final FileSystem fileSystem = MemoryFileSystem.test();
final MockIOSDeploy mockIOSDeploy = MockIOSDeploy();
final MockIOSDeployDebugger mockIOSDeployDebugger = MockIOSDeployDebugger();
when(mockIOSDeploy.prepareDebuggerForLaunch(
deviceId: anyNamed('deviceId'),
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
interfaceType: anyNamed('interfaceType')))
.thenReturn(mockIOSDeployDebugger);
when(mockIOSDeploy.installApp(
deviceId: anyNamed('deviceId'),
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
interfaceType: anyNamed('interfaceType')))
.thenAnswer((_) async => 0);
when(mockIOSDeployDebugger.launchAndAttach()).thenAnswer((_) async => true);
final IOSDevice device = setUpIOSDevice(
fileSystem: fileSystem,
iosDeploy: mockIOSDeploy,
vmServiceConnector: (String string, {Log log}) async {
throw const io.SocketException(
'OS Error: Connection refused, errno = 61, address = localhost, port '
'= 58943',
);
},
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
device.portForwarder = const NoOpDevicePortForwarder();
device.setLogReader(iosApp, FakeDeviceLogReader());
final LaunchResult launchResult = await device.startApp(
iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
fallbackPollingDelay: Duration.zero,
fallbackThrottleTimeout: const Duration(milliseconds: 10),
);
expect(launchResult.started, false);
verify(mockIOSDeployDebugger.detach()).called(1);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
});
} }
IOSDevice setUpIOSDevice({ IOSDevice setUpIOSDevice({
...@@ -419,6 +475,7 @@ IOSDevice setUpIOSDevice({ ...@@ -419,6 +475,7 @@ IOSDevice setUpIOSDevice({
Logger logger, Logger logger,
ProcessManager processManager, ProcessManager processManager,
VmServiceConnector vmServiceConnector, VmServiceConnector vmServiceConnector,
IOSDeploy iosDeploy,
}) { }) {
final Artifacts artifacts = Artifacts.test(); final Artifacts artifacts = Artifacts.test();
final FakePlatform macPlatform = FakePlatform( final FakePlatform macPlatform = FakePlatform(
...@@ -441,7 +498,8 @@ IOSDevice setUpIOSDevice({ ...@@ -441,7 +498,8 @@ IOSDevice setUpIOSDevice({
platform: macPlatform, platform: macPlatform,
iProxy: IProxy.test(logger: logger, processManager: processManager ?? FakeProcessManager.any()), iProxy: IProxy.test(logger: logger, processManager: processManager ?? FakeProcessManager.any()),
logger: logger ?? BufferLogger.test(), logger: logger ?? BufferLogger.test(),
iosDeploy: IOSDeploy( iosDeploy: iosDeploy ??
IOSDeploy(
logger: logger ?? BufferLogger.test(), logger: logger ?? BufferLogger.test(),
platform: macPlatform, platform: macPlatform,
processManager: processManager ?? FakeProcessManager.any(), processManager: processManager ?? FakeProcessManager.any(),
...@@ -465,3 +523,5 @@ class MockDeviceLogReader extends Mock implements DeviceLogReader {} ...@@ -465,3 +523,5 @@ class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockUsage extends Mock implements Usage {} class MockUsage extends Mock implements Usage {}
class MockVmService extends Mock implements VmService {} class MockVmService extends Mock implements VmService {}
class MockDartDevelopmentService extends Mock implements DartDevelopmentService {} class MockDartDevelopmentService extends Mock implements DartDevelopmentService {}
class MockIOSDeployDebugger extends Mock implements IOSDeployDebugger {}
class MockIOSDeploy extends Mock implements IOSDeploy {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment