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
ef5ffd08
Unverified
Commit
ef5ffd08
authored
Jul 13, 2021
by
Darren Austin
Committed by
GitHub
Jul 13, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate devicelab framework code to null safety. (#86325)
(Attempt to reland #85993)
parent
43ed3b6b
Changes
28
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
406 additions
and
470 deletions
+406
-470
test.dart
dev/devicelab/lib/command/test.dart
+9
-11
upload_metrics.dart
dev/devicelab/lib/command/upload_metrics.dart
+2
-4
ab.dart
dev/devicelab/lib/framework/ab.dart
+20
-23
apk_utils.dart
dev/devicelab/lib/framework/apk_utils.dart
+19
-14
browser.dart
dev/devicelab/lib/framework/browser.dart
+61
-66
cocoon.dart
dev/devicelab/lib/framework/cocoon.dart
+24
-31
devices.dart
dev/devicelab/lib/framework/devices.dart
+60
-64
framework.dart
dev/devicelab/lib/framework/framework.dart
+15
-17
ios.dart
dev/devicelab/lib/framework/ios.dart
+5
-14
manifest.dart
dev/devicelab/lib/framework/manifest.dart
+11
-14
runner.dart
dev/devicelab/lib/framework/runner.dart
+20
-22
running_processes.dart
dev/devicelab/lib/framework/running_processes.dart
+9
-11
task_result.dart
dev/devicelab/lib/framework/task_result.dart
+6
-6
utils.dart
dev/devicelab/lib/framework/utils.dart
+44
-47
microbenchmarks.dart
dev/devicelab/lib/microbenchmarks.dart
+0
-2
analysis.dart
dev/devicelab/lib/tasks/analysis.dart
+0
-2
build_test_task.dart
dev/devicelab/lib/tasks/build_test_task.dart
+4
-7
dart_plugin_registry_tests.dart
dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart
+2
-4
gallery.dart
dev/devicelab/lib/tasks/gallery.dart
+4
-6
hot_mode_tests.dart
dev/devicelab/lib/tasks/hot_mode_tests.dart
+9
-11
integration_tests.dart
dev/devicelab/lib/tasks/integration_tests.dart
+0
-2
microbenchmarks.dart
dev/devicelab/lib/tasks/microbenchmarks.dart
+0
-2
new_gallery.dart
dev/devicelab/lib/tasks/new_gallery.dart
+0
-2
perf_tests.dart
dev/devicelab/lib/tasks/perf_tests.dart
+64
-61
platform_channels_benchmarks.dart
dev/devicelab/lib/tasks/platform_channels_benchmarks.dart
+0
-2
plugin_tests.dart
dev/devicelab/lib/tasks/plugin_tests.dart
+6
-8
web_benchmarks.dart
dev/devicelab/lib/tasks/web_benchmarks.dart
+12
-15
web_dev_mode_tests.dart
dev/devicelab/lib/tasks/web_dev_mode_tests.dart
+0
-2
No files found.
dev/devicelab/lib/command/test.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'package:args/command_runner.dart'
;
import
'package:flutter_devicelab/framework/runner.dart'
;
...
...
@@ -64,19 +62,19 @@ class TestCommand extends Command<void> {
@override
Future
<
void
>
run
()
async
{
final
List
<
String
>
taskArgsRaw
=
argResults
[
'task-args'
]
as
List
<
String
>;
final
List
<
String
>
taskArgsRaw
=
argResults
!
[
'task-args'
]
as
List
<
String
>;
// Prepend '--' to convert args to options when passed to task
final
List
<
String
>
taskArgs
=
taskArgsRaw
.
map
((
String
taskArg
)
=>
'--
$taskArg
'
).
toList
();
print
(
taskArgs
);
await
runTasks
(
<
String
>[
argResults
[
'task'
]
as
String
],
deviceId:
argResults
[
'device-id'
]
as
String
,
gitBranch:
argResults
[
'git-branch'
]
as
String
,
localEngine:
argResults
[
'local-engine'
]
as
String
,
localEngineSrcPath:
argResults
[
'local-engine-src-path'
]
as
String
,
luciBuilder:
argResults
[
'luci-builder'
]
as
String
,
resultsPath:
argResults
[
'results-file'
]
as
String
,
silent:
argResults
[
'silent'
]
as
bool
,
<
String
>[
argResults
!
[
'task'
]
as
String
],
deviceId:
argResults
![
'device-id'
]
as
String
?
,
gitBranch:
argResults
![
'git-branch'
]
as
String
?
,
localEngine:
argResults
![
'local-engine'
]
as
String
?
,
localEngineSrcPath:
argResults
![
'local-engine-src-path'
]
as
String
?
,
luciBuilder:
argResults
![
'luci-builder'
]
as
String
?
,
resultsPath:
argResults
![
'results-file'
]
as
String
?
,
silent:
(
argResults
![
'silent'
]
as
bool
?)
??
false
,
taskArgs:
taskArgs
,
);
}
...
...
dev/devicelab/lib/command/upload_metrics.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'package:args/command_runner.dart'
;
import
'../framework/cocoon.dart'
;
...
...
@@ -25,8 +23,8 @@ class UploadMetricsCommand extends Command<void> {
@override
Future
<
void
>
run
()
async
{
final
String
resultsPath
=
argResults
[
'results-file'
]
as
String
;
final
String
serviceAccountTokenFile
=
argResults
[
'service-account-token-file'
]
as
String
;
final
String
resultsPath
=
argResults
!
[
'results-file'
]
as
String
;
final
String
?
serviceAccountTokenFile
=
argResults
![
'service-account-token-file'
]
as
String
?
;
final
Cocoon
cocoon
=
Cocoon
(
serviceAccountTokenPath:
serviceAccountTokenFile
);
return
cocoon
.
sendResultsPath
(
resultsPath
);
...
...
dev/devicelab/lib/framework/ab.dart
View file @
ef5ffd08
...
...
@@ -2,10 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:math'
as
math
;
import
'package:meta/meta.dart'
;
import
'task_result.dart'
;
...
...
@@ -43,8 +40,8 @@ class ABTest {
final
String
localEngine
;
final
String
taskName
;
final
DateTime
runStart
;
DateTime
_runEnd
;
DateTime
get
runEnd
=>
_runEnd
;
DateTime
?
_runEnd
;
DateTime
?
get
runEnd
=>
_runEnd
;
final
Map
<
String
,
List
<
double
>>
_aResults
;
final
Map
<
String
,
List
<
double
>>
_bResults
;
...
...
@@ -91,15 +88,15 @@ class ABTest {
kLocalEngineKeyName:
localEngine
,
kTaskNameKeyName:
taskName
,
kRunStartKeyName:
runStart
.
toIso8601String
(),
kRunEndKeyName:
runEnd
.
toIso8601String
(),
kRunEndKeyName:
runEnd
!
.
toIso8601String
(),
kAResultsKeyName:
_aResults
,
kBResultsKeyName:
_bResults
,
};
static
void
updateColumnLengths
(
List
<
int
>
lengths
,
List
<
String
>
results
)
{
static
void
updateColumnLengths
(
List
<
int
>
lengths
,
List
<
String
?
>
results
)
{
for
(
int
column
=
0
;
column
<
lengths
.
length
;
column
++)
{
if
(
results
[
column
]
!=
null
)
{
lengths
[
column
]
=
math
.
max
(
lengths
[
column
],
results
[
column
]
.
length
);
lengths
[
column
]
=
math
.
max
(
lengths
[
column
],
results
[
column
]
?.
length
??
0
);
}
}
}
...
...
@@ -107,10 +104,10 @@ class ABTest {
static
void
formatResult
(
StringBuffer
buffer
,
List
<
int
>
lengths
,
List
<
FieldJustification
>
aligns
,
List
<
String
>
values
)
{
List
<
String
?
>
values
)
{
for
(
int
column
=
0
;
column
<
lengths
.
length
;
column
++)
{
final
int
len
=
lengths
[
column
];
String
value
=
values
[
column
];
String
?
value
=
values
[
column
];
if
(
value
==
null
)
{
value
=
''
.
padRight
(
len
);
}
else
{
...
...
@@ -142,9 +139,9 @@ class ABTest {
final
Map
<
String
,
_ScoreSummary
>
summariesA
=
_summarize
(
_aResults
);
final
Map
<
String
,
_ScoreSummary
>
summariesB
=
_summarize
(
_bResults
);
final
List
<
List
<
String
>>
tableRows
=
<
List
<
String
>>[
final
List
<
List
<
String
?>>
tableRows
=
<
List
<
String
?
>>[
for
(
final
String
scoreKey
in
<
String
>{...
summariesA
.
keys
,
...
summariesB
.
keys
})
<
String
>[
<
String
?
>[
scoreKey
,
summariesA
[
scoreKey
]?.
averageString
,
summariesA
[
scoreKey
]?.
noiseString
,
summariesB
[
scoreKey
]?.
averageString
,
summariesB
[
scoreKey
]?.
noiseString
,
...
...
@@ -167,7 +164,7 @@ class ABTest {
final
List
<
int
>
lengths
=
List
<
int
>.
filled
(
6
,
0
);
updateColumnLengths
(
lengths
,
titles
);
for
(
final
List
<
String
>
row
in
tableRows
)
{
for
(
final
List
<
String
?
>
row
in
tableRows
)
{
updateColumnLengths
(
lengths
,
row
);
}
...
...
@@ -177,7 +174,7 @@ class ABTest {
FieldJustification
.
CENTER
,
...
alignments
.
skip
(
1
),
],
titles
);
for
(
final
List
<
String
>
row
in
tableRows
)
{
for
(
final
List
<
String
?
>
row
in
tableRows
)
{
formatResult
(
buffer
,
lengths
,
alignments
,
row
);
}
...
...
@@ -192,7 +189,7 @@ class ABTest {
buffer
.
writeln
(
'
$scoreKey
:'
);
buffer
.
write
(
' A:
\t
'
);
if
(
_aResults
.
containsKey
(
scoreKey
))
{
for
(
final
double
score
in
_aResults
[
scoreKey
])
{
for
(
final
double
score
in
_aResults
[
scoreKey
]
!
)
{
buffer
.
write
(
'
${score.toStringAsFixed(2)}
\t
'
);
}
}
else
{
...
...
@@ -202,7 +199,7 @@ class ABTest {
buffer
.
write
(
' B:
\t
'
);
if
(
_bResults
.
containsKey
(
scoreKey
))
{
for
(
final
double
score
in
_bResults
[
scoreKey
])
{
for
(
final
double
score
in
_bResults
[
scoreKey
]
!
)
{
buffer
.
write
(
'
${score.toStringAsFixed(2)}
\t
'
);
}
}
else
{
...
...
@@ -232,8 +229,8 @@ class ABTest {
);
for
(
final
String
scoreKey
in
_allScoreKeys
)
{
final
_ScoreSummary
summaryA
=
summariesA
[
scoreKey
];
final
_ScoreSummary
summaryB
=
summariesB
[
scoreKey
];
final
_ScoreSummary
?
summaryA
=
summariesA
[
scoreKey
];
final
_ScoreSummary
?
summaryB
=
summariesB
[
scoreKey
];
buffer
.
write
(
'
$scoreKey
\t
'
);
if
(
summaryA
!=
null
)
{
...
...
@@ -261,8 +258,8 @@ class ABTest {
class
_ScoreSummary
{
_ScoreSummary
({
@
required
this
.
average
,
@
required
this
.
noise
,
required
this
.
average
,
required
this
.
noise
,
});
/// Average (arithmetic mean) of a series of values collected by a benchmark.
...
...
@@ -275,14 +272,14 @@ class _ScoreSummary {
String
get
averageString
=>
average
.
toStringAsFixed
(
2
);
String
get
noiseString
=>
'(
${_ratioToPercent(noise)}
)'
;
String
improvementOver
(
_ScoreSummary
other
)
{
String
improvementOver
(
_ScoreSummary
?
other
)
{
return
other
==
null
?
''
:
'
${(average / other.average).toStringAsFixed(2)}
x'
;
}
}
void
_addResult
(
TaskResult
result
,
Map
<
String
,
List
<
double
>>
results
)
{
for
(
final
String
scoreKey
in
result
.
benchmarkScoreKeys
)
{
final
double
score
=
(
result
.
data
[
scoreKey
]
as
num
).
toDouble
();
for
(
final
String
scoreKey
in
result
.
benchmarkScoreKeys
??
<
String
>[]
)
{
final
double
score
=
(
result
.
data
!
[
scoreKey
]
as
num
).
toDouble
();
results
.
putIfAbsent
(
scoreKey
,
()
=>
<
double
>[]).
add
(
score
);
}
}
...
...
dev/devicelab/lib/framework/apk_utils.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:path/path.dart'
as
path
;
...
...
@@ -106,7 +104,7 @@ bool hasMultipleOccurrences(String text, Pattern pattern) {
/// The Android home directory.
String
get
_androidHome
{
final
String
androidHome
=
Platform
.
environment
[
'ANDROID_HOME'
]
??
final
String
?
androidHome
=
Platform
.
environment
[
'ANDROID_HOME'
]
??
Platform
.
environment
[
'ANDROID_SDK_ROOT'
];
if
(
androidHome
==
null
||
androidHome
.
isEmpty
)
{
throw
Exception
(
'Environment variable `ANDROID_SDK_ROOT` is not set.'
);
...
...
@@ -118,9 +116,9 @@ String get _androidHome {
Future
<
String
>
_evalApkAnalyzer
(
List
<
String
>
args
,
{
bool
printStdout
=
false
,
String
workingDirectory
,
String
?
workingDirectory
,
})
async
{
final
String
javaHome
=
await
findJavaHome
();
final
String
?
javaHome
=
await
findJavaHome
();
if
(
javaHome
==
null
||
javaHome
.
isEmpty
)
{
throw
Exception
(
'No JAVA_HOME set.'
);
}
...
...
@@ -259,7 +257,7 @@ class FlutterProject {
String
get
androidPath
=>
path
.
join
(
rootPath
,
'android'
);
String
get
iosPath
=>
path
.
join
(
rootPath
,
'ios'
);
Future
<
void
>
addCustomBuildType
(
String
name
,
{
String
initWith
})
async
{
Future
<
void
>
addCustomBuildType
(
String
name
,
{
required
String
initWith
})
async
{
final
File
buildScript
=
File
(
path
.
join
(
androidPath
,
'app'
,
'build.gradle'
),
);
...
...
@@ -276,7 +274,7 @@ android {
'''
);
}
Future
<
void
>
addGlobalBuildType
(
String
name
,
{
String
initWith
})
async
{
Future
<
void
>
addGlobalBuildType
(
String
name
,
{
required
String
initWith
})
async
{
final
File
buildScript
=
File
(
path
.
join
(
androidPath
,
'build.gradle'
),
);
...
...
@@ -360,11 +358,11 @@ flutter:
pubspec
.
writeAsStringSync
(
newContents
);
}
Future
<
void
>
runGradleTask
(
String
task
,
{
List
<
String
>
options
})
async
{
Future
<
void
>
runGradleTask
(
String
task
,
{
List
<
String
>
?
options
})
async
{
return
_runGradleTask
(
workingDirectory:
androidPath
,
task:
task
,
options:
options
);
}
Future
<
ProcessResult
>
resultOfGradleTask
(
String
task
,
{
List
<
String
>
options
})
{
Future
<
ProcessResult
>
resultOfGradleTask
(
String
task
,
{
List
<
String
>
?
options
})
{
return
_resultOfGradleTask
(
workingDirectory:
androidPath
,
task:
task
,
options:
options
);
}
...
...
@@ -416,7 +414,11 @@ class FlutterModuleProject {
String
get
rootPath
=>
path
.
join
(
parent
.
path
,
name
);
}
Future
<
void
>
_runGradleTask
({
String
workingDirectory
,
String
task
,
List
<
String
>
options
})
async
{
Future
<
void
>
_runGradleTask
({
required
String
workingDirectory
,
required
String
task
,
List
<
String
>?
options
,
})
async
{
final
ProcessResult
result
=
await
_resultOfGradleTask
(
workingDirectory:
workingDirectory
,
task:
task
,
...
...
@@ -431,10 +433,13 @@ Future<void> _runGradleTask({String workingDirectory, String task, List<String>
throw
'Gradle exited with error'
;
}
Future
<
ProcessResult
>
_resultOfGradleTask
({
String
workingDirectory
,
String
task
,
List
<
String
>
options
})
async
{
Future
<
ProcessResult
>
_resultOfGradleTask
({
required
String
workingDirectory
,
required
String
task
,
List
<
String
>?
options
,
})
async
{
section
(
'Find Java'
);
final
String
javaHome
=
await
findJavaHome
();
final
String
?
javaHome
=
await
findJavaHome
();
if
(
javaHome
==
null
)
throw
TaskResult
.
failure
(
'Could not find Java'
);
...
...
@@ -465,7 +470,7 @@ Future<ProcessResult> _resultOfGradleTask({String workingDirectory, String task,
}
/// Returns [null] if target matches [expectedTarget], otherwise returns an error message.
String
validateSnapshotDependency
(
FlutterProject
project
,
String
expectedTarget
)
{
String
?
validateSnapshotDependency
(
FlutterProject
project
,
String
expectedTarget
)
{
final
File
snapshotBlob
=
File
(
path
.
join
(
project
.
rootPath
,
'build'
,
'app'
,
'intermediates'
,
'flutter'
,
'debug'
,
'flutter_build.d'
));
...
...
dev/devicelab/lib/framework/browser.dart
View file @
ef5ffd08
...
...
@@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
show
json
,
utf8
,
LineSplitter
,
JsonEncoder
;
import
'dart:io'
as
io
;
import
'dart:math'
as
math
;
import
'package:flutter_devicelab/common.dart'
;
import
'package:meta/meta.dart'
;
import
'package:path/path.dart'
as
path
;
import
'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
;
...
...
@@ -32,10 +29,10 @@ class ChromeOptions {
});
/// If not null passed as `--user-data-dir`.
final
String
userDataDirectory
;
final
String
?
userDataDirectory
;
/// If not null launches a Chrome tab at this URL.
final
String
url
;
final
String
?
url
;
/// The width of the Chrome window.
///
...
...
@@ -49,14 +46,14 @@ class ChromeOptions {
/// Launches code in "headless" mode, which allows running Chrome in
/// environments without a display, such as LUCI and Cirrus.
final
bool
headless
;
final
bool
?
headless
;
/// The port Chrome will use for its debugging protocol.
///
/// If null, Chrome is launched without debugging. When running in headless
/// mode without a debug port, Chrome quits immediately. For most tests it is
/// typical to set [headless] to true and set a non-null debug port.
final
int
debugPort
;
final
int
?
debugPort
;
}
/// A function called when the Chrome process encounters an error.
...
...
@@ -79,7 +76,7 @@ class Chrome {
/// The [onError] callback is called with an error message when the Chrome
/// process encounters an error. In particular, [onError] is called when the
/// Chrome process exits prematurely, i.e. before [stop] is called.
static
Future
<
Chrome
>
launch
(
ChromeOptions
options
,
{
String
workingDirectory
,
@
required
ChromeErrorCallback
onError
})
async
{
static
Future
<
Chrome
>
launch
(
ChromeOptions
options
,
{
String
?
workingDirectory
,
required
ChromeErrorCallback
onError
})
async
{
if
(!
io
.
Platform
.
isWindows
)
{
final
io
.
ProcessResult
versionResult
=
io
.
Process
.
runSync
(
_findSystemChromeExecutable
(),
const
<
String
>[
'--version'
]);
print
(
'Launching
${versionResult.stdout}
'
);
...
...
@@ -92,10 +89,10 @@ class Chrome {
if
(
options
.
userDataDirectory
!=
null
)
'--user-data-dir=
${options.userDataDirectory}
'
,
if
(
options
.
url
!=
null
)
options
.
url
,
options
.
url
!
,
if
(
io
.
Platform
.
environment
[
'CHROME_NO_SANDBOX'
]
==
'true'
)
'--no-sandbox'
,
if
(
options
.
headless
)
if
(
options
.
headless
==
true
)
'--headless'
,
if
(
withDebugging
)
'--remote-debugging-port=
${options.debugPort}
'
,
...
...
@@ -116,9 +113,9 @@ class Chrome {
workingDirectory:
workingDirectory
,
);
WipConnection
debugConnection
;
WipConnection
?
debugConnection
;
if
(
withDebugging
)
{
debugConnection
=
await
_connectToChromeDebugPort
(
chromeProcess
,
options
.
debugPort
);
debugConnection
=
await
_connectToChromeDebugPort
(
chromeProcess
,
options
.
debugPort
!
);
}
return
Chrome
.
_
(
chromeProcess
,
onError
,
debugConnection
);
...
...
@@ -126,12 +123,12 @@ class Chrome {
final
io
.
Process
_chromeProcess
;
final
ChromeErrorCallback
_onError
;
final
WipConnection
_debugConnection
;
final
WipConnection
?
_debugConnection
;
bool
_isStopped
=
false
;
Completer
<
void
>
_tracingCompleter
;
StreamSubscription
<
WipEvent
>
_tracingSubscription
;
List
<
Map
<
String
,
dynamic
>>
_tracingData
;
Completer
<
void
>
?
_tracingCompleter
;
StreamSubscription
<
WipEvent
>
?
_tracingSubscription
;
List
<
Map
<
String
,
dynamic
>>
?
_tracingData
;
/// Starts recording a performance trace.
///
...
...
@@ -151,24 +148,24 @@ class Chrome {
// Subscribe to tracing events prior to calling "Tracing.start". Otherwise,
// we'll miss tracing data.
_tracingSubscription
=
_debugConnection
.
onNotification
.
listen
((
WipEvent
event
)
{
_tracingSubscription
=
_debugConnection
?
.
onNotification
.
listen
((
WipEvent
event
)
{
// We receive data as a sequence of "Tracing.dataCollected" followed by
// "Tracing.tracingComplete" at the end. Until "Tracing.tracingComplete"
// is received, the data may be incomplete.
if
(
event
.
method
==
'Tracing.tracingComplete'
)
{
_tracingCompleter
.
complete
();
_tracingSubscription
.
cancel
();
_tracingCompleter
!
.
complete
();
_tracingSubscription
!
.
cancel
();
_tracingSubscription
=
null
;
}
else
if
(
event
.
method
==
'Tracing.dataCollected'
)
{
final
dynamic
value
=
event
.
params
[
'value'
];
final
dynamic
value
=
event
.
params
?
[
'value'
];
if
(
value
is
!
List
)
{
throw
FormatException
(
'"Tracing.dataCollected" returned malformed data. '
'Expected a List but got:
${value.runtimeType}
'
);
}
_tracingData
.
addAll
((
event
.
params
[
'value'
]
as
List
<
dynamic
>).
cast
<
Map
<
String
,
dynamic
>>());
_tracingData
?.
addAll
((
event
.
params
?
[
'value'
]
as
List
<
dynamic
>).
cast
<
Map
<
String
,
dynamic
>>());
}
});
await
_debugConnection
.
sendCommand
(
'Tracing.start'
,
<
String
,
dynamic
>{
await
_debugConnection
?
.
sendCommand
(
'Tracing.start'
,
<
String
,
dynamic
>{
// The choice of categories is as follows:
//
// blink:
...
...
@@ -190,22 +187,23 @@ class Chrome {
/// Stops a performance tracing session started by [beginRecordingPerformance].
///
/// Returns all the collected tracing data unfiltered.
Future
<
List
<
Map
<
String
,
dynamic
>>>
endRecordingPerformance
()
async
{
await
_debugConnection
.
sendCommand
(
'Tracing.end'
);
await
_tracingCompleter
.
future
;
final
List
<
Map
<
String
,
dynamic
>>
data
=
_tracingData
;
Future
<
List
<
Map
<
String
,
dynamic
>>
?
>
endRecordingPerformance
()
async
{
await
_debugConnection
!
.
sendCommand
(
'Tracing.end'
);
await
_tracingCompleter
!
.
future
;
final
List
<
Map
<
String
,
dynamic
>>
?
data
=
_tracingData
;
_tracingCompleter
=
null
;
_tracingData
=
null
;
return
data
;
}
Future
<
void
>
reloadPage
({
bool
ignoreCache
=
false
})
async
{
await
_debugConnection
.
page
.
reload
(
ignoreCache:
ignoreCache
);
await
_debugConnection
?
.
page
.
reload
(
ignoreCache:
ignoreCache
);
}
/// Stops the Chrome process.
void
stop
()
{
_isStopped
=
true
;
_tracingSubscription
?.
cancel
();
_chromeProcess
.
kill
();
}
}
...
...
@@ -214,7 +212,7 @@ String _findSystemChromeExecutable() {
// On some environments, such as the Dart HHH tester, Chrome resides in a
// non-standard location and is provided via the following environment
// variable.
final
String
envExecutable
=
io
.
Platform
.
environment
[
'CHROME_EXECUTABLE'
];
final
String
?
envExecutable
=
io
.
Platform
.
environment
[
'CHROME_EXECUTABLE'
];
if
(
envExecutable
!=
null
)
{
return
envExecutable
;
}
...
...
@@ -232,15 +230,12 @@ String _findSystemChromeExecutable() {
return
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
;
}
else
if
(
io
.
Platform
.
isWindows
)
{
const
String
kWindowsExecutable
=
r'Google\Chrome\Application\chrome.exe'
;
final
List
<
String
>
kWindowsPrefixes
=
<
String
>[
final
List
<
String
>
kWindowsPrefixes
=
<
String
?
>[
io
.
Platform
.
environment
[
'LOCALAPPDATA'
],
io
.
Platform
.
environment
[
'PROGRAMFILES'
],
io
.
Platform
.
environment
[
'PROGRAMFILES(X86)'
],
];
]
.
whereType
<
String
>().
toList
()
;
final
String
windowsPrefix
=
kWindowsPrefixes
.
firstWhere
((
String
prefix
)
{
if
(
prefix
==
null
)
{
return
false
;
}
final
String
expectedPath
=
path
.
join
(
prefix
,
kWindowsExecutable
);
return
io
.
File
(
expectedPath
).
existsSync
();
},
orElse:
()
=>
'.'
);
...
...
@@ -269,7 +264,7 @@ Future<Uri> _getRemoteDebuggerUrl(Uri base) async {
final
io
.
HttpClient
client
=
io
.
HttpClient
();
final
io
.
HttpClientRequest
request
=
await
client
.
getUrl
(
base
.
resolve
(
'/json/list'
));
final
io
.
HttpClientResponse
response
=
await
request
.
close
();
final
List
<
dynamic
>
jsonObject
=
await
json
.
fuse
(
utf8
).
decoder
.
bind
(
response
).
single
as
List
<
dynamic
>
;
final
List
<
dynamic
>
?
jsonObject
=
await
json
.
fuse
(
utf8
).
decoder
.
bind
(
response
).
single
as
List
<
dynamic
>?
;
if
(
jsonObject
==
null
||
jsonObject
.
isEmpty
)
{
return
base
;
}
...
...
@@ -279,17 +274,17 @@ Future<Uri> _getRemoteDebuggerUrl(Uri base) async {
/// Summarizes a Blink trace down to a few interesting values.
class
BlinkTraceSummary
{
BlinkTraceSummary
.
_
({
@
required
this
.
averageBeginFrameTime
,
@
required
this
.
averageUpdateLifecyclePhasesTime
,
required
this
.
averageBeginFrameTime
,
required
this
.
averageUpdateLifecyclePhasesTime
,
})
:
averageTotalUIFrameTime
=
averageBeginFrameTime
+
averageUpdateLifecyclePhasesTime
;
static
BlinkTraceSummary
fromJson
(
List
<
Map
<
String
,
dynamic
>>
traceJson
)
{
static
BlinkTraceSummary
?
fromJson
(
List
<
Map
<
String
,
dynamic
>>
traceJson
)
{
try
{
// Convert raw JSON data to BlinkTraceEvent objects sorted by timestamp.
List
<
BlinkTraceEvent
>
events
=
traceJson
.
map
<
BlinkTraceEvent
>(
BlinkTraceEvent
.
fromJson
)
.
toList
()
..
sort
((
BlinkTraceEvent
a
,
BlinkTraceEvent
b
)
=>
a
.
ts
-
b
.
ts
);
..
sort
((
BlinkTraceEvent
a
,
BlinkTraceEvent
b
)
=>
a
.
ts
!
-
b
.
ts
!
);
Exception
noMeasuredFramesFound
()
=>
Exception
(
'No measured frames found in benchmark tracing data. This likely '
...
...
@@ -316,7 +311,7 @@ class BlinkTraceSummary {
return
null
;
}
final
int
tabPid
=
firstMeasuredFrameEvent
.
pid
;
final
int
tabPid
=
firstMeasuredFrameEvent
.
pid
!
;
// Filter out data from unrelated processes
events
=
events
.
where
((
BlinkTraceEvent
element
)
=>
element
.
pid
==
tabPid
).
toList
();
...
...
@@ -352,8 +347,8 @@ class BlinkTraceSummary {
// Compute averages and summarize.
return
BlinkTraceSummary
.
_
(
averageBeginFrameTime:
_computeAverageDuration
(
frames
.
map
((
BlinkFrame
frame
)
=>
frame
.
beginFrame
).
toList
()),
averageUpdateLifecyclePhasesTime:
_computeAverageDuration
(
frames
.
map
((
BlinkFrame
frame
)
=>
frame
.
updateAllLifecyclePhases
).
toList
()),
averageBeginFrameTime:
_computeAverageDuration
(
frames
.
map
((
BlinkFrame
frame
)
=>
frame
.
beginFrame
).
whereType
<
BlinkTraceEvent
>().
toList
()),
averageUpdateLifecyclePhasesTime:
_computeAverageDuration
(
frames
.
map
((
BlinkFrame
frame
)
=>
frame
.
updateAllLifecyclePhases
).
whereType
<
BlinkTraceEvent
>().
toList
()),
);
}
catch
(
_
,
__
)
{
final
io
.
File
traceFile
=
io
.
File
(
'./chrome-trace.json'
);
...
...
@@ -392,16 +387,16 @@ class BlinkTraceSummary {
/// Contains events pertaining to a single frame in the Blink trace data.
class
BlinkFrame
{
/// Corresponds to 'WebViewImpl::beginFrame' event.
BlinkTraceEvent
beginFrame
;
BlinkTraceEvent
?
beginFrame
;
/// Corresponds to 'WebViewImpl::updateAllLifecyclePhases' event.
BlinkTraceEvent
updateAllLifecyclePhases
;
BlinkTraceEvent
?
updateAllLifecyclePhases
;
/// Corresponds to 'measured_frame' begin event.
BlinkTraceEvent
beginMeasuredFrame
;
BlinkTraceEvent
?
beginMeasuredFrame
;
/// Corresponds to 'measured_frame' end event.
BlinkTraceEvent
endMeasuredFrame
;
BlinkTraceEvent
?
endMeasuredFrame
;
}
/// Takes a list of events that have non-null [BlinkTraceEvent.tdur] computes
...
...
@@ -414,7 +409,7 @@ Duration _computeAverageDuration(List<BlinkTraceEvent> events) {
if
(
event
.
tdur
==
null
)
{
throw
FormatException
(
'Trace event lacks "tdur" field:
$event
'
);
}
return
previousValue
+
event
.
tdur
;
return
previousValue
+
event
.
tdur
!
;
});
final
int
sampleCount
=
math
.
min
(
events
.
length
,
_kMeasuredSampleCount
);
return
Duration
(
microseconds:
sum
~/
sampleCount
);
...
...
@@ -426,15 +421,15 @@ Duration _computeAverageDuration(List<BlinkTraceEvent> events) {
/// * https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
class
BlinkTraceEvent
{
BlinkTraceEvent
.
_
({
@
required
this
.
args
,
@
required
this
.
cat
,
@
required
this
.
name
,
@
required
this
.
ph
,
@required
this
.
pid
,
@required
this
.
tid
,
@required
this
.
ts
,
@required
this
.
tts
,
@required
this
.
tdur
,
required
this
.
args
,
required
this
.
cat
,
required
this
.
name
,
required
this
.
ph
,
this
.
pid
,
this
.
tid
,
this
.
ts
,
this
.
tts
,
this
.
tdur
,
});
/// Parses an event from its JSON representation.
...
...
@@ -488,19 +483,19 @@ class BlinkTraceEvent {
final
String
ph
;
/// Process ID of the process that emitted the event.
final
int
pid
;
final
int
?
pid
;
/// Thread ID of the thread that emitted the event.
final
int
tid
;
final
int
?
tid
;
/// Timestamp in microseconds using tracer clock.
final
int
ts
;
final
int
?
ts
;
/// Timestamp in microseconds using thread clock.
final
int
tts
;
final
int
?
tts
;
/// Event duration in microseconds.
final
int
tdur
;
final
int
?
tdur
;
/// A "begin frame" event contains all of the scripting time of an animation
/// frame (JavaScript, WebAssembly), plus a negligible amount of internal
...
...
@@ -556,8 +551,8 @@ class BlinkTraceEvent {
/// validation and conversion is needed.
///
/// Returns null if the value is null.
int
_readInt
(
Map
<
String
,
dynamic
>
json
,
String
key
)
{
final
num
jsonValue
=
json
[
key
]
as
num
;
int
?
_readInt
(
Map
<
String
,
dynamic
>
json
,
String
key
)
{
final
num
?
jsonValue
=
json
[
key
]
as
num
?
;
if
(
jsonValue
==
null
)
{
return
null
;
...
...
@@ -578,10 +573,10 @@ int _readInt(Map<String, dynamic> json, String key) {
/// Inconsistency detected by ld.so: ../elf/dl-tls.c: 493: _dl_allocate_tls_init: Assertion `listp->slotinfo[cnt].gen <= GL(dl_tls_generation)' failed!
const
String
_kGlibcError
=
'Inconsistency detected by ld.so'
;
Future
<
io
.
Process
>
_spawnChromiumProcess
(
String
executable
,
List
<
String
>
args
,
{
String
workingDirectory
})
async
{
Future
<
io
.
Process
>
_spawnChromiumProcess
(
String
executable
,
List
<
String
>
args
,
{
String
?
workingDirectory
})
async
{
// Keep attempting to launch the browser until one of:
// - Chrome launched successfully, in which case we just return from the loop.
// - The tool detected an unretr
i
able Chrome error, in which case we throw ToolExit.
// - The tool detected an unretr
y
able Chrome error, in which case we throw ToolExit.
while
(
true
)
{
final
io
.
Process
process
=
await
io
.
Process
.
start
(
executable
,
args
,
workingDirectory:
workingDirectory
);
...
...
@@ -611,7 +606,7 @@ Future<io.Process> _spawnChromiumProcess(String executable, List<String> args, {
'Encountered glibc bug https://sourceware.org/bugzilla/show_bug.cgi?id=19329. '
'Will try launching browser again.'
,
);
return
null
;
return
''
;
}
print
(
'Failed to launch browser. Command used to launch it:
${args.join(' ')}
'
);
throw
Exception
(
...
...
@@ -630,7 +625,7 @@ Future<io.Process> _spawnChromiumProcess(String executable, List<String> args, {
// launching more processes.
unawaited
(
process
.
exitCode
.
timeout
(
const
Duration
(
seconds:
1
),
onTimeout:
()
{
process
.
kill
();
return
null
;
return
0
;
}));
}
}
dev/devicelab/lib/framework/cocoon.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
show
Encoding
,
json
;
import
'dart:io'
;
...
...
@@ -20,12 +18,12 @@ import 'utils.dart';
typedef
ProcessRunSync
=
ProcessResult
Function
(
String
,
List
<
String
>,
{
Map
<
String
,
String
>
environment
,
Map
<
String
,
String
>
?
environment
,
bool
includeParentEnvironment
,
bool
runInShell
,
Encoding
stderrEncoding
,
Encoding
stdoutEncoding
,
String
workingDirectory
,
Encoding
?
stderrEncoding
,
Encoding
?
stdoutEncoding
,
String
?
workingDirectory
,
});
/// Class for test runner to interact with Flutter's infrastructure service, Cocoon.
...
...
@@ -34,8 +32,8 @@ typedef ProcessRunSync = ProcessResult Function(
/// To retrieve these results, the test runner needs to send results back so the database can be updated.
class
Cocoon
{
Cocoon
({
String
serviceAccountTokenPath
,
@visibleForTesting
Client
httpClient
,
String
?
serviceAccountTokenPath
,
@visibleForTesting
Client
?
httpClient
,
@visibleForTesting
this
.
fs
=
const
LocalFileSystem
(),
@visibleForTesting
this
.
processRunSync
=
Process
.
runSync
,
@visibleForTesting
this
.
requestRetryLimit
=
5
,
...
...
@@ -58,7 +56,7 @@ class Cocoon {
final
int
requestRetryLimit
;
String
get
commitSha
=>
_commitSha
??
_readCommitSha
();
String
_commitSha
;
String
?
_commitSha
;
/// Parse the local repo for the current running commit.
String
_readCommitSha
()
{
...
...
@@ -85,9 +83,9 @@ class Cocoon {
/// Send [TaskResult] to Cocoon.
// TODO(chillers): Remove when sendResultsPath is used in prod. https://github.com/flutter/flutter/issues/72457
Future
<
void
>
sendTaskResult
({
@
required
String
builderName
,
@
required
TaskResult
result
,
@
required
String
gitBranch
,
required
String
builderName
,
required
TaskResult
result
,
required
String
gitBranch
,
})
async
{
assert
(
builderName
!=
null
);
assert
(
gitBranch
!=
null
);
...
...
@@ -109,16 +107,11 @@ class Cocoon {
/// Write the given parameters into an update task request and store the JSON in [resultsPath].
Future
<
void
>
writeTaskResultToFile
({
@required
String
builderName
,
@required
String
gitBranch
,
@
required
TaskResult
result
,
@
required
String
resultsPath
,
String
?
builderName
,
String
?
gitBranch
,
required
TaskResult
result
,
required
String
resultsPath
,
})
async
{
assert
(
builderName
!=
null
);
assert
(
gitBranch
!=
null
);
assert
(
result
!=
null
);
assert
(
resultsPath
!=
null
);
final
Map
<
String
,
dynamic
>
updateRequest
=
_constructUpdateRequest
(
gitBranch:
gitBranch
,
builderName:
builderName
,
...
...
@@ -134,9 +127,9 @@ class Cocoon {
}
Map
<
String
,
dynamic
>
_constructUpdateRequest
({
@required
String
builderName
,
@
required
TaskResult
result
,
@required
String
gitBranch
,
String
?
builderName
,
required
TaskResult
result
,
String
?
gitBranch
,
})
{
final
Map
<
String
,
dynamic
>
updateRequest
=
<
String
,
dynamic
>{
'CommitBranch'
:
gitBranch
,
...
...
@@ -151,12 +144,12 @@ class Cocoon {
final
List
<
String
>
validScoreKeys
=
<
String
>[];
if
(
result
.
benchmarkScoreKeys
!=
null
)
{
for
(
final
String
scoreKey
in
result
.
benchmarkScoreKeys
)
{
final
Object
score
=
result
.
data
[
scoreKey
]
;
for
(
final
String
scoreKey
in
result
.
benchmarkScoreKeys
!
)
{
final
Object
score
=
result
.
data
![
scoreKey
]
as
Object
;
if
(
score
is
num
)
{
// Convert all metrics to double, which provide plenty of precision
// without having to add support for multiple numeric types in Cocoon.
result
.
data
[
scoreKey
]
=
score
.
toDouble
();
result
.
data
!
[
scoreKey
]
=
score
.
toDouble
();
validScoreKeys
.
add
(
scoreKey
);
}
}
...
...
@@ -195,15 +188,15 @@ class Cocoon {
class
AuthenticatedCocoonClient
extends
BaseClient
{
AuthenticatedCocoonClient
(
this
.
_serviceAccountTokenPath
,
{
@visibleForTesting
Client
httpClient
,
@visibleForTesting
FileSystem
filesystem
,
@visibleForTesting
Client
?
httpClient
,
@visibleForTesting
FileSystem
?
filesystem
,
})
:
_delegate
=
httpClient
??
Client
(),
_fs
=
filesystem
??
const
LocalFileSystem
();
/// Authentication token to have the ability to upload and record test results.
///
/// This is intended to only be passed on automated runs on LUCI post-submit.
final
String
_serviceAccountTokenPath
;
final
String
?
_serviceAccountTokenPath
;
/// Underlying [HttpClient] to send requests to.
final
Client
_delegate
;
...
...
@@ -213,7 +206,7 @@ class AuthenticatedCocoonClient extends BaseClient {
/// Value contained in the service account token file that can be used in http requests.
String
get
serviceAccountToken
=>
_serviceAccountToken
??
_readServiceAccountTokenFile
();
String
_serviceAccountToken
;
String
?
_serviceAccountToken
;
/// Get [serviceAccountToken] from the given service account file.
String
_readServiceAccountTokenFile
()
{
...
...
dev/devicelab/lib/framework/devices.dart
View file @
ef5ffd08
...
...
@@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
import
'dart:math'
as
math
;
import
'package:flutter_devicelab/common.dart'
;
import
'package:meta/meta.dart'
;
import
'package:path/path.dart'
as
path
;
import
'utils.dart'
;
...
...
@@ -37,8 +34,8 @@ String getArtifactPath() {
}
/// Return the item is in idList if find a match, otherwise return null
String
_findMatchId
(
List
<
String
>
idList
,
String
idPattern
)
{
String
candidate
;
String
?
_findMatchId
(
List
<
String
>
idList
,
String
idPattern
)
{
String
?
candidate
;
idPattern
=
idPattern
.
toLowerCase
();
for
(
final
String
id
in
idList
)
{
if
(
id
.
toLowerCase
()
==
idPattern
)
{
...
...
@@ -184,47 +181,46 @@ enum AndroidCPU {
}
class
AndroidDeviceDiscovery
implements
DeviceDiscovery
{
factory
AndroidDeviceDiscovery
({
AndroidCPU
cpu
})
{
factory
AndroidDeviceDiscovery
({
AndroidCPU
?
cpu
})
{
return
_instance
??=
AndroidDeviceDiscovery
.
_
(
cpu
);
}
AndroidDeviceDiscovery
.
_
(
this
.
cpu
);
final
AndroidCPU
cpu
;
final
AndroidCPU
?
cpu
;
// Parses information about a device. Example:
//
// 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper
static
final
RegExp
_kDeviceRegex
=
RegExp
(
r'^(\S+)\s+(\S+)(.*)'
);
static
AndroidDeviceDiscovery
_instance
;
static
AndroidDeviceDiscovery
?
_instance
;
AndroidDevice
_workingDevice
;
AndroidDevice
?
_workingDevice
;
@override
Future
<
AndroidDevice
>
get
workingDevice
async
{
if
(
_workingDevice
==
null
)
{
if
(
Platform
.
environment
.
containsKey
(
DeviceIdEnvName
))
{
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
];
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
]
!
;
await
chooseWorkingDeviceById
(
deviceId
);
return
_workingDevice
;
return
_workingDevice
!
;
}
await
chooseWorkingDevice
();
}
return
_workingDevice
;
return
_workingDevice
!
;
}
Future
<
bool
>
_matchesCPURequirement
(
AndroidDevice
device
)
async
{
if
(
cpu
==
null
)
return
true
;
switch
(
cpu
)
{
case
null
:
return
true
;
case
AndroidCPU
.
arm64
:
return
device
.
isArm64
();
case
AndroidCPU
.
arm
:
return
device
.
isArm
();
}
return
true
;
}
/// Picks a random Android device out of connected devices and sets it as
...
...
@@ -259,11 +255,11 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
@override
Future
<
void
>
chooseWorkingDeviceById
(
String
deviceId
)
async
{
final
String
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
final
String
?
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
if
(
matchedId
!=
null
)
{
_workingDevice
=
AndroidDevice
(
deviceId:
matchedId
);
if
(
cpu
!=
null
)
{
if
(!
await
_matchesCPURequirement
(
_workingDevice
))
{
if
(!
await
_matchesCPURequirement
(
_workingDevice
!
))
{
throw
DeviceException
(
'The selected device
$matchedId
does not match the cpu requirement'
);
}
}
...
...
@@ -290,10 +286,10 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
continue
;
if
(
_kDeviceRegex
.
hasMatch
(
line
))
{
final
Match
match
=
_kDeviceRegex
.
firstMatch
(
line
);
final
Match
match
=
_kDeviceRegex
.
firstMatch
(
line
)
!
;
final
String
deviceID
=
match
[
1
];
final
String
deviceState
=
match
[
2
];
final
String
deviceID
=
match
[
1
]
!
;
final
String
deviceState
=
match
[
2
]
!
;
if
(!
const
<
String
>[
'unauthorized'
,
'offline'
].
contains
(
deviceState
))
{
results
.
add
(
deviceID
);
...
...
@@ -342,9 +338,9 @@ class FuchsiaDeviceDiscovery implements DeviceDiscovery {
FuchsiaDeviceDiscovery
.
_
();
static
FuchsiaDeviceDiscovery
_instance
;
static
FuchsiaDeviceDiscovery
?
_instance
;
FuchsiaDevice
_workingDevice
;
FuchsiaDevice
?
_workingDevice
;
String
get
_ffx
{
final
String
ffx
=
path
.
join
(
getArtifactPath
(),
'fuchsia'
,
'tools'
,
'x64'
,
'ffx'
);
...
...
@@ -358,13 +354,13 @@ class FuchsiaDeviceDiscovery implements DeviceDiscovery {
Future
<
FuchsiaDevice
>
get
workingDevice
async
{
if
(
_workingDevice
==
null
)
{
if
(
Platform
.
environment
.
containsKey
(
DeviceIdEnvName
))
{
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
];
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
]
!
;
await
chooseWorkingDeviceById
(
deviceId
);
return
_workingDevice
;
return
_workingDevice
!
;
}
await
chooseWorkingDevice
();
}
return
_workingDevice
;
return
_workingDevice
!
;
}
/// Picks the first connected Fuchsia device.
...
...
@@ -383,8 +379,8 @@ class FuchsiaDeviceDiscovery implements DeviceDiscovery {
@override
Future
<
void
>
chooseWorkingDeviceById
(
String
deviceId
)
async
{
final
String
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
if
(
device
Id
!=
null
)
{
final
String
?
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
if
(
matched
Id
!=
null
)
{
_workingDevice
=
FuchsiaDevice
(
deviceId:
matchedId
);
print
(
'Choose device by ID:
$matchedId
'
);
return
;
...
...
@@ -442,7 +438,7 @@ class FuchsiaDeviceDiscovery implements DeviceDiscovery {
}
class
AndroidDevice
extends
Device
{
AndroidDevice
({
@
required
this
.
deviceId
})
{
AndroidDevice
({
required
this
.
deviceId
})
{
_updateDeviceInfo
();
}
...
...
@@ -540,19 +536,19 @@ class AndroidDevice extends Device {
}
/// Executes [command] on `adb shell` and returns its exit code.
Future
<
void
>
shellExec
(
String
command
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
bool
silent
=
false
})
async
{
Future
<
void
>
shellExec
(
String
command
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
?
environment
,
bool
silent
=
false
})
async
{
await
adb
(<
String
>[
'shell'
,
command
,
...
arguments
],
environment:
environment
,
silent:
silent
);
}
/// Executes [command] on `adb shell` and returns its standard output as a [String].
Future
<
String
>
shellEval
(
String
command
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
bool
silent
=
false
})
{
Future
<
String
>
shellEval
(
String
command
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
?
environment
,
bool
silent
=
false
})
{
return
adb
(<
String
>[
'shell'
,
command
,
...
arguments
],
environment:
environment
,
silent:
silent
);
}
/// Runs `adb` with the given [arguments], selecting this device.
Future
<
String
>
adb
(
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
Map
<
String
,
String
>
?
environment
,
bool
silent
=
false
,
})
{
return
eval
(
...
...
@@ -568,18 +564,18 @@ class AndroidDevice extends Device {
@override
Future
<
Map
<
String
,
dynamic
>>
getMemoryStats
(
String
packageName
)
async
{
final
String
meminfo
=
await
shellEval
(
'dumpsys'
,
<
String
>[
'meminfo'
,
packageName
]);
final
Match
match
=
RegExp
(
r'TOTAL\s+(\d+)'
).
firstMatch
(
meminfo
);
final
Match
?
match
=
RegExp
(
r'TOTAL\s+(\d+)'
).
firstMatch
(
meminfo
);
assert
(
match
!=
null
,
'could not parse dumpsys meminfo output'
);
return
<
String
,
dynamic
>{
'total_kb'
:
int
.
parse
(
match
.
group
(
1
)
),
'total_kb'
:
int
.
parse
(
match
!.
group
(
1
)!
),
};
}
@override
bool
get
canStreamLogs
=>
true
;
bool
_abortedLogging
/*!*/
=
false
;
Process
/*?*/
_loggingProcess
;
bool
_abortedLogging
=
false
;
Process
?
_loggingProcess
;
@override
Future
<
void
>
startLoggingToSink
(
IOSink
sink
,
{
bool
clear
=
true
})
async
{
...
...
@@ -596,17 +592,17 @@ class AndroidDevice extends Device {
// to view the whole log, or just run logcat alongside this.
<
String
>[
'-s'
,
deviceId
,
'logcat'
,
'ActivityManager:I'
,
'flutter:V'
,
'*:F'
],
);
_loggingProcess
.
stdout
_loggingProcess
!
.
stdout
.
transform
<
String
>(
const
Utf8Decoder
(
allowMalformed:
true
))
.
listen
((
String
line
)
{
sink
.
write
(
line
);
});
_loggingProcess
.
stderr
_loggingProcess
!
.
stderr
.
transform
<
String
>(
const
Utf8Decoder
(
allowMalformed:
true
))
.
listen
((
String
line
)
{
sink
.
write
(
line
);
});
unawaited
(
_loggingProcess
.
exitCode
.
then
<
void
>((
int
exitCode
)
{
unawaited
(
_loggingProcess
!
.
exitCode
.
then
<
void
>((
int
exitCode
)
{
if
(!
_abortedLogging
)
{
sink
.
writeln
(
'adb logcat failed with exit code
$exitCode
.
\n
'
);
}
...
...
@@ -617,8 +613,8 @@ class AndroidDevice extends Device {
Future
<
void
>
stopLoggingToSink
()
async
{
if
(
_loggingProcess
!=
null
)
{
_abortedLogging
=
true
;
_loggingProcess
.
kill
();
await
_loggingProcess
.
exitCode
;
_loggingProcess
!
.
kill
();
await
_loggingProcess
!
.
exitCode
;
}
}
...
...
@@ -629,7 +625,7 @@ class AndroidDevice extends Device {
final
Completer
<
void
>
processDone
=
Completer
<
void
>();
final
Completer
<
void
>
abort
=
Completer
<
void
>();
bool
aborted
=
false
;
StreamController
<
String
>
stream
;
late
final
StreamController
<
String
>
stream
;
stream
=
StreamController
<
String
>(
onListen:
()
async
{
await
adb
(<
String
>[
'logcat'
,
'--clear'
]);
...
...
@@ -713,22 +709,22 @@ class IosDeviceDiscovery implements DeviceDiscovery {
IosDeviceDiscovery
.
_
();
static
IosDeviceDiscovery
_instance
;
static
IosDeviceDiscovery
?
_instance
;
IosDevice
_workingDevice
;
IosDevice
?
_workingDevice
;
@override
Future
<
IosDevice
>
get
workingDevice
async
{
if
(
_workingDevice
==
null
)
{
if
(
Platform
.
environment
.
containsKey
(
DeviceIdEnvName
))
{
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
];
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
]
!
;
await
chooseWorkingDeviceById
(
deviceId
);
return
_workingDevice
;
return
_workingDevice
!
;
}
await
chooseWorkingDevice
();
}
return
_workingDevice
;
return
_workingDevice
!
;
}
/// Picks a random iOS device out of connected devices and sets it as
...
...
@@ -749,7 +745,7 @@ class IosDeviceDiscovery implements DeviceDiscovery {
@override
Future
<
void
>
chooseWorkingDeviceById
(
String
deviceId
)
async
{
final
String
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
final
String
?
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
if
(
matchedId
!=
null
)
{
_workingDevice
=
IosDevice
(
deviceId:
matchedId
);
print
(
'Choose device by ID:
$matchedId
'
);
...
...
@@ -824,7 +820,7 @@ class IosDeviceDiscovery implements DeviceDiscovery {
/// iOS device.
class
IosDevice
extends
Device
{
IosDevice
({
@
required
this
.
deviceId
});
IosDevice
({
required
this
.
deviceId
});
@override
final
String
deviceId
;
...
...
@@ -846,8 +842,8 @@ class IosDevice extends Device {
@override
bool
get
canStreamLogs
=>
true
;
bool
_abortedLogging
/*!*/
=
false
;
Process
/*?*/
_loggingProcess
;
bool
_abortedLogging
=
false
;
Process
?
_loggingProcess
;
@override
Future
<
void
>
startLoggingToSink
(
IOSink
sink
,
{
bool
clear
=
true
})
async
{
...
...
@@ -859,17 +855,17 @@ class IosDevice extends Device {
'DYLD_LIBRARY_PATH'
:
dyldLibraryPath
,
},
);
_loggingProcess
.
stdout
_loggingProcess
!
.
stdout
.
transform
<
String
>(
const
Utf8Decoder
(
allowMalformed:
true
))
.
listen
((
String
line
)
{
sink
.
write
(
line
);
});
_loggingProcess
.
stderr
_loggingProcess
!
.
stderr
.
transform
<
String
>(
const
Utf8Decoder
(
allowMalformed:
true
))
.
listen
((
String
line
)
{
sink
.
write
(
line
);
});
unawaited
(
_loggingProcess
.
exitCode
.
then
<
void
>((
int
exitCode
)
{
unawaited
(
_loggingProcess
!
.
exitCode
.
then
<
void
>((
int
exitCode
)
{
if
(!
_abortedLogging
)
{
sink
.
writeln
(
'idevicesyslog failed with exit code
$exitCode
.
\n
'
);
}
...
...
@@ -880,8 +876,8 @@ class IosDevice extends Device {
Future
<
void
>
stopLoggingToSink
()
async
{
if
(
_loggingProcess
!=
null
)
{
_abortedLogging
=
true
;
_loggingProcess
.
kill
();
await
_loggingProcess
.
exitCode
;
_loggingProcess
!
.
kill
();
await
_loggingProcess
!
.
exitCode
;
}
}
...
...
@@ -934,7 +930,7 @@ class IosDevice extends Device {
/// Fuchsia device.
class
FuchsiaDevice
extends
Device
{
const
FuchsiaDevice
({
@
required
this
.
deviceId
});
const
FuchsiaDevice
({
required
this
.
deviceId
});
@override
final
String
deviceId
;
...
...
@@ -982,7 +978,7 @@ class FuchsiaDevice extends Device {
/// Path to the `adb` executable.
String
get
adbPath
{
final
String
androidHome
=
Platform
.
environment
[
'ANDROID_HOME'
]
??
Platform
.
environment
[
'ANDROID_SDK_ROOT'
];
final
String
?
androidHome
=
Platform
.
environment
[
'ANDROID_HOME'
]
??
Platform
.
environment
[
'ANDROID_SDK_ROOT'
];
if
(
androidHome
==
null
)
{
throw
const
DeviceException
(
...
...
@@ -1001,7 +997,7 @@ String get adbPath {
}
class
FakeDevice
extends
Device
{
const
FakeDevice
({
@
required
this
.
deviceId
});
const
FakeDevice
({
required
this
.
deviceId
});
@override
final
String
deviceId
;
...
...
@@ -1055,22 +1051,22 @@ class FakeDeviceDiscovery implements DeviceDiscovery {
FakeDeviceDiscovery
.
_
();
static
FakeDeviceDiscovery
_instance
;
static
FakeDeviceDiscovery
?
_instance
;
FakeDevice
_workingDevice
;
FakeDevice
?
_workingDevice
;
@override
Future
<
FakeDevice
>
get
workingDevice
async
{
if
(
_workingDevice
==
null
)
{
if
(
Platform
.
environment
.
containsKey
(
DeviceIdEnvName
))
{
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
];
final
String
deviceId
=
Platform
.
environment
[
DeviceIdEnvName
]
!
;
await
chooseWorkingDeviceById
(
deviceId
);
return
_workingDevice
;
return
_workingDevice
!
;
}
await
chooseWorkingDevice
();
}
return
_workingDevice
;
return
_workingDevice
!
;
}
/// The Fake is only available for by ID device discovery.
...
...
@@ -1081,7 +1077,7 @@ class FakeDeviceDiscovery implements DeviceDiscovery {
@override
Future
<
void
>
chooseWorkingDeviceById
(
String
deviceId
)
async
{
final
String
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
final
String
?
matchedId
=
_findMatchId
(
await
discoverDevices
(),
deviceId
);
if
(
matchedId
!=
null
)
{
_workingDevice
=
FakeDevice
(
deviceId:
matchedId
);
print
(
'Choose device by ID:
$matchedId
'
);
...
...
dev/devicelab/lib/framework/framework.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:developer'
;
...
...
@@ -64,8 +62,8 @@ class _TaskRunner {
_TaskRunner
(
this
.
task
)
{
registerExtension
(
'ext.cocoonRunTask'
,
(
String
method
,
Map
<
String
,
String
>
parameters
)
async
{
final
Duration
taskTimeout
=
parameters
.
containsKey
(
'timeoutInMinutes'
)
?
Duration
(
minutes:
int
.
parse
(
parameters
[
'timeoutInMinutes'
]))
final
Duration
?
taskTimeout
=
parameters
.
containsKey
(
'timeoutInMinutes'
)
?
Duration
(
minutes:
int
.
parse
(
parameters
[
'timeoutInMinutes'
]
!
))
:
null
;
// This is only expected to be passed in unit test runs so they do not
// kill the Dart process that is running them and waste time running config.
...
...
@@ -82,7 +80,7 @@ class _TaskRunner {
final
TaskFunction
task
;
Future
<
Device
/*?*/
>
_getWorkingDeviceIfAvailable
()
async
{
Future
<
Device
?
>
_getWorkingDeviceIfAvailable
()
async
{
try
{
return
await
devices
.
workingDevice
;
}
on
DeviceException
{
...
...
@@ -91,8 +89,8 @@ class _TaskRunner {
}
// TODO(ianh): workaround for https://github.com/dart-lang/sdk/issues/23797
RawReceivePort
_keepAlivePort
;
Timer
_startTaskTimeout
;
RawReceivePort
?
_keepAlivePort
;
Timer
?
_startTaskTimeout
;
bool
_taskStarted
=
false
;
final
Completer
<
TaskResult
>
_completer
=
Completer
<
TaskResult
>();
...
...
@@ -102,7 +100,7 @@ class _TaskRunner {
/// Signals that this task runner finished running the task.
Future
<
TaskResult
>
get
whenDone
=>
_completer
.
future
;
Future
<
TaskResult
>
run
(
Duration
taskTimeout
,
{
Future
<
TaskResult
>
run
(
Duration
?
taskTimeout
,
{
bool
runFlutterConfig
=
true
,
bool
runProcessCleanup
=
true
,
})
async
{
...
...
@@ -110,7 +108,7 @@ class _TaskRunner {
_taskStarted
=
true
;
print
(
'Running task with a timeout of
$taskTimeout
.'
);
final
String
exe
=
Platform
.
isWindows
?
'.exe'
:
''
;
Set
<
RunningProcessInfo
>
beforeRunningDartInstances
;
late
Set
<
RunningProcessInfo
>
beforeRunningDartInstances
;
if
(
runProcessCleanup
)
{
section
(
'Checking running Dart
$exe
processes'
);
beforeRunningDartInstances
=
await
getRunningProcesses
(
...
...
@@ -136,7 +134,7 @@ class _TaskRunner {
'--enable-windows-desktop'
,
'--enable-linux-desktop'
,
'--enable-web'
,
if
(
localEngine
!=
null
)
...<
String
>[
'--local-engine'
,
localEngine
],
if
(
localEngine
!=
null
)
...<
String
>[
'--local-engine'
,
localEngine
!
],
],
canFail:
true
);
if
(
configResult
!=
0
)
{
print
(
'Failed to enable configuration, tasks may not run.'
);
...
...
@@ -145,12 +143,12 @@ class _TaskRunner {
print
(
'Skipping enabling configs for macOS, Linux, Windows, and Web'
);
}
final
Device
/*?*/
device
=
await
_getWorkingDeviceIfAvailable
();
/*late*/
TaskResult
result
;
IOSink
/*?*/
sink
;
final
Device
?
device
=
await
_getWorkingDeviceIfAvailable
();
late
TaskResult
result
;
IOSink
?
sink
;
try
{
if
(
device
!=
null
&&
device
.
canStreamLogs
&&
hostAgent
.
dumpDirectory
!=
null
)
{
sink
=
File
(
path
.
join
(
hostAgent
.
dumpDirectory
.
path
,
'
${device.deviceId}
.log'
)).
openWrite
();
sink
=
File
(
path
.
join
(
hostAgent
.
dumpDirectory
!
.
path
,
'
${device.deviceId}
.log'
)).
openWrite
();
await
device
.
startLoggingToSink
(
sink
);
}
...
...
@@ -212,7 +210,7 @@ class _TaskRunner {
final
File
rebootFile
=
_rebootFile
();
int
runCount
;
if
(
rebootFile
.
existsSync
())
{
runCount
=
int
.
tryParse
(
rebootFile
.
readAsStringSync
().
trim
());
runCount
=
int
.
tryParse
(
rebootFile
.
readAsStringSync
().
trim
())
??
0
;
}
else
{
runCount
=
0
;
}
...
...
@@ -283,10 +281,10 @@ class _TaskRunner {
File
_rebootFile
(
)
{
if
(
Platform
.
isLinux
||
Platform
.
isMacOS
)
{
return
File
(
path
.
join
(
Platform
.
environment
[
'HOME'
],
'.reboot-count'
));
return
File
(
path
.
join
(
Platform
.
environment
[
'HOME'
]
!
,
'.reboot-count'
));
}
if
(!
Platform
.
isWindows
)
{
throw
StateError
(
'Unexpected platform
${Platform.operatingSystem}
'
);
}
return
File
(
path
.
join
(
Platform
.
environment
[
'USERPROFILE'
],
'.reboot-count'
));
return
File
(
path
.
join
(
Platform
.
environment
[
'USERPROFILE'
]
!
,
'.reboot-count'
));
}
dev/devicelab/lib/framework/ios.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:convert'
;
import
'utils.dart'
;
...
...
@@ -42,17 +40,10 @@ Future<bool> containsBitcode(String pathToBinary) async {
final
List
<
String
>
lines
=
LineSplitter
.
split
(
loadCommands
).
toList
();
lines
.
asMap
().
forEach
((
int
index
,
String
line
)
{
if
(
line
.
contains
(
'segname __LLVM'
)
&&
lines
.
length
-
index
-
1
>
3
)
{
final
String
emptyBitcodeMarker
=
lines
emptyBitcodeMarkerFound
|
=
lines
.
skip
(
index
-
1
)
.
take
(
4
)
.
firstWhere
(
(
String
line
)
=>
line
.
contains
(
' size 0x0000000000000001'
),
orElse:
()
=>
null
,
);
if
(
emptyBitcodeMarker
!=
null
)
{
emptyBitcodeMarkerFound
=
true
;
return
;
}
.
any
((
String
line
)
=>
line
.
contains
(
' size 0x0000000000000001'
));
}
});
return
!
emptyBitcodeMarkerFound
;
...
...
@@ -79,16 +70,16 @@ Future<void> testWithNewIOSSimulator(
workingDirectory:
flutterDirectory
.
path
,
);
String
iOSSimRuntime
;
String
?
iOSSimRuntime
;
final
RegExp
iOSRuntimePattern
=
RegExp
(
r'iOS .*\) - (.*)'
);
for
(
final
String
runtime
in
LineSplitter
.
split
(
availableRuntimes
))
{
// These seem to be in order, so allow matching multiple lines so it grabs
// the last (hopefully latest) one.
final
RegExpMatch
iOSRuntimeMatch
=
iOSRuntimePattern
.
firstMatch
(
runtime
);
final
RegExpMatch
?
iOSRuntimeMatch
=
iOSRuntimePattern
.
firstMatch
(
runtime
);
if
(
iOSRuntimeMatch
!=
null
)
{
iOSSimRuntime
=
iOSRuntimeMatch
.
group
(
1
).
trim
();
iOSSimRuntime
=
iOSRuntimeMatch
.
group
(
1
)
!
.
trim
();
continue
;
}
}
...
...
dev/devicelab/lib/framework/manifest.dart
View file @
ef5ffd08
...
...
@@ -2,17 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:meta/meta.dart'
;
import
'package:yaml/yaml.dart'
;
import
'utils.dart'
;
/// Loads manifest data from `manifest.yaml` file or from [yaml], if present.
Manifest
loadTaskManifest
(
[
String
yaml
])
{
Manifest
loadTaskManifest
(
[
String
?
yaml
])
{
final
dynamic
manifestYaml
=
yaml
==
null
?
loadYaml
(
file
(
'manifest.yaml'
).
readAsStringSync
())
:
loadYamlNode
(
yaml
);
...
...
@@ -32,13 +29,13 @@ class Manifest {
/// A CI task.
class
ManifestTask
{
ManifestTask
.
_
({
@
required
this
.
name
,
@
required
this
.
description
,
@
required
this
.
stage
,
@
required
this
.
requiredAgentCapabilities
,
@
required
this
.
isFlaky
,
@
required
this
.
timeoutInMinutes
,
@
required
this
.
onLuci
,
required
this
.
name
,
required
this
.
description
,
required
this
.
stage
,
required
this
.
requiredAgentCapabilities
,
required
this
.
isFlaky
,
required
this
.
timeoutInMinutes
,
required
this
.
onLuci
,
})
{
final
String
taskName
=
'task "
$name
"'
;
_checkIsNotBlank
(
name
,
'Task name'
,
taskName
);
...
...
@@ -148,9 +145,9 @@ ManifestTask _validateAndParseTask(String taskName, dynamic taskYaml) {
// ignore: avoid_dynamic_calls
stage:
taskYaml
[
'stage'
]
as
String
,
requiredAgentCapabilities:
capabilities
as
List
<
String
>,
isFlaky:
isFlaky
as
bool
??
false
,
isFlaky:
isFlaky
as
bool
,
timeoutInMinutes:
timeoutInMinutes
as
int
,
onLuci:
onLuci
as
bool
??
false
,
onLuci:
onLuci
as
bool
,
);
}
...
...
@@ -161,7 +158,7 @@ List<String> _validateAndParseCapabilities(String taskName, dynamic capabilities
final
dynamic
capability
=
capabilities
[
i
];
_checkType
(
capability
is
String
,
capability
,
'required_agent_capabilities[
$i
]'
,
'string'
);
}
return
(
capabilitiesYaml
as
List
<
dynamic
>)
.
cast
<
String
>();
return
capabilitiesYaml
.
cast
<
String
>();
}
void
_checkType
(
bool
isValid
,
dynamic
value
,
String
variableName
,
String
typeName
)
{
...
...
dev/devicelab/lib/framework/runner.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
...
...
@@ -21,13 +19,13 @@ Future<void> runTasks(
List
<
String
>
taskNames
,
{
bool
exitOnFirstTestFailure
=
false
,
bool
silent
=
false
,
String
deviceId
,
String
gitBranch
,
String
localEngine
,
String
localEngineSrcPath
,
String
luciBuilder
,
String
resultsPath
,
List
<
String
>
taskArgs
,
String
?
deviceId
,
String
?
gitBranch
,
String
?
localEngine
,
String
?
localEngineSrcPath
,
String
?
luciBuilder
,
String
?
resultsPath
,
List
<
String
>
?
taskArgs
,
})
async
{
for
(
final
String
taskName
in
taskNames
)
{
section
(
'Running task "
$taskName
"'
);
...
...
@@ -44,7 +42,7 @@ Future<void> runTasks(
print
(
const
JsonEncoder
.
withIndent
(
' '
).
convert
(
result
));
section
(
'Finished task "
$taskName
"'
);
if
(
resultsPath
!=
null
)
{
if
(
resultsPath
!=
null
&&
gitBranch
!=
null
)
{
final
Cocoon
cocoon
=
Cocoon
();
await
cocoon
.
writeTaskResultToFile
(
builderName:
luciBuilder
,
...
...
@@ -76,11 +74,11 @@ Future<void> runTasks(
Future
<
TaskResult
>
runTask
(
String
taskName
,
{
bool
silent
=
false
,
String
localEngine
,
String
localEngineSrcPath
,
String
deviceId
,
List
<
String
>
taskArgs
,
@visibleForTesting
Map
<
String
,
String
>
isolateParams
,
String
?
localEngine
,
String
?
localEngineSrcPath
,
String
?
deviceId
,
List
<
String
>
?
taskArgs
,
@visibleForTesting
Map
<
String
,
String
>
?
isolateParams
,
})
async
{
final
String
taskExecutable
=
'bin/tasks/
$taskName
.dart'
;
...
...
@@ -117,7 +115,7 @@ Future<TaskResult> runTask(
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
if
(!
uri
.
isCompleted
)
{
final
Uri
serviceUri
=
parseServiceUri
(
line
,
prefix:
'Observatory listening on '
);
final
Uri
?
serviceUri
=
parseServiceUri
(
line
,
prefix:
'Observatory listening on '
);
if
(
serviceUri
!=
null
)
uri
.
complete
(
serviceUri
);
}
...
...
@@ -139,7 +137,7 @@ Future<TaskResult> runTask(
'ext.cocoonRunTask'
,
args:
isolateParams
,
isolateId:
result
.
isolate
.
id
,
)).
json
;
)).
json
!
;
final
TaskResult
taskResult
=
TaskResult
.
fromJson
(
taskResultJson
);
await
runner
.
exitCode
;
return
taskResult
;
...
...
@@ -168,13 +166,13 @@ Future<ConnectionResult> _connectToRunnerIsolate(Uri vmServiceUri) async {
// Look up the isolate.
final
VmService
client
=
await
vmServiceConnectUri
(
url
);
VM
vm
=
await
client
.
getVM
();
while
(
vm
.
isolates
.
isEmpty
)
{
while
(
vm
.
isolates
!
.
isEmpty
)
{
await
Future
<
void
>.
delayed
(
const
Duration
(
seconds:
1
));
vm
=
await
client
.
getVM
();
}
final
IsolateRef
isolate
=
vm
.
isolates
.
first
;
final
IsolateRef
isolate
=
vm
.
isolates
!
.
first
;
final
Response
response
=
await
client
.
callServiceExtension
(
'ext.cocoonRunnerReady'
,
isolateId:
isolate
.
id
);
if
(
response
.
json
[
'response'
]
!=
'ready'
)
if
(
response
.
json
!
[
'response'
]
!=
'ready'
)
throw
'not ready yet'
;
return
ConnectionResult
(
client
,
isolate
);
}
catch
(
error
)
{
...
...
@@ -193,7 +191,7 @@ class ConnectionResult {
}
/// The cocoon client sends an invalid VM service response, we need to intercept it.
Future
<
VmService
>
vmServiceConnectUri
(
String
wsUri
,
{
Log
log
})
async
{
Future
<
VmService
>
vmServiceConnectUri
(
String
wsUri
,
{
Log
?
log
})
async
{
final
WebSocket
socket
=
await
WebSocket
.
connect
(
wsUri
);
final
StreamController
<
dynamic
>
controller
=
StreamController
<
dynamic
>();
final
Completer
<
dynamic
>
streamClosedCompleter
=
Completer
<
dynamic
>();
...
...
@@ -207,7 +205,7 @@ Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
controller
.
add
(
data
);
}
},
onError:
(
dynamic
err
,
StackTrace
stackTrace
)
=>
controller
.
addError
(
err
,
stackTrace
),
onError:
(
Object
err
,
StackTrace
stackTrace
)
=>
controller
.
addError
(
err
,
stackTrace
),
onDone:
()
=>
streamClosedCompleter
.
complete
(),
);
...
...
dev/devicelab/lib/framework/running_processes.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:meta/meta.dart'
;
...
...
@@ -36,7 +34,7 @@ class RunningProcessInfo {
}
}
Future
<
bool
>
killProcess
(
String
pid
,
{
ProcessManager
processManager
})
async
{
Future
<
bool
>
killProcess
(
String
pid
,
{
ProcessManager
?
processManager
})
async
{
assert
(
pid
!=
null
,
'Must specify a pid to kill'
);
processManager
??=
const
LocalProcessManager
();
ProcessResult
result
;
...
...
@@ -58,8 +56,8 @@ Future<bool> killProcess(String pid, {ProcessManager processManager}) async {
}
Stream
<
RunningProcessInfo
>
getRunningProcesses
({
String
processName
,
ProcessManager
processManager
,
String
?
processName
,
ProcessManager
?
processManager
,
})
{
processManager
??=
const
LocalProcessManager
();
if
(
Platform
.
isWindows
)
{
...
...
@@ -69,7 +67,7 @@ Stream<RunningProcessInfo> getRunningProcesses({
}
@visibleForTesting
Stream
<
RunningProcessInfo
>
windowsRunningProcesses
(
String
processName
)
async
*
{
Stream
<
RunningProcessInfo
>
windowsRunningProcesses
(
String
?
processName
)
async
*
{
// PowerShell script to get the command line arguments and create time of
// a process.
// See: https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
...
...
@@ -107,8 +105,8 @@ Iterable<RunningProcessInfo> processPowershellOutput(String output) sync* {
const
int
processIdHeaderSize
=
'ProcessId'
.
length
;
const
int
creationDateHeaderStart
=
processIdHeaderSize
+
1
;
int
creationDateHeaderEnd
;
int
commandLineHeaderStart
;
late
int
creationDateHeaderEnd
;
late
int
commandLineHeaderStart
;
bool
inTableBody
=
false
;
for
(
final
String
line
in
output
.
split
(
'
\n
'
))
{
if
(
line
.
startsWith
(
'ProcessId'
))
{
...
...
@@ -160,7 +158,7 @@ Iterable<RunningProcessInfo> processPowershellOutput(String output) sync* {
@visibleForTesting
Stream
<
RunningProcessInfo
>
posixRunningProcesses
(
String
processName
,
String
?
processName
,
ProcessManager
processManager
,
)
async
*
{
// Cirrus is missing this in Linux for some reason.
...
...
@@ -194,7 +192,7 @@ Stream<RunningProcessInfo> posixRunningProcesses(
@visibleForTesting
Iterable
<
RunningProcessInfo
>
processPsOutput
(
String
output
,
String
processName
,
String
?
processName
,
)
sync
*
{
if
(
output
==
null
)
{
return
;
...
...
@@ -235,7 +233,7 @@ Iterable<RunningProcessInfo> processPsOutput(
final
String
rawTime
=
line
.
substring
(
0
,
24
);
final
String
year
=
rawTime
.
substring
(
20
,
24
);
final
String
month
=
months
[
rawTime
.
substring
(
4
,
7
)];
final
String
month
=
months
[
rawTime
.
substring
(
4
,
7
)]
!
;
final
String
day
=
rawTime
.
substring
(
8
,
10
).
replaceFirst
(
' '
,
'0'
);
final
String
time
=
rawTime
.
substring
(
11
,
19
);
...
...
dev/devicelab/lib/framework/task_result.dart
View file @
ef5ffd08
...
...
@@ -41,7 +41,7 @@ class TaskResult {
List
<
String
>
detailFiles
=
const
<
String
>[],
})
{
return
TaskResult
.
success
(
json
.
decode
(
file
.
readAsStringSync
())
as
Map
<
String
,
dynamic
>,
json
.
decode
(
file
.
readAsStringSync
())
as
Map
<
String
,
dynamic
>
?
,
benchmarkScoreKeys:
benchmarkScoreKeys
,
detailFiles:
detailFiles
,
);
...
...
@@ -53,14 +53,14 @@ class TaskResult {
if
(
success
)
{
final
List
<
String
>
benchmarkScoreKeys
=
(
json
[
'benchmarkScoreKeys'
]
as
List
<
dynamic
>?
??
<
String
>[]).
cast
<
String
>();
final
List
<
String
>
detailFiles
=
(
json
[
'detailFiles'
]
as
List
<
dynamic
>?
??
<
String
>[]).
cast
<
String
>();
return
TaskResult
.
success
(
json
[
'data'
]
as
Map
<
String
,
dynamic
>,
return
TaskResult
.
success
(
json
[
'data'
]
as
Map
<
String
,
dynamic
>
?
,
benchmarkScoreKeys:
benchmarkScoreKeys
,
detailFiles:
detailFiles
,
message:
json
[
'reason'
]
as
String
,
message:
json
[
'reason'
]
as
String
?
,
);
}
return
TaskResult
.
failure
(
json
[
'reason'
]
as
String
);
return
TaskResult
.
failure
(
json
[
'reason'
]
as
String
?
);
}
/// Constructs an unsuccessful result.
...
...
@@ -88,7 +88,7 @@ class TaskResult {
bool
get
failed
=>
!
succeeded
;
/// Explains the result in a human-readable format.
final
String
message
;
final
String
?
message
;
/// Serializes this task result to JSON format.
///
...
...
@@ -124,7 +124,7 @@ class TaskResult {
}
@override
String
toString
()
=>
message
;
String
toString
()
=>
message
??
''
;
}
class
TaskResultCheckProcesses
extends
TaskResult
{
...
...
dev/devicelab/lib/framework/utils.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
...
...
@@ -11,7 +9,6 @@ import 'dart:math' as math;
import
'package:flutter_devicelab/common.dart'
;
import
'package:flutter_devicelab/framework/devices.dart'
;
import
'package:meta/meta.dart'
;
import
'package:path/path.dart'
as
path
;
import
'package:process/process.dart'
;
import
'package:stack_trace/stack_trace.dart'
;
...
...
@@ -23,7 +20,7 @@ import 'task_result.dart';
String
cwd
=
Directory
.
current
.
path
;
/// The local engine to use for [flutter] and [evalFlutter], if any.
String
get
localEngine
{
String
?
get
localEngine
{
// Use two distinct `defaultValue`s to determine whether a 'localEngine'
// declaration exists in the environment.
const
bool
isDefined
=
...
...
@@ -34,7 +31,7 @@ String get localEngine {
/// The local engine source path to use if a local engine is used for [flutter]
/// and [evalFlutter].
String
get
localEngineSrcPath
{
String
?
get
localEngineSrcPath
{
// Use two distinct `defaultValue`s to determine whether a
// 'localEngineSrcPath' declaration exists in the environment.
const
bool
isDefined
=
...
...
@@ -70,18 +67,18 @@ class HealthCheckResult {
HealthCheckResult
.
failure
(
this
.
details
)
:
succeeded
=
false
;
HealthCheckResult
.
error
(
dynamic
error
,
dynamic
stackTrace
)
:
succeeded
=
false
,
details
=
'ERROR:
$error${
'\n$stackTrace' ??
''}
'
;
details
=
'ERROR:
$error${
stackTrace != null ? '\n$stackTrace' :
''}
'
;
final
bool
succeeded
;
final
String
details
;
final
String
?
details
;
@override
String
toString
()
{
final
StringBuffer
buf
=
StringBuffer
(
succeeded
?
'succeeded'
:
'failed'
);
if
(
details
!=
null
&&
details
.
trim
().
isNotEmpty
)
{
if
(
details
!=
null
&&
details
!
.
trim
().
isNotEmpty
)
{
buf
.
writeln
();
// Indent details by 4 spaces
for
(
final
String
line
in
details
.
trim
().
split
(
'
\n
'
))
{
for
(
final
String
line
in
details
!
.
trim
().
split
(
'
\n
'
))
{
buf
.
writeln
(
'
$line
'
);
}
}
...
...
@@ -127,7 +124,7 @@ Directory dir(String path) => Directory(path);
File
file
(
String
path
)
=>
File
(
path
);
void
copy
(
File
sourceFile
,
Directory
targetDirectory
,
{
String
name
})
{
void
copy
(
File
sourceFile
,
Directory
targetDirectory
,
{
String
?
name
})
{
final
File
target
=
file
(
path
.
join
(
targetDirectory
.
path
,
name
??
path
.
basename
(
sourceFile
.
path
)));
target
.
writeAsBytesSync
(
sourceFile
.
readAsBytesSync
());
...
...
@@ -154,7 +151,7 @@ void recursiveCopy(Directory source, Directory target) {
}
FileSystemEntity
move
(
FileSystemEntity
whatToMove
,
{
Directory
to
,
String
name
})
{
{
required
Directory
to
,
String
?
name
})
{
return
whatToMove
.
renameSync
(
path
.
join
(
to
.
path
,
name
??
path
.
basename
(
whatToMove
.
path
)));
}
...
...
@@ -225,9 +222,9 @@ Future<String> getDartVersion() async {
return
version
.
replaceAll
(
'"'
,
"'"
);
}
Future
<
String
>
getCurrentFlutterRepoCommit
()
{
Future
<
String
?
>
getCurrentFlutterRepoCommit
()
{
if
(!
dir
(
'
${flutterDirectory.path}
/.git'
).
existsSync
())
{
return
Future
<
String
>.
value
(
null
);
return
Future
<
String
?
>.
value
(
null
);
}
return
inDirectory
<
String
>(
flutterDirectory
,
()
{
...
...
@@ -275,10 +272,10 @@ Future<DateTime> getFlutterRepoCommitTimestamp(String commit) {
/// returned in the form of a [Future] that completes to a [Process] object.
Future
<
Process
>
startProcess
(
String
executable
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
List
<
String
>
?
arguments
,
{
Map
<
String
,
String
>
?
environment
,
bool
isBot
=
true
,
// set to false to pretend not to be on a bot (e.g. to test user-facing outputs)
String
workingDirectory
,
String
?
workingDirectory
,
})
async
{
assert
(
isBot
!=
null
);
final
String
command
=
'
$executable
${arguments?.join(" ") ?? ""}
'
;
...
...
@@ -288,7 +285,7 @@ Future<Process> startProcess(
newEnvironment
[
'LANG'
]
=
'en_US.UTF-8'
;
print
(
'
\n
Executing:
$command
in
$finalWorkingDirectory
with environment
$newEnvironment
'
);
final
Process
process
=
await
_processManager
.
start
(
<
String
>[
executable
,
...
arguments
],
<
String
>[
executable
,
...
?
arguments
],
environment:
newEnvironment
,
workingDirectory:
finalWorkingDirectory
,
);
...
...
@@ -324,9 +321,9 @@ Future<void> forceQuitRunningProcesses() async {
Future
<
int
>
exec
(
String
executable
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
Map
<
String
,
String
>
?
environment
,
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
String
workingDirectory
,
String
?
workingDirectory
,
})
async
{
return
_execute
(
executable
,
...
...
@@ -340,11 +337,11 @@ Future<int> exec(
Future
<
int
>
_execute
(
String
executable
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
Map
<
String
,
String
>
?
environment
,
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
String
workingDirectory
,
StringBuffer
output
,
// if not null, the stdout will be written here
StringBuffer
stderr
,
// if not null, the stderr will be written here
String
?
workingDirectory
,
StringBuffer
?
output
,
// if not null, the stdout will be written here
StringBuffer
?
stderr
,
// if not null, the stderr will be written here
bool
printStdout
=
true
,
bool
printStderr
=
true
,
})
async
{
...
...
@@ -376,8 +373,8 @@ Future<int> _execute(
/// Returns a future that completes when both out and error streams a closed.
Future
<
void
>
forwardStandardStreams
(
Process
process
,
{
StringBuffer
output
,
StringBuffer
stderr
,
StringBuffer
?
output
,
StringBuffer
?
stderr
,
bool
printStdout
=
true
,
bool
printStderr
=
true
,
})
{
...
...
@@ -414,10 +411,10 @@ Future<void> forwardStandardStreams(
Future
<
String
>
eval
(
String
executable
,
List
<
String
>
arguments
,
{
Map
<
String
,
String
>
environment
,
Map
<
String
,
String
>
?
environment
,
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
String
workingDirectory
,
StringBuffer
stderr
,
// if not null, the stderr will be written here
String
?
workingDirectory
,
StringBuffer
?
stderr
,
// if not null, the stderr will be written here
bool
printStdout
=
true
,
bool
printStderr
=
true
,
})
async
{
...
...
@@ -457,10 +454,10 @@ List<String> flutterCommandArgs(String command, List<String> options) {
if
(
command
==
'drive'
&&
hostAgent
.
dumpDirectory
!=
null
)
...<
String
>[
'--screenshot'
,
hostAgent
.
dumpDirectory
.
path
,
hostAgent
.
dumpDirectory
!
.
path
,
],
if
(
localEngine
!=
null
)
...<
String
>[
'--local-engine'
,
localEngine
],
if
(
localEngineSrcPath
!=
null
)
...<
String
>[
'--local-engine-src-path'
,
localEngineSrcPath
],
if
(
localEngine
!=
null
)
...<
String
>[
'--local-engine'
,
localEngine
!
],
if
(
localEngineSrcPath
!=
null
)
...<
String
>[
'--local-engine-src-path'
,
localEngineSrcPath
!
],
...
options
,
];
}
...
...
@@ -470,7 +467,7 @@ List<String> flutterCommandArgs(String command, List<String> options) {
Future
<
int
>
flutter
(
String
command
,
{
List
<
String
>
options
=
const
<
String
>[],
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
Map
<
String
,
String
>
environment
=
const
<
String
,
String
>{}
,
Map
<
String
,
String
>
?
environment
,
})
{
final
List
<
String
>
args
=
flutterCommandArgs
(
command
,
options
);
return
exec
(
path
.
join
(
flutterDirectory
.
path
,
'bin'
,
'flutter'
),
args
,
...
...
@@ -493,8 +490,8 @@ Future<Process> startFlutter(String command, {
Future
<
String
>
evalFlutter
(
String
command
,
{
List
<
String
>
options
=
const
<
String
>[],
bool
canFail
=
false
,
// as in, whether failures are ok. False means that they are fatal.
Map
<
String
,
String
>
environment
,
StringBuffer
stderr
,
// if not null, the stderr will be written here.
Map
<
String
,
String
>
?
environment
,
StringBuffer
?
stderr
,
// if not null, the stderr will be written here.
})
{
final
List
<
String
>
args
=
flutterCommandArgs
(
command
,
options
);
return
eval
(
path
.
join
(
flutterDirectory
.
path
,
'bin'
,
'flutter'
),
args
,
...
...
@@ -521,7 +518,7 @@ Future<int> dart(List<String> args) => exec(dartBin, <String>['--disable-dart-de
/// Returns a future that completes with a path suitable for JAVA_HOME
/// or with null, if Java cannot be found.
Future
<
String
>
findJavaHome
()
async
{
Future
<
String
?
>
findJavaHome
()
async
{
if
(
_javaHome
==
null
)
{
final
Iterable
<
String
>
hits
=
grep
(
'Java binary at: '
,
...
...
@@ -537,7 +534,7 @@ Future<String> findJavaHome() async {
}
return
_javaHome
;
}
String
_javaHome
;
String
?
_javaHome
;
Future
<
T
>
inDirectory
<
T
>(
dynamic
directory
,
Future
<
T
>
Function
()
action
)
async
{
final
String
previousCwd
=
cwd
;
...
...
@@ -568,12 +565,12 @@ void cd(dynamic directory) {
Directory
get
flutterDirectory
=>
Directory
.
current
.
parent
.
parent
;
String
requireEnvVar
(
String
name
)
{
final
String
value
=
Platform
.
environment
[
name
];
final
String
?
value
=
Platform
.
environment
[
name
];
if
(
value
==
null
)
fail
(
'
$name
environment variable is missing. Quitting.'
);
return
value
;
return
value
!
;
}
T
requireConfigProperty
<
T
>(
Map
<
String
,
dynamic
>
map
,
String
propertyName
)
{
...
...
@@ -637,7 +634,7 @@ void checkNotNull(Object o1,
}
/// Splits [from] into lines and selects those that contain [pattern].
Iterable
<
String
>
grep
(
Pattern
pattern
,
{
@
required
String
from
})
{
Iterable
<
String
>
grep
(
Pattern
pattern
,
{
required
String
from
})
{
return
from
.
split
(
'
\n
'
).
where
((
String
line
)
{
return
line
.
contains
(
pattern
);
});
...
...
@@ -675,8 +672,8 @@ final RegExp _obsUriRegExp = RegExp(r'((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)');
///
/// The `prefix`, if specified, is a regular expression pattern and must not contain groups.
/// `prefix` defaults to the RegExp: `An Observatory debugger .* is available at: `.
int
parseServicePort
(
String
line
,
{
Pattern
prefix
,
int
?
parseServicePort
(
String
line
,
{
Pattern
?
prefix
,
})
{
prefix
??=
_obsRegExp
;
final
Iterable
<
Match
>
matchesIter
=
prefix
.
allMatches
(
line
);
...
...
@@ -686,15 +683,15 @@ int parseServicePort(String line, {
final
Match
prefixMatch
=
matchesIter
.
first
;
final
List
<
Match
>
matches
=
_obsPortRegExp
.
allMatches
(
line
,
prefixMatch
.
end
).
toList
();
return
matches
.
isEmpty
?
null
:
int
.
parse
(
matches
[
0
].
group
(
2
));
return
matches
.
isEmpty
?
null
:
int
.
parse
(
matches
[
0
].
group
(
2
)
!
);
}
/// Tries to extract a URL from the string.
///
/// The `prefix`, if specified, is a regular expression pattern and must not contain groups.
/// `prefix` defaults to the RegExp: `An Observatory debugger .* is available at: `.
Uri
parseServiceUri
(
String
line
,
{
Pattern
prefix
,
Uri
?
parseServiceUri
(
String
line
,
{
Pattern
?
prefix
,
})
{
prefix
??=
_obsRegExp
;
final
Iterable
<
Match
>
matchesIter
=
prefix
.
allMatches
(
line
);
...
...
@@ -704,7 +701,7 @@ Uri parseServiceUri(String line, {
final
Match
prefixMatch
=
matchesIter
.
first
;
final
List
<
Match
>
matches
=
_obsUriRegExp
.
allMatches
(
line
,
prefixMatch
.
end
).
toList
();
return
matches
.
isEmpty
?
null
:
Uri
.
parse
(
matches
[
0
].
group
(
0
));
return
matches
.
isEmpty
?
null
:
Uri
.
parse
(
matches
[
0
].
group
(
0
)
!
);
}
/// Checks that the file exists, otherwise throws a [FileSystemException].
...
...
@@ -771,7 +768,7 @@ void checkFileContains(List<Pattern> patterns, String filePath) {
///
/// Removes the directory [path], then clones the git repository
/// specified by [repo] to the directory [path].
Future
<
int
>
gitClone
({
String
path
,
String
repo
})
async
{
Future
<
int
>
gitClone
({
required
String
path
,
required
String
repo
})
async
{
rmTree
(
Directory
(
path
));
await
Directory
(
path
).
create
(
recursive:
true
);
...
...
@@ -792,7 +789,7 @@ Future<int> gitClone({String path, String repo}) async {
/// Waits a constant duration of [delayDuration] between every retry attempt.
Future
<
T
>
retry
<
T
>(
FutureOr
<
T
>
Function
()
fn
,
{
FutureOr
<
bool
>
Function
(
Exception
)
retryIf
,
FutureOr
<
bool
>
Function
(
Exception
)
?
retryIf
,
int
maxAttempts
=
5
,
Duration
delayDuration
=
const
Duration
(
seconds:
3
),
})
async
{
...
...
dev/devicelab/lib/microbenchmarks.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
...
...
dev/devicelab/lib/tasks/analysis.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:path/path.dart'
as
path
;
...
...
dev/devicelab/lib/tasks/build_test_task.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:args/args.dart'
;
...
...
@@ -18,10 +16,9 @@ import '../framework/utils.dart';
abstract
class
BuildTestTask
{
BuildTestTask
(
this
.
args
,
{
this
.
workingDirectory
,
this
.
runFlutterClean
=
true
,})
{
final
ArgResults
argResults
=
argParser
.
parse
(
args
);
applicationBinaryPath
=
argResults
[
kApplicationBinaryPathOption
]
as
String
;
applicationBinaryPath
=
argResults
[
kApplicationBinaryPathOption
]
as
String
?
;
buildOnly
=
argResults
[
kBuildOnlyFlag
]
as
bool
;
testOnly
=
argResults
[
kTestOnlyFlag
]
as
bool
;
}
static
const
String
kApplicationBinaryPathOption
=
'application-binary-path'
;
...
...
@@ -48,10 +45,10 @@ abstract class BuildTestTask {
/// Path to a built application to use in [test].
///
/// If not given, will default to child's expected location.
String
applicationBinaryPath
;
String
?
applicationBinaryPath
;
/// Where the test artifacts are stored, such as performance results.
final
Directory
workingDirectory
;
final
Directory
?
workingDirectory
;
/// Run Flutter build to create [applicationBinaryPath].
Future
<
void
>
build
()
async
{
...
...
@@ -93,7 +90,7 @@ abstract class BuildTestTask {
///
/// Tasks can override to support default values. Otherwise, it will default
/// to needing to be passed as an argument in the test runner.
String
getApplicationBinaryPath
()
=>
applicationBinaryPath
;
String
?
getApplicationBinaryPath
()
=>
applicationBinaryPath
;
/// Run this task.
///
...
...
dev/devicelab/lib/tasks/dart_plugin_registry_tests.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
...
...
@@ -15,8 +13,8 @@ import 'package:flutter_devicelab/framework/utils.dart';
import
'package:path/path.dart'
as
path
;
TaskFunction
dartPluginRegistryTest
(
{
String
deviceIdOverride
,
Map
<
String
,
String
>
environment
,
String
?
deviceIdOverride
,
Map
<
String
,
String
>
?
environment
,
})
{
final
Directory
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_devicelab_dart_plugin_test.'
);
...
...
dev/devicelab/lib/tasks/gallery.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:convert'
;
import
'dart:io'
;
import
'dart:math'
as
math
;
...
...
@@ -55,9 +53,9 @@ class GalleryTransitionTest {
final
bool
needFullTimeline
;
final
String
testFile
;
final
String
timelineSummaryFile
;
final
String
timelineTraceFile
;
final
String
transitionDurationFile
;
final
String
driverFile
;
final
String
?
timelineTraceFile
;
final
String
?
transitionDurationFile
;
final
String
?
driverFile
;
Future
<
TaskResult
>
call
()
async
{
final
Device
device
=
await
devices
.
workingDevice
;
...
...
@@ -65,7 +63,7 @@ class GalleryTransitionTest {
final
String
deviceId
=
device
.
deviceId
;
final
Directory
galleryDirectory
=
dir
(
'
${flutterDirectory.path}
/dev/integration_tests/flutter_gallery'
);
await
inDirectory
<
void
>(
galleryDirectory
,
()
async
{
String
applicationBinaryPath
;
String
?
applicationBinaryPath
;
if
(
deviceOperatingSystem
==
DeviceOperatingSystem
.
android
)
{
section
(
'BUILDING APPLICATION'
);
await
flutter
(
...
...
dev/devicelab/lib/tasks/hot_mode_tests.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
...
...
@@ -20,7 +18,7 @@ final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'dev/in
const
String
kSourceLine
=
'fontSize: (orientation == Orientation.portrait) ? 32.0 : 24.0'
;
const
String
kReplacementLine
=
'fontSize: (orientation == Orientation.portrait) ? 34.0 : 24.0'
;
TaskFunction
createHotModeTest
(
{
String
deviceIdOverride
,
Map
<
String
,
String
>
environment
})
{
TaskFunction
createHotModeTest
(
{
String
?
deviceIdOverride
,
Map
<
String
,
String
>?
environment
})
{
// This file is modified during the test and needs to be restored at the end.
final
File
flutterFrameworkSource
=
file
(
path
.
join
(
flutterDirectory
.
path
,
'packages/flutter/lib/src/widgets/framework.dart'
,
...
...
@@ -35,13 +33,13 @@ TaskFunction createHotModeTest({String deviceIdOverride, Map<String, String> env
final
File
benchmarkFile
=
file
(
path
.
join
(
_editedFlutterGalleryDir
.
path
,
'hot_benchmark.json'
));
rm
(
benchmarkFile
);
final
List
<
String
>
options
=
<
String
>[
'--hot'
,
'-d'
,
deviceIdOverride
,
'--benchmark'
,
'--resident'
,
'--no-android-gradle-daemon'
,
'--no-publish-port'
,
'--verbose'
,
'--hot'
,
'-d'
,
deviceIdOverride
!
,
'--benchmark'
,
'--resident'
,
'--no-android-gradle-daemon'
,
'--no-publish-port'
,
'--verbose'
,
];
int
hotReloadCount
=
0
;
Map
<
String
,
dynamic
>
smallReloadData
;
Map
<
String
,
dynamic
>
mediumReloadData
;
Map
<
String
,
dynamic
>
largeReloadData
;
Map
<
String
,
dynamic
>
freshRestartReloadsData
;
late
Map
<
String
,
dynamic
>
smallReloadData
;
late
Map
<
String
,
dynamic
>
mediumReloadData
;
late
Map
<
String
,
dynamic
>
largeReloadData
;
late
Map
<
String
,
dynamic
>
freshRestartReloadsData
;
await
inDirectory
<
void
>(
flutterDirectory
,
()
async
{
...
...
@@ -215,9 +213,9 @@ TaskFunction createHotModeTest({String deviceIdOverride, Map<String, String> env
};
}
Future
<
Map
<
String
,
Object
>>
captureReloadData
(
Future
<
Map
<
String
,
dynamic
>>
captureReloadData
(
List
<
String
>
options
,
Map
<
String
,
String
>
environment
,
Map
<
String
,
String
>
?
environment
,
File
benchmarkFile
,
void
Function
(
String
,
Process
)
onLine
,
)
async
{
...
...
@@ -247,7 +245,7 @@ Future<Map<String, Object>> captureReloadData(
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
stdoutDone
.
future
,
stderrDone
.
future
]);
await
process
.
exitCode
;
final
Map
<
String
,
dynamic
>
result
=
json
.
decode
(
benchmarkFile
.
readAsStringSync
())
as
Map
<
String
,
dynamic
>;
final
Map
<
String
,
Object
>
result
=
json
.
decode
(
benchmarkFile
.
readAsStringSync
())
as
Map
<
String
,
Object
>;
benchmarkFile
.
deleteSync
();
return
result
;
}
dev/devicelab/lib/tasks/integration_tests.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'../framework/devices.dart'
;
import
'../framework/framework.dart'
;
import
'../framework/task_result.dart'
;
...
...
dev/devicelab/lib/tasks/microbenchmarks.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:io'
;
...
...
dev/devicelab/lib/tasks/new_gallery.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:flutter_devicelab/tasks/perf_tests.dart'
;
...
...
dev/devicelab/lib/tasks/perf_tests.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
show
LineSplitter
,
json
,
utf8
;
import
'dart:io'
;
...
...
@@ -516,7 +514,7 @@ class StartupTest {
final
List
<
Map
<
String
,
dynamic
>>
results
=
<
Map
<
String
,
dynamic
>>[];
section
(
'Building application'
);
String
applicationBinaryPath
;
String
?
applicationBinaryPath
;
switch
(
deviceOperatingSystem
)
{
case
DeviceOperatingSystem
.
android
:
await
flutter
(
'build'
,
options:
<
String
>[
...
...
@@ -586,7 +584,7 @@ class StartupTest {
'-d'
,
device
.
deviceId
,
'--out'
,
hostAgent
.
dumpDirectory
hostAgent
.
dumpDirectory
!
.
childFile
(
'screenshot_startup_failure_
$currentFailures
.png'
)
.
path
,
],
...
...
@@ -630,7 +628,7 @@ class DevtoolsStartupTest {
final
Device
device
=
await
devices
.
workingDevice
;
section
(
'Building application'
);
String
applicationBinaryPath
;
String
?
applicationBinaryPath
;
switch
(
deviceOperatingSystem
)
{
case
DeviceOperatingSystem
.
android
:
await
flutter
(
'build'
,
options:
<
String
>[
...
...
@@ -733,7 +731,7 @@ class PerfTest {
this
.
needsFullTimeline
=
true
,
this
.
benchmarkScoreKeys
,
this
.
dartDefine
=
''
,
String
resultFilename
,
String
?
resultFilename
,
}):
_resultFilename
=
resultFilename
;
const
PerfTest
.
e2e
(
...
...
@@ -753,12 +751,12 @@ class PerfTest {
/// The main entry-point file of the application, as run on the device.
final
String
testTarget
;
// The prefix name of the filename such as `<timelineFileName>.timeline_summary.json`.
final
String
timelineFileName
;
final
String
?
timelineFileName
;
String
get
traceFilename
=>
'
$timelineFileName
.timeline'
;
String
get
resultFilename
=>
_resultFilename
??
'
$timelineFileName
.timeline_summary'
;
final
String
_resultFilename
;
final
String
?
_resultFilename
;
/// The test file to run on the host.
final
String
testDriver
;
final
String
?
testDriver
;
/// Whether to collect CPU and GPU metrics.
final
bool
measureCpuGpu
;
/// Whether to collect memory metrics.
...
...
@@ -788,7 +786,7 @@ class PerfTest {
/// if (measureCpuGpu) 'average_gpu_usage',
/// ]
/// ```
final
List
<
String
>
benchmarkScoreKeys
;
final
List
<
String
>
?
benchmarkScoreKeys
;
/// Additional flags for `--dart-define` to control the test
final
String
dartDefine
;
...
...
@@ -800,8 +798,8 @@ class PerfTest {
@protected
Future
<
TaskResult
>
internalRun
({
bool
cacheSkSL
=
false
,
String
existingApp
,
String
writeSkslFileName
,
String
?
existingApp
,
String
?
writeSkslFileName
,
})
{
return
inDirectory
<
TaskResult
>(
testDirectory
,
()
async
{
final
Device
device
=
await
devices
.
workingDevice
;
...
...
@@ -818,7 +816,7 @@ class PerfTest {
'--trace-startup'
,
// Enables "endless" timeline event buffering.
'-t'
,
testTarget
,
if
(
testDriver
!=
null
)
...<
String
>[
'--driver'
,
testDriver
],
...<
String
>[
'--driver'
,
testDriver
!
],
if
(
existingApp
!=
null
)
...<
String
>[
'--use-existing-app'
,
existingApp
],
if
(
writeSkslFileName
!=
null
)
...
...
@@ -890,9 +888,9 @@ class PerfTestWithSkSL extends PerfTest {
String
testTarget
,
String
timelineFileName
,
{
bool
measureCpuGpu
=
false
,
String
testDriver
,
String
?
testDriver
,
bool
needsFullTimeline
=
true
,
List
<
String
>
benchmarkScoreKeys
,
List
<
String
>
?
benchmarkScoreKeys
,
})
:
super
(
testDirectory
,
testTarget
,
...
...
@@ -964,7 +962,7 @@ class PerfTestWithSkSL extends PerfTest {
);
}
Future
<
String
>
_runApp
({
String
appBinary
,
bool
cacheSkSL
=
false
,
String
skslPath
})
async
{
Future
<
String
>
_runApp
({
String
?
appBinary
,
bool
cacheSkSL
=
false
,
String
?
skslPath
})
async
{
if
(
File
(
_vmserviceFileName
).
existsSync
())
{
File
(
_vmserviceFileName
).
deleteSync
();
}
...
...
@@ -1027,9 +1025,9 @@ class PerfTestWithSkSL extends PerfTest {
});
}
String
_flutterPath
;
Device
_device
;
Process
_runProcess
;
late
String
_flutterPath
;
late
Device
_device
;
late
Process
_runProcess
;
static
const
String
_kVmserviceOutFileName
=
'vmservice.out'
;
}
...
...
@@ -1073,12 +1071,16 @@ class WebCompileTest {
///
/// Run a single web compile test for the app under [directory], and store
/// its metrics with prefix [metric].
static
Future
<
Map
<
String
,
int
>>
runSingleBuildTest
({
String
directory
,
String
metric
,
bool
measureBuildTime
=
false
})
{
static
Future
<
Map
<
String
,
int
>>
runSingleBuildTest
({
required
String
directory
,
required
String
metric
,
bool
measureBuildTime
=
false
,
})
{
return
inDirectory
<
Map
<
String
,
int
>>(
directory
,
()
async
{
final
Map
<
String
,
int
>
metrics
=
<
String
,
int
>{};
await
flutter
(
'packages'
,
options:
<
String
>[
'get'
]);
final
Stopwatch
watch
=
measureBuildTime
?
Stopwatch
()
:
null
;
final
Stopwatch
?
watch
=
measureBuildTime
?
Stopwatch
()
:
null
;
watch
?.
start
();
await
evalFlutter
(
'build'
,
options:
<
String
>[
'web'
,
...
...
@@ -1091,7 +1093,7 @@ class WebCompileTest {
metrics
.
addAll
(
await
getSize
(
outputFileName
,
metric:
metric
));
if
(
measureBuildTime
)
{
metrics
[
'
${metric}
_dart2js_millis'
]
=
watch
.
elapsedMilliseconds
;
metrics
[
'
${metric}
_dart2js_millis'
]
=
watch
!
.
elapsedMilliseconds
;
}
return
metrics
;
...
...
@@ -1099,7 +1101,7 @@ class WebCompileTest {
}
/// Obtains the size and gzipped size of a file given by [fileName].
static
Future
<
Map
<
String
,
int
>>
getSize
(
String
fileName
,
{
String
metric
})
async
{
static
Future
<
Map
<
String
,
int
>>
getSize
(
String
fileName
,
{
required
String
metric
})
async
{
final
Map
<
String
,
int
>
sizeMetrics
=
<
String
,
int
>{};
final
ProcessResult
result
=
await
Process
.
run
(
'du'
,
<
String
>[
'-k'
,
fileName
]);
...
...
@@ -1168,10 +1170,12 @@ class CompileTest {
await
flutter
(
'build'
,
options:
options
);
watch
.
stop
();
final
Directory
appBuildDirectory
=
dir
(
path
.
join
(
cwd
,
'build/ios/Release-iphoneos'
));
final
Directory
appBundle
=
appBuildDirectory
final
Directory
?
appBundle
=
appBuildDirectory
.
listSync
()
.
whereType
<
Directory
>()
.
singleWhere
((
Directory
directory
)
=>
path
.
extension
(
directory
.
path
)
==
'.app'
,
orElse:
()
=>
null
);
.
whereType
<
Directory
?>()
.
singleWhere
((
Directory
?
directory
)
=>
directory
!=
null
&&
path
.
extension
(
directory
.
path
)
==
'.app'
,
orElse:
()
=>
null
);
if
(
appBundle
==
null
)
{
throw
'Failed to find app bundle in
${appBuildDirectory.path}
'
;
}
...
...
@@ -1226,8 +1230,8 @@ class CompileTest {
}
static
Future
<
Map
<
String
,
dynamic
>>
_compileDebug
({
@
required
bool
clean
,
@
required
String
metricKey
,
required
bool
clean
,
required
String
metricKey
,
})
async
{
if
(
clean
)
{
await
flutter
(
'clean'
);
...
...
@@ -1290,9 +1294,9 @@ class CompileTest {
fileToMetadata
[
entry
.
path
]
=
entry
;
}
final
_UnzipListEntry
libflutter
=
fileToMetadata
[
'lib/armeabi-v7a/libflutter.so'
];
final
_UnzipListEntry
libapp
=
fileToMetadata
[
'lib/armeabi-v7a/libapp.so'
];
final
_UnzipListEntry
license
=
fileToMetadata
[
'assets/flutter_assets/NOTICES.Z'
];
final
_UnzipListEntry
libflutter
=
fileToMetadata
[
'lib/armeabi-v7a/libflutter.so'
]
!
;
final
_UnzipListEntry
libapp
=
fileToMetadata
[
'lib/armeabi-v7a/libapp.so'
]
!
;
final
_UnzipListEntry
license
=
fileToMetadata
[
'assets/flutter_assets/NOTICES.Z'
]
!
;
return
<
String
,
dynamic
>{
'libflutter_uncompressed_bytes'
:
libflutter
.
uncompressedSize
,
...
...
@@ -1315,9 +1319,9 @@ class MemoryTest {
/// Completes when the log line specified in the last call to
/// [prepareForNextMessage] is seen by `adb logcat`.
Future
<
void
>
get
receivedNextMessage
=>
_receivedNextMessage
?.
future
;
Completer
<
void
>
_receivedNextMessage
;
String
_nextMessage
;
Future
<
void
>
?
get
receivedNextMessage
=>
_receivedNextMessage
?.
future
;
Completer
<
void
>
?
_receivedNextMessage
;
String
?
_nextMessage
;
/// Prepares the [receivedNextMessage] future such that it will complete
/// when `adb logcat` sees a log line with the given `message`.
...
...
@@ -1328,8 +1332,8 @@ class MemoryTest {
int
get
iterationCount
=>
10
;
Device
get
device
=>
_device
;
Device
_device
;
Device
?
get
device
=>
_device
;
Device
?
_device
;
Future
<
TaskResult
>
run
()
{
return
inDirectory
<
TaskResult
>(
project
,
()
async
{
...
...
@@ -1337,13 +1341,13 @@ class MemoryTest {
// device.getMemoryStats, etc, aren't implemented for iOS.
_device
=
await
devices
.
workingDevice
;
await
device
.
unlock
();
await
device
!
.
unlock
();
await
flutter
(
'packages'
,
options:
<
String
>[
'get'
]);
final
StreamSubscription
<
String
>
adb
=
device
.
logcat
.
listen
(
final
StreamSubscription
<
String
>
adb
=
device
!
.
logcat
.
listen
(
(
String
data
)
{
if
(
data
.
contains
(
'==== MEMORY BENCHMARK ====
$_nextMessage
===='
))
_receivedNextMessage
.
complete
();
_receivedNextMessage
?
.
complete
();
},
);
...
...
@@ -1356,12 +1360,12 @@ class MemoryTest {
assert
(
_endMemory
.
length
==
iteration
+
1
);
assert
(
_diffMemory
.
length
==
iteration
+
1
);
print
(
'terminating...'
);
await
device
.
stop
(
package
);
await
device
!
.
stop
(
package
);
await
Future
<
void
>.
delayed
(
const
Duration
(
milliseconds:
10
));
}
await
adb
.
cancel
();
await
flutter
(
'install'
,
options:
<
String
>[
'--uninstall-only'
,
'-d'
,
device
.
deviceId
]);
await
flutter
(
'install'
,
options:
<
String
>[
'--uninstall-only'
,
'-d'
,
device
!
.
deviceId
]);
final
ListStatistics
startMemoryStatistics
=
ListStatistics
(
_startMemory
);
final
ListStatistics
endMemoryStatistics
=
ListStatistics
(
_endMemory
);
...
...
@@ -1392,7 +1396,7 @@ class MemoryTest {
'--verbose'
,
'--release'
,
'--no-resident'
,
'-d'
,
device
.
deviceId
,
'-d'
,
device
!
.
deviceId
,
test
,
]);
print
(
'awaiting "ready" message...'
);
...
...
@@ -1411,7 +1415,7 @@ class MemoryTest {
prepareForNextMessage
(
'DONE'
);
print
(
'tapping device...'
);
await
device
.
tap
(
100
,
100
);
await
device
!
.
tap
(
100
,
100
);
print
(
'awaiting "done" message...'
);
await
receivedNextMessage
;
...
...
@@ -1422,23 +1426,23 @@ class MemoryTest {
final
List
<
int
>
_endMemory
=
<
int
>[];
final
List
<
int
>
_diffMemory
=
<
int
>[];
Map
<
String
,
dynamic
>
_startMemoryUsage
;
Map
<
String
,
dynamic
>
?
_startMemoryUsage
;
@protected
Future
<
void
>
recordStart
()
async
{
assert
(
_startMemoryUsage
==
null
);
print
(
'snapshotting memory usage...'
);
_startMemoryUsage
=
await
device
.
getMemoryStats
(
package
);
_startMemoryUsage
=
await
device
!
.
getMemoryStats
(
package
);
}
@protected
Future
<
void
>
recordEnd
()
async
{
assert
(
_startMemoryUsage
!=
null
);
print
(
'snapshotting memory usage...'
);
final
Map
<
String
,
dynamic
>
endMemoryUsage
=
await
device
.
getMemoryStats
(
package
);
_startMemory
.
add
(
_startMemoryUsage
[
'total_kb'
]
as
int
);
final
Map
<
String
,
dynamic
>
endMemoryUsage
=
await
device
!
.
getMemoryStats
(
package
);
_startMemory
.
add
(
_startMemoryUsage
!
[
'total_kb'
]
as
int
);
_endMemory
.
add
(
endMemoryUsage
[
'total_kb'
]
as
int
);
_diffMemory
.
add
((
endMemoryUsage
[
'total_kb'
]
as
int
)
-
(
_startMemoryUsage
[
'total_kb'
]
as
int
));
_diffMemory
.
add
((
endMemoryUsage
[
'total_kb'
]
as
int
)
-
(
_startMemoryUsage
!
[
'total_kb'
]
as
int
));
}
}
...
...
@@ -1487,7 +1491,7 @@ class DevToolsMemoryTest {
});
}
Device
_device
;
late
Device
_device
;
static
const
String
_kJsonFileName
=
'devtools_memory.json'
;
}
...
...
@@ -1505,7 +1509,6 @@ String _reportedDurationTestToString(ReportedDurationTestFlavor flavor) {
case
ReportedDurationTestFlavor
.
release
:
return
'release'
;
}
throw
ArgumentError
(
'Unexpected value for enum
$flavor
'
);
}
class
ReportedDurationTest
{
...
...
@@ -1521,8 +1524,8 @@ class ReportedDurationTest {
int
get
iterationCount
=>
10
;
Device
get
device
=>
_device
;
Device
_device
;
Device
?
get
device
=>
_device
;
Device
?
_device
;
Future
<
TaskResult
>
run
()
{
return
inDirectory
<
TaskResult
>(
project
,
()
async
{
...
...
@@ -1530,13 +1533,13 @@ class ReportedDurationTest {
// device.getMemoryStats, etc, aren't implemented for iOS.
_device
=
await
devices
.
workingDevice
;
await
device
.
unlock
();
await
device
!
.
unlock
();
await
flutter
(
'packages'
,
options:
<
String
>[
'get'
]);
final
StreamSubscription
<
String
>
adb
=
device
.
logcat
.
listen
(
final
StreamSubscription
<
String
>
adb
=
device
!
.
logcat
.
listen
(
(
String
data
)
{
if
(
durationPattern
.
hasMatch
(
data
))
durationCompleter
.
complete
(
int
.
parse
(
durationPattern
.
firstMatch
(
data
)
.
group
(
1
)
));
durationCompleter
.
complete
(
int
.
parse
(
durationPattern
.
firstMatch
(
data
)
!.
group
(
1
)!
));
},
);
print
(
'launching
$project$test
on device...'
);
...
...
@@ -1546,13 +1549,13 @@ class ReportedDurationTest {
'--no-fast-start'
,
'--
${_reportedDurationTestToString(flavor)}
'
,
'--no-resident'
,
'-d'
,
device
.
deviceId
,
'-d'
,
device
!
.
deviceId
,
test
,
]);
final
int
duration
=
await
durationCompleter
.
future
;
print
(
'terminating...'
);
await
device
.
stop
(
package
);
await
device
!
.
stop
(
package
);
await
adb
.
cancel
();
_device
=
null
;
...
...
@@ -1607,9 +1610,9 @@ class _UnzipListEntry {
}
_UnzipListEntry
.
_
({
@
required
this
.
uncompressedSize
,
@
required
this
.
compressedSize
,
@
required
this
.
path
,
required
this
.
uncompressedSize
,
required
this
.
compressedSize
,
required
this
.
path
,
})
:
assert
(
uncompressedSize
!=
null
),
assert
(
compressedSize
!=
null
),
assert
(
compressedSize
<=
uncompressedSize
),
...
...
@@ -1633,7 +1636,7 @@ Future<File> waitForFile(String path) async {
throw
StateError
(
'Did not find vmservice out file after 400 seconds'
);
}
String
_findIosAppInBuildDirectory
(
String
searchDirectory
)
{
String
?
_findIosAppInBuildDirectory
(
String
searchDirectory
)
{
for
(
final
FileSystemEntity
entity
in
Directory
(
searchDirectory
).
listSync
())
{
if
(
entity
.
path
.
endsWith
(
'.app'
))
{
return
entity
.
path
;
...
...
dev/devicelab/lib/tasks/platform_channels_benchmarks.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
show
Process
,
Directory
;
import
'package:flutter_devicelab/framework/devices.dart'
as
adb
;
...
...
dev/devicelab/lib/tasks/plugin_tests.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:io'
;
import
'package:flutter_devicelab/framework/framework.dart'
;
...
...
@@ -31,8 +29,8 @@ class PluginTest {
final
String
buildTarget
;
final
List
<
String
>
options
;
final
Map
<
String
,
String
>
pluginCreateEnvironment
;
final
Map
<
String
,
String
>
appCreateEnvironment
;
final
Map
<
String
,
String
>
?
pluginCreateEnvironment
;
final
Map
<
String
,
String
>
?
appCreateEnvironment
;
Future
<
TaskResult
>
call
()
async
{
final
Directory
tempDir
=
...
...
@@ -77,7 +75,7 @@ class _FlutterProject {
String
get
rootPath
=>
path
.
join
(
parent
.
path
,
name
);
Future
<
void
>
addPlugin
(
String
plugin
,
{
String
pluginPath
})
async
{
Future
<
void
>
addPlugin
(
String
plugin
,
{
String
?
pluginPath
})
async
{
final
File
pubspec
=
File
(
path
.
join
(
rootPath
,
'pubspec.yaml'
));
String
content
=
await
pubspec
.
readAsString
();
final
String
dependency
=
...
...
@@ -100,9 +98,9 @@ class _FlutterProject {
List
<
String
>
options
,
String
target
,
{
String
name
,
String
template
,
Map
<
String
,
String
>
environment
,
required
String
name
,
required
String
template
,
Map
<
String
,
String
>
?
environment
,
})
async
{
await
inDirectory
(
directory
,
()
async
{
await
flutter
(
...
...
dev/devicelab/lib/tasks/web_benchmarks.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
show
json
;
import
'dart:io'
as
io
;
...
...
@@ -13,7 +11,6 @@ import 'package:flutter_devicelab/framework/browser.dart';
import
'package:flutter_devicelab/framework/task_result.dart'
;
import
'package:flutter_devicelab/framework/utils.dart'
;
import
'package:logging/logging.dart'
;
import
'package:meta/meta.dart'
;
import
'package:path/path.dart'
as
path
;
import
'package:shelf/shelf.dart'
;
import
'package:shelf/shelf_io.dart'
as
shelf_io
;
...
...
@@ -23,7 +20,7 @@ import 'package:shelf_static/shelf_static.dart';
const
int
benchmarkServerPort
=
9999
;
const
int
chromeDebugPort
=
10000
;
Future
<
TaskResult
>
runWebBenchmark
({
@
required
bool
useCanvasKit
})
async
{
Future
<
TaskResult
>
runWebBenchmark
({
required
bool
useCanvasKit
})
async
{
// Reduce logging level. Otherwise, package:webkit_inspection_protocol is way too spammy.
Logger
.
root
.
level
=
Level
.
INFO
;
final
String
macrobenchmarksDirectory
=
path
.
join
(
flutterDirectory
.
path
,
'dev'
,
'benchmarks'
,
'macrobenchmarks'
);
...
...
@@ -38,17 +35,17 @@ Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
]);
final
Completer
<
List
<
Map
<
String
,
dynamic
>>>
profileData
=
Completer
<
List
<
Map
<
String
,
dynamic
>>>();
final
List
<
Map
<
String
,
dynamic
>>
collectedProfiles
=
<
Map
<
String
,
dynamic
>>[];
List
<
String
>
benchmarks
;
Iterator
<
String
>
benchmarkIterator
;
List
<
String
>
?
benchmarks
;
late
Iterator
<
String
>
benchmarkIterator
;
// This future fixes a race condition between the web-page loading and
// asking to run a benchmark, and us connecting to Chrome's DevTools port.
// Sometime one wins. Other times, the other wins.
Future
<
Chrome
>
whenChromeIsReady
;
Chrome
chrome
;
io
.
HttpServer
server
;
Future
<
Chrome
>
?
whenChromeIsReady
;
Chrome
?
chrome
;
late
io
.
HttpServer
server
;
Cascade
cascade
=
Cascade
();
List
<
Map
<
String
,
dynamic
>>
latestPerformanceTrace
;
List
<
Map
<
String
,
dynamic
>>
?
latestPerformanceTrace
;
cascade
=
cascade
.
add
((
Request
request
)
async
{
try
{
chrome
??=
await
whenChromeIsReady
;
...
...
@@ -66,7 +63,7 @@ Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
// Trace data is null when the benchmark is not frame-based, such as RawRecorder.
if
(
latestPerformanceTrace
!=
null
)
{
final
BlinkTraceSummary
traceSummary
=
BlinkTraceSummary
.
fromJson
(
latestPerformanceTrace
)
;
final
BlinkTraceSummary
traceSummary
=
BlinkTraceSummary
.
fromJson
(
latestPerformanceTrace
!)!
;
profile
[
'totalUiFrame.average'
]
=
traceSummary
.
averageTotalUIFrameTime
.
inMicroseconds
;
profile
[
'scoreKeys'
]
??=
<
dynamic
>[];
// using dynamic for consistency with JSON
(
profile
[
'scoreKeys'
]
as
List
<
dynamic
>).
add
(
'totalUiFrame.average'
);
...
...
@@ -76,10 +73,10 @@ Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
return
Response
.
ok
(
'Profile received'
);
}
else
if
(
request
.
requestedUri
.
path
.
endsWith
(
'/start-performance-tracing'
))
{
latestPerformanceTrace
=
null
;
await
chrome
.
beginRecordingPerformance
(
request
.
requestedUri
.
queryParameters
[
'label'
]
);
await
chrome
!.
beginRecordingPerformance
(
request
.
requestedUri
.
queryParameters
[
'label'
]!
);
return
Response
.
ok
(
'Started performance tracing'
);
}
else
if
(
request
.
requestedUri
.
path
.
endsWith
(
'/stop-performance-tracing'
))
{
latestPerformanceTrace
=
await
chrome
.
endRecordingPerformance
();
latestPerformanceTrace
=
await
chrome
!
.
endRecordingPerformance
();
return
Response
.
ok
(
'Stopped performance tracing'
);
}
else
if
(
request
.
requestedUri
.
path
.
endsWith
(
'/on-error'
))
{
final
Map
<
String
,
dynamic
>
errorDetails
=
json
.
decode
(
await
request
.
readAsString
())
as
Map
<
String
,
dynamic
>;
...
...
@@ -90,7 +87,7 @@ Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
}
else
if
(
request
.
requestedUri
.
path
.
endsWith
(
'/next-benchmark'
))
{
if
(
benchmarks
==
null
)
{
benchmarks
=
(
json
.
decode
(
await
request
.
readAsString
())
as
List
<
dynamic
>).
cast
<
String
>();
benchmarkIterator
=
benchmarks
.
iterator
;
benchmarkIterator
=
benchmarks
!
.
iterator
;
}
if
(
benchmarkIterator
.
moveNext
())
{
final
String
nextBenchmark
=
benchmarkIterator
.
current
;
...
...
@@ -186,7 +183,7 @@ Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
}
return
TaskResult
.
success
(
taskResult
,
benchmarkScoreKeys:
benchmarkScoreKeys
);
}
finally
{
unawaited
(
server
?
.
close
());
unawaited
(
server
.
close
());
chrome
?.
stop
();
}
});
...
...
dev/devicelab/lib/tasks/web_dev_mode_tests.dart
View file @
ef5ffd08
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
...
...
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