Unverified Commit e99a66a4 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] check if stream is open before sending message in ios device (#99947)

parent 2386fd90
...@@ -647,14 +647,25 @@ class IOSDeviceLogReader extends DeviceLogReader { ...@@ -647,14 +647,25 @@ class IOSDeviceLogReader extends DeviceLogReader {
// Logging from the dart code has no prefixing metadata. // Logging from the dart code has no prefixing metadata.
final RegExp _debuggerLoggingRegex = RegExp(r'^\S* \S* \S*\[[0-9:]*] (.*)'); final RegExp _debuggerLoggingRegex = RegExp(r'^\S* \S* \S*\[[0-9:]*] (.*)');
late final StreamController<String> _linesController = StreamController<String>.broadcast( @visibleForTesting
late final StreamController<String> linesController = StreamController<String>.broadcast(
onListen: _listenToSysLog, onListen: _listenToSysLog,
onCancel: dispose, onCancel: dispose,
); );
// Sometimes (race condition?) we try to send a log after the controller has
// been closed. See https://github.com/flutter/flutter/issues/99021 for more
// context.
void _addToLinesController(String message) {
if (!linesController.isClosed) {
linesController.add(message);
}
}
final List<StreamSubscription<void>> _loggingSubscriptions = <StreamSubscription<void>>[]; final List<StreamSubscription<void>> _loggingSubscriptions = <StreamSubscription<void>>[];
@override @override
Stream<String> get logLines => _linesController.stream; Stream<String> get logLines => linesController.stream;
@override @override
FlutterVmService? get connectedVMService => _connectedVMService; FlutterVmService? get connectedVMService => _connectedVMService;
...@@ -694,7 +705,7 @@ class IOSDeviceLogReader extends DeviceLogReader { ...@@ -694,7 +705,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
} }
final String message = processVmServiceMessage(event); final String message = processVmServiceMessage(event);
if (message.isNotEmpty) { if (message.isNotEmpty) {
_linesController.add(message); _addToLinesController(message);
} }
} }
...@@ -717,9 +728,9 @@ class IOSDeviceLogReader extends DeviceLogReader { ...@@ -717,9 +728,9 @@ class IOSDeviceLogReader extends DeviceLogReader {
} }
// Add the debugger logs to the controller created on initialization. // Add the debugger logs to the controller created on initialization.
_loggingSubscriptions.add(debugger.logLines.listen( _loggingSubscriptions.add(debugger.logLines.listen(
(String line) => _linesController.add(_debuggerLineHandler(line)), (String line) => _addToLinesController(_debuggerLineHandler(line)),
onError: _linesController.addError, onError: linesController.addError,
onDone: _linesController.close, onDone: linesController.close,
cancelOnError: true, cancelOnError: true,
)); ));
} }
...@@ -737,8 +748,8 @@ class IOSDeviceLogReader extends DeviceLogReader { ...@@ -737,8 +748,8 @@ class IOSDeviceLogReader extends DeviceLogReader {
process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(_newSyslogLineHandler()); process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(_newSyslogLineHandler());
process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(_newSyslogLineHandler()); process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(_newSyslogLineHandler());
process.exitCode.whenComplete(() { process.exitCode.whenComplete(() {
if (_linesController.hasListener) { if (linesController.hasListener) {
_linesController.close(); linesController.close();
} }
}); });
assert(idevicesyslogProcess == null); assert(idevicesyslogProcess == null);
...@@ -761,7 +772,7 @@ class IOSDeviceLogReader extends DeviceLogReader { ...@@ -761,7 +772,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
return (String line) { return (String line) {
if (printing) { if (printing) {
if (!_anyLineRegex.hasMatch(line)) { if (!_anyLineRegex.hasMatch(line)) {
_linesController.add(decodeSyslog(line)); _addToLinesController(decodeSyslog(line));
return; return;
} }
...@@ -773,7 +784,7 @@ class IOSDeviceLogReader extends DeviceLogReader { ...@@ -773,7 +784,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
if (match != null) { if (match != null) {
final String logLine = line.substring(match.end); final String logLine = line.substring(match.end);
// Only display the log line after the initial device and executable information. // Only display the log line after the initial device and executable information.
_linesController.add(decodeSyslog(logLine)); _addToLinesController(decodeSyslog(logLine));
printing = true; printing = true;
} }
......
...@@ -383,7 +383,7 @@ class IOSDeployDebugger { ...@@ -383,7 +383,7 @@ class IOSDeployDebugger {
// To avoid all lines being double spaced, if the last line from the // To avoid all lines being double spaced, if the last line from the
// debugger was not an empty line, skip this empty line. // debugger was not an empty line, skip this empty line.
// This will still cause "legit" logged newlines to be doubled... // This will still cause "legit" logged newlines to be doubled...
} else { } else if (!_debuggerOutput.isClosed) {
_debuggerOutput.add(line); _debuggerOutput.add(line);
} }
lastLineFromDebugger = line; lastLineFromDebugger = line;
...@@ -413,11 +413,15 @@ class IOSDeployDebugger { ...@@ -413,11 +413,15 @@ class IOSDeployDebugger {
} on ProcessException catch (exception, stackTrace) { } on ProcessException catch (exception, stackTrace) {
_logger.printTrace('ios-deploy failed: $exception'); _logger.printTrace('ios-deploy failed: $exception');
_debuggerState = _IOSDeployDebuggerState.detached; _debuggerState = _IOSDeployDebuggerState.detached;
_debuggerOutput.addError(exception, stackTrace); if (!_debuggerOutput.isClosed) {
_debuggerOutput.addError(exception, stackTrace);
}
} on ArgumentError catch (exception, stackTrace) { } on ArgumentError catch (exception, stackTrace) {
_logger.printTrace('ios-deploy failed: $exception'); _logger.printTrace('ios-deploy failed: $exception');
_debuggerState = _IOSDeployDebuggerState.detached; _debuggerState = _IOSDeployDebuggerState.detached;
_debuggerOutput.addError(exception, stackTrace); if (!_debuggerOutput.isClosed) {
_debuggerOutput.addError(exception, stackTrace);
}
} }
// Wait until the debugger attaches, or the attempt fails. // Wait until the debugger attaches, or the attempt fails.
return debuggerCompleter.future; return debuggerCompleter.future;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/async_guard.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/convert.dart';
...@@ -309,6 +310,45 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt ...@@ -309,6 +310,45 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
logReader.dispose(); logReader.dispose();
expect(iosDeployDebugger.detached, true); expect(iosDeployDebugger.detached, true);
}); });
testWithoutContext('Does not throw if debuggerStream set after logReader closed', () async {
final Stream<String> debuggingLogs = Stream<String>.fromIterable(<String>[
'2020-09-15 19:15:10.931434-0700 Runner[541:226276] Did finish launching.',
'2020-09-15 19:15:10.931434-0700 Runner[541:226276] [Category] Did finish launching from logging category.',
'stderr from dart',
'',
]);
final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
iMobileDevice: IMobileDevice(
artifacts: artifacts,
processManager: processManager,
cache: fakeCache,
logger: logger,
),
useSyslog: false,
);
Object exception;
StackTrace trace;
await asyncGuard(
() async {
await logReader.linesController.close();
final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger();
iosDeployDebugger.logLines = debuggingLogs;
logReader.debuggerStream = iosDeployDebugger;
await logReader.logLines.drain<void>();
},
onError: (Object err, StackTrace stackTrace) {
exception = err;
trace = stackTrace;
}
);
expect(
exception,
isNull,
reason: trace.toString(),
);
});
}); });
} }
......
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