mirror of
https://github.com/flutter/flutter
synced 2024-08-27 20:10:11 +00:00
Add debugging for Dart VM timeout flake (#126437)
Check what is available in the device's iOS DeviceSupport folder to check if symbols were properly fetched. Also, add some logging to track what status the debugger is in. Debugging for https://github.com/flutter/flutter/issues/121231.
This commit is contained in:
parent
0636f5e035
commit
5d1132561f
|
@ -546,6 +546,7 @@ class IOSDevice extends Device {
|
|||
"If you don't see your app in the Settings, uninstall the app and rerun to see the prompt again."
|
||||
);
|
||||
} else {
|
||||
iosDeployDebugger?.checkForSymbolsFiles(_fileSystem);
|
||||
iosDeployDebugger?.pauseDumpBacktraceResume();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -288,6 +288,9 @@ class IOSDeployDebugger {
|
|||
bool get debuggerAttached => _debuggerState == _IOSDeployDebuggerState.attached;
|
||||
_IOSDeployDebuggerState _debuggerState;
|
||||
|
||||
@visibleForTesting
|
||||
String? symbolsDirectoryPath;
|
||||
|
||||
// (lldb) platform select remote-'ios' --sysroot
|
||||
// https://github.com/ios-control/ios-deploy/blob/1.11.2-beta.1/src/ios-deploy/ios-deploy.m#L33
|
||||
// This regex is to get the configurable lldb prompt. By default this prompt will be "lldb".
|
||||
|
@ -306,6 +309,9 @@ class IOSDeployDebugger {
|
|||
// (lldb) Process 6152 resuming
|
||||
static final RegExp _lldbProcessResuming = RegExp(r'Process \d+ resuming');
|
||||
|
||||
// Symbol Path: /Users/swarming/Library/Developer/Xcode/iOS DeviceSupport/16.2 (20C65) arm64e/Symbols
|
||||
static final RegExp _symbolsPathPattern = RegExp(r'.*Symbol Path: ');
|
||||
|
||||
// Send signal to stop (pause) the app. Used before a backtrace dump.
|
||||
static const String _signalStop = 'process signal SIGSTOP';
|
||||
|
||||
|
@ -362,12 +368,25 @@ class IOSDeployDebugger {
|
|||
return;
|
||||
}
|
||||
|
||||
// Symbol Path: /Users/swarming/Library/Developer/Xcode/iOS DeviceSupport/16.2 (20C65) arm64e/Symbols
|
||||
if (_symbolsPathPattern.hasMatch(line)) {
|
||||
_logger.printTrace('Detected path to iOS debug symbols: "$line"');
|
||||
final String prefix = _symbolsPathPattern.stringMatch(line) ?? '';
|
||||
if (prefix.isEmpty) {
|
||||
return;
|
||||
}
|
||||
symbolsDirectoryPath = line.substring(prefix.length);
|
||||
return;
|
||||
}
|
||||
|
||||
// (lldb) run
|
||||
// success
|
||||
// 2020-09-15 13:42:25.185474-0700 Runner[477:181141] flutter: The Dart VM service is listening on http://127.0.0.1:57782/
|
||||
if (lldbRun.hasMatch(line)) {
|
||||
_logger.printTrace(line);
|
||||
_debuggerState = _IOSDeployDebuggerState.launching;
|
||||
// TODO(vashworth): Remove all debugger state comments when https://github.com/flutter/flutter/issues/126412 is resolved.
|
||||
_logger.printTrace('Debugger state set to launching.');
|
||||
return;
|
||||
}
|
||||
// Next line after "run" must be "success", or the attach failed.
|
||||
|
@ -376,6 +395,7 @@ class IOSDeployDebugger {
|
|||
_logger.printTrace(line);
|
||||
final bool attachSuccess = line == 'success';
|
||||
_debuggerState = attachSuccess ? _IOSDeployDebuggerState.attached : _IOSDeployDebuggerState.detached;
|
||||
_logger.printTrace('Debugger state set to ${attachSuccess ? 'attached' : 'detached'}.');
|
||||
if (!debuggerCompleter.isCompleted) {
|
||||
debuggerCompleter.complete(attachSuccess);
|
||||
}
|
||||
|
@ -392,6 +412,7 @@ class IOSDeployDebugger {
|
|||
// Even though we're not "detached", just stopped, mark as detached so the backtrace
|
||||
// is only show in verbose.
|
||||
_debuggerState = _IOSDeployDebuggerState.detached;
|
||||
_logger.printTrace('Debugger state set to detached.');
|
||||
|
||||
// If we paused the app and are waiting to resume it, complete the completer
|
||||
final Completer<void>? processResumeCompleter = _processResumeCompleter;
|
||||
|
@ -422,6 +443,7 @@ class IOSDeployDebugger {
|
|||
if (_lldbProcessDetached.hasMatch(line)) {
|
||||
// The debugger has detached from the app, and there will be no more debugging messages.
|
||||
// Kill the ios-deploy process.
|
||||
_logger.printTrace(line);
|
||||
exit();
|
||||
return;
|
||||
}
|
||||
|
@ -430,6 +452,7 @@ class IOSDeployDebugger {
|
|||
_logger.printTrace(line);
|
||||
// we marked this detached when we received [_backTraceAll]
|
||||
_debuggerState = _IOSDeployDebuggerState.attached;
|
||||
_logger.printTrace('Debugger state set to attached.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -510,6 +533,33 @@ class IOSDeployDebugger {
|
|||
_iosDeployProcess?.stdin.writeln(_processResume);
|
||||
}
|
||||
|
||||
/// Check what files are found in the device's iOS DeviceSupport directory.
|
||||
///
|
||||
/// Expected files include Symbols (directory), Info.plist, and .finalized.
|
||||
///
|
||||
/// If any of the expected files are missing or there are additional files
|
||||
/// (such as .copying_lock or .processing_lock), this may indicate the
|
||||
/// symbols may still be fetching or something went wrong when fetching them.
|
||||
///
|
||||
/// Used for debugging test flakes: https://github.com/flutter/flutter/issues/121231
|
||||
Future<void> checkForSymbolsFiles(FileSystem fileSystem) async {
|
||||
if (symbolsDirectoryPath == null) {
|
||||
_logger.printTrace('No path provided for Symbols directory.');
|
||||
return;
|
||||
}
|
||||
final Directory symbolsDirectory = fileSystem.directory(symbolsDirectoryPath);
|
||||
if (!symbolsDirectory.existsSync()) {
|
||||
_logger.printTrace('Unable to find Symbols directory at $symbolsDirectoryPath');
|
||||
return;
|
||||
}
|
||||
final Directory currentDeviceSupportDir = symbolsDirectory.parent;
|
||||
final List<FileSystemEntity> symbolStatusFiles = currentDeviceSupportDir.listSync();
|
||||
_logger.printTrace('Symbol files:');
|
||||
for (final FileSystemEntity file in symbolStatusFiles) {
|
||||
_logger.printTrace(' ${file.basename}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stopAndDumpBacktrace() async {
|
||||
if (!debuggerAttached) {
|
||||
return;
|
||||
|
|
|
@ -428,6 +428,93 @@ process continue
|
|||
'process detach',
|
||||
]);
|
||||
});
|
||||
|
||||
group('Check for symbols', () {
|
||||
late String symbolsDirectoryPath;
|
||||
|
||||
setUp(() {
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
symbolsDirectoryPath = '/Users/swarming/Library/Developer/Xcode/iOS DeviceSupport/16.2 (20C65) arm64e/Symbols';
|
||||
});
|
||||
|
||||
testWithoutContext('and no path provided', () async {
|
||||
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'ios-deploy',
|
||||
],
|
||||
stdout:
|
||||
'(lldb) Process 6156 stopped',
|
||||
),
|
||||
]);
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
|
||||
processManager: processManager,
|
||||
logger: logger,
|
||||
);
|
||||
await iosDeployDebugger.launchAndAttach();
|
||||
await iosDeployDebugger.checkForSymbolsFiles(fileSystem);
|
||||
expect(iosDeployDebugger.symbolsDirectoryPath, isNull);
|
||||
expect(logger.traceText, contains('No path provided for Symbols directory.'));
|
||||
});
|
||||
|
||||
testWithoutContext('and unable to find directory', () async {
|
||||
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'ios-deploy',
|
||||
],
|
||||
stdout:
|
||||
'[ 95%] Developer disk image mounted successfully\n'
|
||||
'Symbol Path: $symbolsDirectoryPath\n'
|
||||
'[100%] Connecting to remote debug server',
|
||||
),
|
||||
]);
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
|
||||
processManager: processManager,
|
||||
logger: logger,
|
||||
);
|
||||
await iosDeployDebugger.launchAndAttach();
|
||||
await iosDeployDebugger.checkForSymbolsFiles(fileSystem);
|
||||
expect(iosDeployDebugger.symbolsDirectoryPath, symbolsDirectoryPath);
|
||||
expect(logger.traceText, contains('Unable to find Symbols directory'));
|
||||
});
|
||||
|
||||
testWithoutContext('and find status', () async {
|
||||
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||
FakeCommand(
|
||||
command: const <String>[
|
||||
'ios-deploy',
|
||||
],
|
||||
stdout:
|
||||
'[ 95%] Developer disk image mounted successfully\n'
|
||||
'Symbol Path: $symbolsDirectoryPath\n'
|
||||
'[100%] Connecting to remote debug server',
|
||||
),
|
||||
]);
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test(
|
||||
processManager: processManager,
|
||||
logger: logger,
|
||||
);
|
||||
final Directory symbolsDirectory = fileSystem.directory(symbolsDirectoryPath);
|
||||
symbolsDirectory.createSync(recursive: true);
|
||||
|
||||
final File copyingStatusFile = symbolsDirectory.parent.childFile('.copying_lock');
|
||||
copyingStatusFile.createSync();
|
||||
|
||||
final File processingStatusFile = symbolsDirectory.parent.childFile('.processing_lock');
|
||||
processingStatusFile.createSync();
|
||||
|
||||
await iosDeployDebugger.launchAndAttach();
|
||||
await iosDeployDebugger.checkForSymbolsFiles(fileSystem);
|
||||
expect(iosDeployDebugger.symbolsDirectoryPath, symbolsDirectoryPath);
|
||||
expect(logger.traceText, contains('Symbol files:'));
|
||||
expect(logger.traceText, contains('.copying_lock'));
|
||||
expect(logger.traceText, contains('.processing_lock'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('IOSDeploy.uninstallApp', () {
|
||||
|
|
Loading…
Reference in a new issue