Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
bccc9eac
Unverified
Commit
bccc9eac
authored
Dec 02, 2021
by
Hannes Winkler
Committed by
GitHub
Dec 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix a stream lifecycle bug in CustomDeviceLogReader (#94310)
parent
e147fae8
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
81 additions
and
14 deletions
+81
-14
custom_device.dart
...s/flutter_tools/lib/src/custom_devices/custom_device.dart
+33
-14
custom_device_test.dart
...test/general.shard/custom_devices/custom_device_test.dart
+48
-0
No files found.
packages/flutter_tools/lib/src/custom_devices/custom_device.dart
View file @
bccc9eac
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
import
'dart:async'
;
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:process/process.dart'
;
import
'package:process/process.dart'
;
import
'../application_package.dart'
;
import
'../application_package.dart'
;
...
@@ -53,7 +54,11 @@ class CustomDeviceLogReader extends DeviceLogReader {
...
@@ -53,7 +54,11 @@ class CustomDeviceLogReader extends DeviceLogReader {
@override
@override
final
String
name
;
final
String
name
;
final
StreamController
<
String
>
_logLinesController
=
StreamController
<
String
>.
broadcast
();
@visibleForTesting
final
StreamController
<
String
>
logLinesController
=
StreamController
<
String
>.
broadcast
();
@visibleForTesting
final
List
<
StreamSubscription
<
String
>>
subscriptions
=
<
StreamSubscription
<
String
>>[];
/// Listen to [process]' stdout and stderr, decode them using [SystemEncoding]
/// Listen to [process]' stdout and stderr, decode them using [SystemEncoding]
/// and add each decoded line to [logLines].
/// and add each decoded line to [logLines].
...
@@ -66,13 +71,17 @@ class CustomDeviceLogReader extends DeviceLogReader {
...
@@ -66,13 +71,17 @@ class CustomDeviceLogReader extends DeviceLogReader {
void
listenToProcessOutput
(
Process
process
,
{
Encoding
encoding
=
systemEncoding
})
{
void
listenToProcessOutput
(
Process
process
,
{
Encoding
encoding
=
systemEncoding
})
{
final
Converter
<
List
<
int
>,
String
>
decoder
=
encoding
.
decoder
;
final
Converter
<
List
<
int
>,
String
>
decoder
=
encoding
.
decoder
;
process
.
stdout
.
transform
<
String
>(
decoder
)
subscriptions
.
add
(
.
transform
<
String
>(
const
LineSplitter
())
process
.
stdout
.
transform
<
String
>(
decoder
)
.
listen
(
_logLinesController
.
add
);
.
transform
<
String
>(
const
LineSplitter
())
.
listen
(
logLinesController
.
add
),
);
process
.
stderr
.
transform
<
String
>(
decoder
)
subscriptions
.
add
(
.
transform
<
String
>(
const
LineSplitter
())
process
.
stderr
.
transform
<
String
>(
decoder
)
.
listen
(
_logLinesController
.
add
);
.
transform
<
String
>(
const
LineSplitter
())
.
listen
(
logLinesController
.
add
)
);
}
}
/// Add all lines emitted by [lines] to this [CustomDeviceLogReader]s [logLines]
/// Add all lines emitted by [lines] to this [CustomDeviceLogReader]s [logLines]
...
@@ -83,18 +92,28 @@ class CustomDeviceLogReader extends DeviceLogReader {
...
@@ -83,18 +92,28 @@ class CustomDeviceLogReader extends DeviceLogReader {
///
///
/// Useful when you want to combine the contents of multiple log readers.
/// Useful when you want to combine the contents of multiple log readers.
void
listenToLinesStream
(
Stream
<
String
>
lines
)
{
void
listenToLinesStream
(
Stream
<
String
>
lines
)
{
_logLinesController
.
addStream
(
lines
);
subscriptions
.
add
(
lines
.
listen
(
logLinesController
.
add
)
);
}
}
/// Dispose this log reader, freeing all associated resources and marking
/// Dispose this log reader, freeing all associated resources and marking
/// [logLines] as done.
/// [logLines] as done.
@override
@override
void
dispose
()
{
Future
<
void
>
dispose
()
async
{
_logLinesController
.
close
();
final
List
<
Future
<
void
>>
futures
=
<
Future
<
void
>>[];
for
(
final
StreamSubscription
<
String
>
subscription
in
subscriptions
)
{
futures
.
add
(
subscription
.
cancel
());
}
futures
.
add
(
logLinesController
.
close
());
await
Future
.
wait
(
futures
);
}
}
@override
@override
Stream
<
String
>
get
logLines
=>
_
logLinesController
.
stream
;
Stream
<
String
>
get
logLines
=>
logLinesController
.
stream
;
}
}
/// A [DevicePortForwarder] that uses commands to forward / unforward a port.
/// A [DevicePortForwarder] that uses commands to forward / unforward a port.
...
@@ -170,8 +189,8 @@ class CustomDevicePortForwarder extends DevicePortForwarder {
...
@@ -170,8 +189,8 @@ class CustomDevicePortForwarder extends DevicePortForwarder {
}));
}));
unawaited
(
completer
.
future
.
whenComplete
(()
{
unawaited
(
completer
.
future
.
whenComplete
(()
{
logLinesSubscription
.
cancel
(
);
unawaited
(
logLinesSubscription
.
cancel
()
);
reader
.
dispose
(
);
unawaited
(
reader
.
dispose
()
);
}));
}));
return
completer
.
future
;
return
completer
.
future
;
...
@@ -440,7 +459,7 @@ class CustomDeviceAppSession {
...
@@ -440,7 +459,7 @@ class CustomDeviceAppSession {
_process
=
null
;
_process
=
null
;
}
}
logReader
.
dispose
(
);
unawaited
(
logReader
.
dispose
()
);
}
}
}
}
...
...
packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart
View file @
bccc9eac
...
@@ -587,6 +587,54 @@ void main() {
...
@@ -587,6 +587,54 @@ void main() {
expect
(
await
device
.
targetPlatform
,
TargetPlatform
.
linux_x64
);
expect
(
await
device
.
targetPlatform
,
TargetPlatform
.
linux_x64
);
});
});
testWithoutContext
(
'CustomDeviceLogReader cancels subscriptions before closing logLines stream'
,
()
async
{
final
CustomDeviceLogReader
logReader
=
CustomDeviceLogReader
(
'testname'
);
final
Iterable
<
List
<
int
>>
lines
=
Iterable
<
List
<
int
>>.
generate
(
5
,
(
int
_
)
=>
utf8
.
encode
(
'test'
));
logReader
.
listenToProcessOutput
(
FakeProcess
(
exitCode:
Future
<
int
>.
value
(
0
),
stdout:
Stream
<
List
<
int
>>.
fromIterable
(
lines
),
stderr:
Stream
<
List
<
int
>>.
fromIterable
(
lines
),
),
);
final
List
<
MyFakeStreamSubscription
<
String
>>
subscriptions
=
<
MyFakeStreamSubscription
<
String
>>[];
bool
logLinesStreamDone
=
false
;
logReader
.
logLines
.
listen
((
_
)
{},
onDone:
()
{
expect
(
subscriptions
,
everyElement
((
MyFakeStreamSubscription
<
String
>
s
)
=>
s
.
canceled
));
logLinesStreamDone
=
true
;
});
logReader
.
subscriptions
.
replaceRange
(
0
,
logReader
.
subscriptions
.
length
,
logReader
.
subscriptions
.
map
(
(
StreamSubscription
<
String
>
e
)
=>
MyFakeStreamSubscription
<
String
>(
e
)
),
);
subscriptions
.
addAll
(
logReader
.
subscriptions
.
cast
());
await
logReader
.
dispose
();
expect
(
logLinesStreamDone
,
true
);
});
}
class
MyFakeStreamSubscription
<
T
>
extends
Fake
implements
StreamSubscription
<
T
>
{
MyFakeStreamSubscription
(
this
.
parent
);
StreamSubscription
<
T
>
parent
;
bool
canceled
=
false
;
@override
Future
<
void
>
cancel
()
{
canceled
=
true
;
return
parent
.
cancel
();
}
}
}
class
FakeBundleBuilder
extends
Fake
implements
BundleBuilder
{
class
FakeBundleBuilder
extends
Fake
implements
BundleBuilder
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment