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
d5b715d7
Unverified
Commit
d5b715d7
authored
Sep 23, 2020
by
Jenn Magder
Committed by
GitHub
Sep 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Stream logging from attached debugger on iOS 13+ (#66399)
parent
658e6c8a
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
971 additions
and
257 deletions
+971
-257
flutter_run_test.dart
dev/automated_tests/flutter_run_test/flutter_run_test.dart
+4
-0
flutter_run_test.dart
dev/devicelab/bin/tasks/flutter_run_test.dart
+19
-5
devices.dart
packages/flutter_tools/lib/src/ios/devices.dart
+73
-12
fallback_discovery.dart
packages/flutter_tools/lib/src/ios/fallback_discovery.dart
+17
-17
ios_deploy.dart
packages/flutter_tools/lib/src/ios/ios_deploy.dart
+237
-15
protocol_discovery.dart
packages/flutter_tools/lib/src/protocol_discovery.dart
+7
-4
ios_deploy_test.dart
...flutter_tools/test/general.shard/ios/ios_deploy_test.dart
+247
-42
ios_device_logger_test.dart
..._tools/test/general.shard/ios/ios_device_logger_test.dart
+261
-128
ios_device_start_prebuilt_test.dart
...est/general.shard/ios/ios_device_start_prebuilt_test.dart
+106
-34
No files found.
dev/automated_tests/flutter_run_test/flutter_run_test.dart
View file @
d5b715d7
...
@@ -2,11 +2,15 @@
...
@@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:io'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
void
main
(
)
{
group
(
'example'
,
()
{
group
(
'example'
,
()
{
test
(
'passed'
,
()
{
test
(
'passed'
,
()
{
print
(
'This is print'
);
stderr
.
writeln
(
'This is writeln'
);
expect
(
true
,
true
);
expect
(
true
,
true
);
});
});
test
(
'failed'
,
()
{
test
(
'failed'
,
()
{
...
...
dev/devicelab/bin/tasks/flutter_run_test.dart
View file @
d5b715d7
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
import
'dart:io'
;
import
'package:path/path.dart'
as
path
;
import
'package:path/path.dart'
as
path
;
...
@@ -19,9 +20,10 @@ const Pattern passedMessageMatch = '+0: example passed';
...
@@ -19,9 +20,10 @@ const Pattern passedMessageMatch = '+0: example passed';
const
Pattern
failedMessageMatch
=
'+1: example failed [E]'
;
const
Pattern
failedMessageMatch
=
'+1: example failed [E]'
;
const
Pattern
skippedMessageMatch
=
'+1 -1: example skipped'
;
const
Pattern
skippedMessageMatch
=
'+1 -1: example skipped'
;
const
Pattern
finishedMessageMatch
=
'+1 ~1 -1: Some tests failed.'
;
const
Pattern
finishedMessageMatch
=
'+1 ~1 -1: Some tests failed.'
;
const
Pattern
printMessageMatch
=
'This is print'
;
const
Pattern
writelnMessageMatch
=
'This is writeln'
;
Future
<
void
>
main
()
async
{
Future
<
void
>
main
()
async
{
deviceOperatingSystem
=
DeviceOperatingSystem
.
android
;
await
task
(
createFlutterRunTask
);
await
task
(
createFlutterRunTask
);
}
}
...
@@ -31,19 +33,26 @@ Future<TaskResult> createFlutterRunTask() async {
...
@@ -31,19 +33,26 @@ Future<TaskResult> createFlutterRunTask() async {
bool
failedTest
=
false
;
bool
failedTest
=
false
;
bool
skippedTest
=
false
;
bool
skippedTest
=
false
;
bool
finishedMessage
=
false
;
bool
finishedMessage
=
false
;
bool
printMessage
=
false
;
bool
writelnMessage
=
false
;
final
Device
device
=
await
devices
.
workingDevice
;
final
Device
device
=
await
devices
.
workingDevice
;
await
device
.
unlock
();
await
device
.
unlock
();
final
List
<
String
>
options
=
<
String
>[
final
List
<
String
>
options
=
<
String
>[
'-t'
,
runTestSource
.
absolute
.
path
,
'-d'
,
device
.
deviceId
,
'-t'
,
runTestSource
.
absolute
.
path
,
'-d'
,
device
.
deviceId
,
'-v'
,
];
];
await
inDirectory
<
void
>(
flutterGalleryDir
,
()
async
{
await
inDirectory
<
void
>(
flutterGalleryDir
,
()
async
{
startProcess
(
final
Process
run
=
await
startProcess
(
path
.
join
(
flutterDirectory
.
path
,
'bin'
,
'flutter'
),
path
.
join
(
flutterDirectory
.
path
,
'bin'
,
'flutter'
),
flutterCommandArgs
(
'run'
,
options
),
flutterCommandArgs
(
'run'
,
options
),
environment:
null
,
environment:
null
,
);
);
final
Completer
<
void
>
finished
=
Completer
<
void
>();
final
Completer
<
void
>
finished
=
Completer
<
void
>();
final
StreamSubscription
<
void
>
subscription
=
device
.
logcat
.
listen
((
String
line
)
{
final
StreamSubscription
<
void
>
subscription
=
run
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
print
(
'stdout:
$line
'
);
// tests execute in order.
// tests execute in order.
if
(
line
.
contains
(
passedMessageMatch
))
{
if
(
line
.
contains
(
passedMessageMatch
))
{
passedTest
=
true
;
passedTest
=
true
;
...
@@ -51,6 +60,10 @@ Future<TaskResult> createFlutterRunTask() async {
...
@@ -51,6 +60,10 @@ Future<TaskResult> createFlutterRunTask() async {
failedTest
=
true
;
failedTest
=
true
;
}
else
if
(
line
.
contains
(
skippedMessageMatch
))
{
}
else
if
(
line
.
contains
(
skippedMessageMatch
))
{
skippedTest
=
true
;
skippedTest
=
true
;
}
else
if
(
line
.
contains
(
printMessageMatch
))
{
printMessage
=
true
;
}
else
if
(
line
.
contains
(
writelnMessageMatch
))
{
writelnMessage
=
true
;
}
else
if
(
line
.
contains
(
finishedMessageMatch
))
{
}
else
if
(
line
.
contains
(
finishedMessageMatch
))
{
finishedMessage
=
true
;
finishedMessage
=
true
;
finished
.
complete
();
finished
.
complete
();
...
@@ -58,8 +71,9 @@ Future<TaskResult> createFlutterRunTask() async {
...
@@ -58,8 +71,9 @@ Future<TaskResult> createFlutterRunTask() async {
});
});
await
finished
.
future
.
timeout
(
const
Duration
(
minutes:
1
));
await
finished
.
future
.
timeout
(
const
Duration
(
minutes:
1
));
subscription
.
cancel
();
subscription
.
cancel
();
run
.
kill
();
});
});
return
passedTest
&&
failedTest
&&
skippedTest
&&
finishedMessage
return
passedTest
&&
failedTest
&&
skippedTest
&&
finishedMessage
&&
printMessage
&&
writelnMessage
?
TaskResult
.
success
(<
String
,
dynamic
>{})
?
TaskResult
.
success
(<
String
,
dynamic
>{})
:
TaskResult
.
failure
(
'Test did not execute as expected.'
);
:
TaskResult
.
failure
(
'Test did not execute as expected.'
);
}
}
packages/flutter_tools/lib/src/ios/devices.dart
View file @
d5b715d7
...
@@ -213,6 +213,9 @@ class IOSDevice extends Device {
...
@@ -213,6 +213,9 @@ class IOSDevice extends Device {
DevicePortForwarder
_portForwarder
;
DevicePortForwarder
_portForwarder
;
@visibleForTesting
IOSDeployDebugger
iosDeployDebugger
;
@override
@override
Future
<
bool
>
get
isLocalEmulator
async
=>
false
;
Future
<
bool
>
get
isLocalEmulator
async
=>
false
;
...
@@ -396,23 +399,45 @@ class IOSDevice extends Device {
...
@@ -396,23 +399,45 @@ class IOSDevice extends Device {
timeout:
timeoutConfiguration
.
slowOperation
);
timeout:
timeoutConfiguration
.
slowOperation
);
try
{
try
{
ProtocolDiscovery
observatoryDiscovery
;
ProtocolDiscovery
observatoryDiscovery
;
int
installationResult
=
1
;
if
(
debuggingOptions
.
debuggingEnabled
)
{
if
(
debuggingOptions
.
debuggingEnabled
)
{
_logger
.
printTrace
(
'Debugging is enabled, connecting to observatory'
);
_logger
.
printTrace
(
'Debugging is enabled, connecting to observatory'
);
final
DeviceLogReader
deviceLogReader
=
getLogReader
(
app:
package
);
// If the device supports syslog reading, prefer launching the app without
// attaching the debugger to avoid the overhead of the unnecessary extra running process.
if
(
majorSdkVersion
>=
IOSDeviceLogReader
.
minimumUniversalLoggingSdkVersion
)
{
iosDeployDebugger
=
_iosDeploy
.
prepareDebuggerForLaunch
(
deviceId:
id
,
bundlePath:
bundle
.
path
,
launchArguments:
launchArguments
,
interfaceType:
interfaceType
,
);
if
(
deviceLogReader
is
IOSDeviceLogReader
)
{
deviceLogReader
.
debuggerStream
=
iosDeployDebugger
;
}
}
observatoryDiscovery
=
ProtocolDiscovery
.
observatory
(
observatoryDiscovery
=
ProtocolDiscovery
.
observatory
(
getLogReader
(
app:
package
)
,
deviceLogReader
,
portForwarder:
portForwarder
,
portForwarder:
portForwarder
,
throttleDuration:
fallbackPollingDelay
,
throttleTimeout:
fallbackThrottleTimeout
??
const
Duration
(
seconds:
5
),
hostPort:
debuggingOptions
.
hostVmServicePort
,
hostPort:
debuggingOptions
.
hostVmServicePort
,
devicePort:
debuggingOptions
.
deviceVmServicePort
,
devicePort:
debuggingOptions
.
deviceVmServicePort
,
ipv6:
ipv6
,
ipv6:
ipv6
,
throttleTimeout:
fallbackThrottleTimeout
??
const
Duration
(
seconds:
1
),
);
);
}
}
final
int
installationResult
=
await
_iosDeploy
.
runApp
(
if
(
iosDeployDebugger
==
null
)
{
deviceId:
id
,
installationResult
=
await
_iosDeploy
.
launchApp
(
bundlePath:
bundle
.
path
,
deviceId:
id
,
launchArguments:
launchArguments
,
bundlePath:
bundle
.
path
,
interfaceType:
interfaceType
,
launchArguments:
launchArguments
,
);
interfaceType:
interfaceType
,
);
}
else
{
installationResult
=
await
iosDeployDebugger
.
launchAndAttach
()
?
0
:
1
;
}
if
(
installationResult
!=
0
)
{
if
(
installationResult
!=
0
)
{
_logger
.
printError
(
'Could not run
${bundle.path}
on
$id
.'
);
_logger
.
printError
(
'Could not run
${bundle.path}
on
$id
.'
);
_logger
.
printError
(
'Try launching Xcode and selecting "Product > Run" to fix the problem:'
);
_logger
.
printError
(
'Try launching Xcode and selecting "Product > Run" to fix the problem:'
);
...
@@ -466,7 +491,11 @@ class IOSDevice extends Device {
...
@@ -466,7 +491,11 @@ class IOSDevice extends Device {
IOSApp
app
,
{
IOSApp
app
,
{
String
userIdentifier
,
String
userIdentifier
,
})
async
{
})
async
{
// Currently we don't have a way to stop an app running on iOS.
// If the debugger is not attached, killing the ios-deploy process won't stop the app.
if
(
iosDeployDebugger
!=
null
&&
iosDeployDebugger
.
debuggerAttached
)
{
// Avoid null.
return
iosDeployDebugger
?.
exit
()
==
true
;
}
return
false
;
return
false
;
}
}
...
@@ -656,6 +685,13 @@ class IOSDeviceLogReader extends DeviceLogReader {
...
@@ -656,6 +685,13 @@ class IOSDeviceLogReader extends DeviceLogReader {
// Matches a syslog line from any app.
// Matches a syslog line from any app.
RegExp
_anyLineRegex
;
RegExp
_anyLineRegex
;
// Logging from native code/Flutter engine is prefixed by timestamp and process metadata:
// 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.
//
// Logging from the dart code has no prefixing metadata.
final
RegExp
_debuggerLoggingRegex
=
RegExp
(
r'^\S* \S* \S*\[[0-9:]*] (.*)'
);
StreamController
<
String
>
_linesController
;
StreamController
<
String
>
_linesController
;
List
<
StreamSubscription
<
void
>>
_loggingSubscriptions
;
List
<
StreamSubscription
<
void
>>
_loggingSubscriptions
;
...
@@ -672,10 +708,10 @@ class IOSDeviceLogReader extends DeviceLogReader {
...
@@ -672,10 +708,10 @@ class IOSDeviceLogReader extends DeviceLogReader {
_connectedVMService
=
connectedVmService
;
_connectedVMService
=
connectedVmService
;
}
}
static
const
int
_
minimumUniversalLoggingSdkVersion
=
13
;
static
const
int
minimumUniversalLoggingSdkVersion
=
13
;
Future
<
void
>
_listenToUnifiedLoggingEvents
(
vm_service
.
VmService
connectedVmService
)
async
{
Future
<
void
>
_listenToUnifiedLoggingEvents
(
vm_service
.
VmService
connectedVmService
)
async
{
if
(
_majorSdkVersion
<
_
minimumUniversalLoggingSdkVersion
)
{
if
(
_majorSdkVersion
<
minimumUniversalLoggingSdkVersion
)
{
return
;
return
;
}
}
try
{
try
{
...
@@ -692,6 +728,10 @@ class IOSDeviceLogReader extends DeviceLogReader {
...
@@ -692,6 +728,10 @@ class IOSDeviceLogReader extends DeviceLogReader {
}
}
void
logMessage
(
vm_service
.
Event
event
)
{
void
logMessage
(
vm_service
.
Event
event
)
{
if
(
_iosDeployDebugger
!=
null
&&
_iosDeployDebugger
.
debuggerAttached
)
{
// Prefer the more complete logs from the attached debugger.
return
;
}
final
String
message
=
processVmServiceMessage
(
event
);
final
String
message
=
processVmServiceMessage
(
event
);
if
(
message
.
isNotEmpty
)
{
if
(
message
.
isNotEmpty
)
{
_linesController
.
add
(
message
);
_linesController
.
add
(
message
);
...
@@ -704,9 +744,29 @@ class IOSDeviceLogReader extends DeviceLogReader {
...
@@ -704,9 +744,29 @@ class IOSDeviceLogReader extends DeviceLogReader {
]);
]);
}
}
/// Log reader will listen to [debugger.logLines] and will detach debugger on dispose.
set
debuggerStream
(
IOSDeployDebugger
debugger
)
{
// Logging is gathered from syslog on iOS 13 and earlier.
if
(
_majorSdkVersion
<
minimumUniversalLoggingSdkVersion
)
{
return
;
}
_iosDeployDebugger
=
debugger
;
// Add the debugger logs to the controller created on initialization.
_loggingSubscriptions
.
add
(
debugger
.
logLines
.
listen
(
(
String
line
)
=>
_linesController
.
add
(
_debuggerLineHandler
(
line
)),
onError:
_linesController
.
addError
,
onDone:
_linesController
.
close
,
cancelOnError:
true
,
));
}
IOSDeployDebugger
_iosDeployDebugger
;
// Strip off the logging metadata (leave the category), or just echo the line.
String
_debuggerLineHandler
(
String
line
)
=>
_debuggerLoggingRegex
?.
firstMatch
(
line
)?.
group
(
1
)
??
line
;
void
_listenToSysLog
()
{
void
_listenToSysLog
()
{
// syslog is not written on iOS 13+.
// syslog is not written on iOS 13+.
if
(
_majorSdkVersion
>=
_
minimumUniversalLoggingSdkVersion
)
{
if
(
_majorSdkVersion
>=
minimumUniversalLoggingSdkVersion
)
{
return
;
return
;
}
}
_iMobileDevice
.
startLogger
(
_deviceId
).
then
<
void
>((
Process
process
)
{
_iMobileDevice
.
startLogger
(
_deviceId
).
then
<
void
>((
Process
process
)
{
...
@@ -763,6 +823,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
...
@@ -763,6 +823,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
loggingSubscription
.
cancel
();
loggingSubscription
.
cancel
();
}
}
_idevicesyslogProcess
?.
kill
();
_idevicesyslogProcess
?.
kill
();
_iosDeployDebugger
?.
detach
();
}
}
}
}
...
...
packages/flutter_tools/lib/src/ios/fallback_discovery.dart
View file @
d5b715d7
...
@@ -82,50 +82,50 @@ class FallbackDiscovery {
...
@@ -82,50 +82,50 @@ class FallbackDiscovery {
}
}
try
{
try
{
final
Uri
result
=
await
_mDnsObservatoryDiscovery
.
getObservatoryUri
(
final
Uri
result
=
await
_protocolDiscovery
.
uri
;
packageId
,
device
,
usesIpv6:
usesIpv6
,
hostVmservicePort:
hostVmservicePort
,
);
if
(
result
!=
null
)
{
if
(
result
!=
null
)
{
UsageEvent
(
UsageEvent
(
_kEventName
,
_kEventName
,
'
mdns
-success'
,
'
log
-success'
,
flutterUsage:
_flutterUsage
,
flutterUsage:
_flutterUsage
,
).
send
();
).
send
();
return
result
;
return
result
;
}
}
}
on
ArgumentError
{
// In the event of an invalid InternetAddress, this code attempts to catch
// an ArgumentError from protocol_discovery.dart
}
on
Exception
catch
(
err
)
{
}
on
Exception
catch
(
err
)
{
_logger
.
printTrace
(
err
.
toString
());
_logger
.
printTrace
(
err
.
toString
());
}
}
_logger
.
printTrace
(
'Failed to connect with
mDNS, falling back to log scanning
'
);
_logger
.
printTrace
(
'Failed to connect with
log scanning, falling back to mDNS
'
);
UsageEvent
(
UsageEvent
(
_kEventName
,
_kEventName
,
'
mdns
-failure'
,
'
log
-failure'
,
flutterUsage:
_flutterUsage
,
flutterUsage:
_flutterUsage
,
).
send
();
).
send
();
try
{
try
{
final
Uri
result
=
await
_protocolDiscovery
.
uri
;
final
Uri
result
=
await
_mDnsObservatoryDiscovery
.
getObservatoryUri
(
packageId
,
device
,
usesIpv6:
usesIpv6
,
hostVmservicePort:
hostVmservicePort
,
);
if
(
result
!=
null
)
{
if
(
result
!=
null
)
{
UsageEvent
(
UsageEvent
(
_kEventName
,
_kEventName
,
'
fallback
-success'
,
'
mdns
-success'
,
flutterUsage:
_flutterUsage
,
flutterUsage:
_flutterUsage
,
).
send
();
).
send
();
return
result
;
return
result
;
}
}
}
on
ArgumentError
{
// In the event of an invalid InternetAddress, this code attempts to catch
// an ArgumentError from protocol_discovery.dart
}
on
Exception
catch
(
err
)
{
}
on
Exception
catch
(
err
)
{
_logger
.
printTrace
(
err
.
toString
());
_logger
.
printTrace
(
err
.
toString
());
}
}
_logger
.
printTrace
(
'Failed to connect with
log scanning
'
);
_logger
.
printTrace
(
'Failed to connect with
mDNS
'
);
UsageEvent
(
UsageEvent
(
_kEventName
,
_kEventName
,
'
fallback
-failure'
,
'
mdns
-failure'
,
flutterUsage:
_flutterUsage
,
flutterUsage:
_flutterUsage
,
).
send
();
).
send
();
return
null
;
return
null
;
...
@@ -148,7 +148,7 @@ class FallbackDiscovery {
...
@@ -148,7 +148,7 @@ class FallbackDiscovery {
assumedWsUri
=
Uri
.
parse
(
'ws://localhost:
$hostPort
/ws'
);
assumedWsUri
=
Uri
.
parse
(
'ws://localhost:
$hostPort
/ws'
);
}
on
Exception
catch
(
err
)
{
}
on
Exception
catch
(
err
)
{
_logger
.
printTrace
(
err
.
toString
());
_logger
.
printTrace
(
err
.
toString
());
_logger
.
printTrace
(
'Failed to connect directly, falling back to
mDNS
'
);
_logger
.
printTrace
(
'Failed to connect directly, falling back to
log scanning
'
);
_sendFailureEvent
(
err
,
assumedDevicePort
);
_sendFailureEvent
(
err
,
assumedDevicePort
);
return
null
;
return
null
;
}
}
...
...
packages/flutter_tools/lib/src/ios/ios_deploy.dart
View file @
d5b715d7
This diff is collapsed.
Click to expand it.
packages/flutter_tools/lib/src/protocol_discovery.dart
View file @
d5b715d7
...
@@ -34,7 +34,7 @@ class ProtocolDiscovery {
...
@@ -34,7 +34,7 @@ class ProtocolDiscovery {
factory
ProtocolDiscovery
.
observatory
(
factory
ProtocolDiscovery
.
observatory
(
DeviceLogReader
logReader
,
{
DeviceLogReader
logReader
,
{
DevicePortForwarder
portForwarder
,
DevicePortForwarder
portForwarder
,
Duration
throttleDuration
=
const
Duration
(
milliseconds:
200
)
,
Duration
throttleDuration
,
Duration
throttleTimeout
,
Duration
throttleTimeout
,
@required
int
hostPort
,
@required
int
hostPort
,
@required
int
devicePort
,
@required
int
devicePort
,
...
@@ -45,7 +45,7 @@ class ProtocolDiscovery {
...
@@ -45,7 +45,7 @@ class ProtocolDiscovery {
logReader
,
logReader
,
kObservatoryService
,
kObservatoryService
,
portForwarder:
portForwarder
,
portForwarder:
portForwarder
,
throttleDuration:
throttleDuration
,
throttleDuration:
throttleDuration
??
const
Duration
(
milliseconds:
200
)
,
throttleTimeout:
throttleTimeout
,
throttleTimeout:
throttleTimeout
,
hostPort:
hostPort
,
hostPort:
hostPort
,
devicePort:
devicePort
,
devicePort:
devicePort
,
...
@@ -225,7 +225,7 @@ class _BufferedStreamController<T> {
...
@@ -225,7 +225,7 @@ class _BufferedStreamController<T> {
///
///
/// For example, consider a `waitDuration` of `10ms`, and list of event names
/// For example, consider a `waitDuration` of `10ms`, and list of event names
/// and arrival times: `a (0ms), b (5ms), c (11ms), d (21ms)`.
/// and arrival times: `a (0ms), b (5ms), c (11ms), d (21ms)`.
/// The events `
c`
and `d` will be produced as a result.
/// The events `
a`, `c`,
and `d` will be produced as a result.
StreamTransformer
<
S
,
S
>
_throttle
<
S
>({
StreamTransformer
<
S
,
S
>
_throttle
<
S
>({
@required
Duration
waitDuration
,
@required
Duration
waitDuration
,
})
{
})
{
...
@@ -240,10 +240,13 @@ StreamTransformer<S, S> _throttle<S>({
...
@@ -240,10 +240,13 @@ StreamTransformer<S, S> _throttle<S>({
handleData:
(
S
value
,
EventSink
<
S
>
sink
)
{
handleData:
(
S
value
,
EventSink
<
S
>
sink
)
{
latestLine
=
value
;
latestLine
=
value
;
final
bool
isFirstMessage
=
lastExecution
==
null
;
final
int
currentTime
=
DateTime
.
now
().
millisecondsSinceEpoch
;
final
int
currentTime
=
DateTime
.
now
().
millisecondsSinceEpoch
;
lastExecution
??=
currentTime
;
lastExecution
??=
currentTime
;
final
int
remainingTime
=
currentTime
-
lastExecution
;
final
int
remainingTime
=
currentTime
-
lastExecution
;
final
int
nextExecutionTime
=
remainingTime
>
waitDuration
.
inMilliseconds
// Always send the first event immediately.
final
int
nextExecutionTime
=
isFirstMessage
||
remainingTime
>
waitDuration
.
inMilliseconds
?
0
?
0
:
waitDuration
.
inMilliseconds
-
remainingTime
;
:
waitDuration
.
inMilliseconds
-
remainingTime
;
...
...
packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart
View file @
d5b715d7
This diff is collapsed.
Click to expand it.
packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart
View file @
d5b715d7
This diff is collapsed.
Click to expand it.
packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
View file @
d5b715d7
This diff is collapsed.
Click to expand it.
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