@@ -647,14 +647,25 @@ class IOSDeviceLogReader extends DeviceLogReader {
647
647
// Logging from the dart code has no prefixing metadata.
648
648
final RegExp _debuggerLoggingRegex = RegExp (r'^\S* \S* \S*\[[0-9:]*] (.*)' );
649
649
650
- late final StreamController <String > _linesController = StreamController <String >.broadcast (
650
+ @visibleForTesting
651
+ late final StreamController <String > linesController = StreamController <String >.broadcast (
651
652
onListen: _listenToSysLog,
652
653
onCancel: dispose,
653
654
);
655
+
656
+ // Sometimes (race condition?) we try to send a log after the controller has
657
+ // been closed. See https://github.com/flutter/flutter/issues/99021 for more
658
+ // context.
659
+ void _addToLinesController (String message) {
660
+ if (! linesController.isClosed) {
661
+ linesController.add (message);
662
+ }
663
+ }
664
+
654
665
final List <StreamSubscription <void >> _loggingSubscriptions = < StreamSubscription <void >> [];
655
666
656
667
@override
657
- Stream <String > get logLines => _linesController .stream;
668
+ Stream <String > get logLines => linesController .stream;
658
669
659
670
@override
660
671
FlutterVmService ? get connectedVMService => _connectedVMService;
@@ -694,7 +705,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
694
705
}
695
706
final String message = processVmServiceMessage (event);
696
707
if (message.isNotEmpty) {
697
- _linesController. add (message);
708
+ _addToLinesController (message);
698
709
}
699
710
}
700
711
@@ -717,9 +728,9 @@ class IOSDeviceLogReader extends DeviceLogReader {
717
728
}
718
729
// Add the debugger logs to the controller created on initialization.
719
730
_loggingSubscriptions.add (debugger.logLines.listen (
720
- (String line) => _linesController. add (_debuggerLineHandler (line)),
721
- onError: _linesController .addError,
722
- onDone: _linesController .close,
731
+ (String line) => _addToLinesController (_debuggerLineHandler (line)),
732
+ onError: linesController .addError,
733
+ onDone: linesController .close,
723
734
cancelOnError: true ,
724
735
));
725
736
}
@@ -737,8 +748,8 @@ class IOSDeviceLogReader extends DeviceLogReader {
737
748
process.stdout.transform <String >(utf8.decoder).transform <String >(const LineSplitter ()).listen (_newSyslogLineHandler ());
738
749
process.stderr.transform <String >(utf8.decoder).transform <String >(const LineSplitter ()).listen (_newSyslogLineHandler ());
739
750
process.exitCode.whenComplete (() {
740
- if (_linesController .hasListener) {
741
- _linesController .close ();
751
+ if (linesController .hasListener) {
752
+ linesController .close ();
742
753
}
743
754
});
744
755
assert (idevicesyslogProcess == null );
@@ -761,7 +772,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
761
772
return (String line) {
762
773
if (printing) {
763
774
if (! _anyLineRegex.hasMatch (line)) {
764
- _linesController. add (decodeSyslog (line));
775
+ _addToLinesController (decodeSyslog (line));
765
776
return ;
766
777
}
767
778
@@ -773,7 +784,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
773
784
if (match != null ) {
774
785
final String logLine = line.substring (match.end);
775
786
// Only display the log line after the initial device and executable information.
776
- _linesController. add (decodeSyslog (logLine));
787
+ _addToLinesController (decodeSyslog (logLine));
777
788
778
789
printing = true ;
779
790
}
0 commit comments