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
a19f5bac
Unverified
Commit
a19f5bac
authored
Sep 19, 2020
by
Jonah Williams
Committed by
GitHub
Sep 19, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] connect widget cache from frontend_server (#65951)
parent
ae630b42
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
281 additions
and
411 deletions
+281
-411
binding.dart
packages/flutter/lib/src/widgets/binding.dart
+6
-41
service_extensions_test.dart
...ages/flutter/test/foundation/service_extensions_test.dart
+0
-4
resident_web_runner.dart
...utter_tools/lib/src/build_runner/resident_web_runner.dart
+1
-0
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+0
-3
daemon.dart
packages/flutter_tools/lib/src/commands/daemon.dart
+0
-3
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+0
-2
devfs.dart
packages/flutter_tools/lib/src/devfs.dart
+25
-9
features.dart
packages/flutter_tools/lib/src/features.dart
+1
-0
events.dart
packages/flutter_tools/lib/src/reporting/events.dart
+4
-0
usage.dart
packages/flutter_tools/lib/src/reporting/usage.dart
+1
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+25
-72
run_hot.dart
packages/flutter_tools/lib/src/run_hot.dart
+12
-2
vmservice.dart
packages/flutter_tools/lib/src/vmservice.dart
+4
-1
widget_cache.dart
packages/flutter_tools/lib/src/widget_cache.dart
+0
-28
resident_runner_test.dart
...lutter_tools/test/general.shard/resident_runner_test.dart
+38
-155
widget_cache_test.dart
...s/flutter_tools/test/general.shard/widget_cache_test.dart
+0
-22
hot_reload_test.dart
...flutter_tools/test/integration.shard/hot_reload_test.dart
+0
-68
single_widget_reload_test.dart
...ols/test/integration.shard/single_widget_reload_test.dart
+63
-0
single_widget_reload_project.dart
...gration.shard/test_data/single_widget_reload_project.dart
+86
-0
test_driver.dart
...ges/flutter_tools/test/integration.shard/test_driver.dart
+15
-1
No files found.
packages/flutter/lib/src/widgets/binding.dart
View file @
a19f5bac
...
...
@@ -433,21 +433,16 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
registerServiceExtension
(
name:
'fastReassemble'
,
callback:
(
Map
<
String
,
Object
>
params
)
async
{
final
FastReassemblePredicate
?
fastReassemblePredicate
=
_debugFastReassembleMethod
;
_debugFastReassembleMethod
=
null
;
if
(
fastReassemblePredicate
==
null
)
{
throw
FlutterError
(
'debugFastReassembleMethod must be set to use fastReassemble.'
);
}
void
markElementsDirty
(
Element
?
element
)
{
if
(
element
==
null
)
{
return
;
}
if
(
fastReassemblePredicate
(
element
.
widget
))
{
final
String
?
className
=
params
[
'className'
]
as
String
?;
void
markElementsDirty
(
Element
element
)
{
if
(
element
.
widget
.
runtimeType
.
toString
()
==
className
)
{
element
.
markNeedsBuild
();
}
element
.
visitChildElements
(
markElementsDirty
);
}
markElementsDirty
(
renderViewElement
);
if
(
renderViewElement
!=
null
)
{
markElementsDirty
(
renderViewElement
!);
}
await
endOfFrame
;
return
<
String
,
String
>{
'type'
:
'Success'
};
},
...
...
@@ -1061,36 +1056,6 @@ void runApp(Widget app) {
..
scheduleWarmUpFrame
();
}
/// A function that should validate that the provided object is assignable to a
/// given type.
typedef
FastReassemblePredicate
=
bool
Function
(
Object
);
/// Debug-only functionality used to perform faster hot reloads.
///
/// This field is set by expression evaluation in the flutter tool and is
/// used to invalidate specific types of [Element]s. This setter
/// should not be referenced in user code and is only public so that expression
/// evaluation can be done in the context of an almost-arbitrary Dart library.
///
/// For example, expression evaluation might be performed with the following code:
///
/// ```dart
/// (debugFastReassembleMethod=(Object x) => x is Foo)()
/// ```
///
/// And then followed by a call to `ext.flutter.fastReassemble`. This will read
/// the provided predicate and use it to mark specific elements dirty wherever
/// [Element.widget] is a `Foo`. Afterwards, the internal field will be nulled
/// out.
FastReassemblePredicate
?
get
debugFastReassembleMethod
=>
_debugFastReassembleMethod
;
set
debugFastReassembleMethod
(
FastReassemblePredicate
?
fastReassemblePredicate
)
{
assert
(()
{
_debugFastReassembleMethod
=
fastReassemblePredicate
;
return
true
;
}());
}
FastReassemblePredicate
?
_debugFastReassembleMethod
;
/// Print a string representation of the currently running app.
void
debugDumpApp
(
)
{
assert
(
WidgetsBinding
.
instance
!=
null
);
...
...
packages/flutter/test/foundation/service_extensions_test.dart
View file @
a19f5bac
...
...
@@ -740,8 +740,4 @@ void main() {
expect
(
brightnessValue
,
'Brightness.light'
);
});
test
(
'Service extensions - fastReassemble'
,
()
async
{
expect
(
binding
.
testExtension
(
'fastReassemble'
,
<
String
,
String
>{}),
throwsA
(
isA
<
FlutterError
>()));
});
}
packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
View file @
a19f5bac
...
...
@@ -588,6 +588,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
reason:
reason
,
overallTimeInMs:
timer
.
elapsed
.
inMilliseconds
,
nullSafety:
usageNullSafety
,
fastReassemble:
null
,
).
send
();
}
return
OperationResult
.
ok
;
...
...
packages/flutter_tools/lib/src/commands/attach.dart
View file @
a19f5bac
...
...
@@ -15,7 +15,6 @@ import '../base/io.dart';
import
'../commands/daemon.dart'
;
import
'../compile.dart'
;
import
'../device.dart'
;
import
'../features.dart'
;
import
'../fuchsia/fuchsia_device.dart'
;
import
'../globals.dart'
as
globals
;
import
'../ios/devices.dart'
;
...
...
@@ -27,7 +26,6 @@ import '../resident_runner.dart';
import
'../run_cold.dart'
;
import
'../run_hot.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../widget_cache.dart'
;
/// A Flutter-command that attaches to applications that have been launched
/// without `flutter run`.
...
...
@@ -384,7 +382,6 @@ class AttachCommand extends FlutterCommand {
targetModel:
TargetModel
(
stringArg
(
'target-model'
)),
buildInfo:
getBuildInfo
(),
userIdentifier:
userIdentifier
,
widgetCache:
WidgetCache
(
featureFlags:
featureFlags
),
);
flutterDevice
.
observatoryUris
=
observatoryUris
;
final
List
<
FlutterDevice
>
flutterDevices
=
<
FlutterDevice
>[
flutterDevice
];
...
...
packages/flutter_tools/lib/src/commands/daemon.dart
View file @
a19f5bac
...
...
@@ -19,7 +19,6 @@ import '../build_info.dart';
import
'../convert.dart'
;
import
'../device.dart'
;
import
'../emulator.dart'
;
import
'../features.dart'
;
import
'../globals.dart'
as
globals
;
import
'../project.dart'
;
import
'../resident_runner.dart'
;
...
...
@@ -27,7 +26,6 @@ import '../run_cold.dart';
import
'../run_hot.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../web/web_runner.dart'
;
import
'../widget_cache.dart'
;
const
String
protocolVersion
=
'0.6.0'
;
...
...
@@ -472,7 +470,6 @@ class AppDomain extends Domain {
flutterProject:
flutterProject
,
target:
target
,
buildInfo:
options
.
buildInfo
,
widgetCache:
WidgetCache
(
featureFlags:
featureFlags
),
);
ResidentRunner
runner
;
...
...
packages/flutter_tools/lib/src/commands/run.dart
View file @
a19f5bac
...
...
@@ -23,7 +23,6 @@ import '../run_hot.dart';
import
'../runner/flutter_command.dart'
;
import
'../tracing.dart'
;
import
'../web/web_runner.dart'
;
import
'../widget_cache.dart'
;
import
'daemon.dart'
;
abstract
class
RunCommandBase
extends
FlutterCommand
with
DeviceBasedDevelopmentArtifacts
{
...
...
@@ -532,7 +531,6 @@ class RunCommand extends RunCommandBase {
target:
stringArg
(
'target'
),
buildInfo:
getBuildInfo
(),
userIdentifier:
userIdentifier
,
widgetCache:
WidgetCache
(
featureFlags:
featureFlags
),
),
];
// Only support "web mode" with a single web device due to resident runner
...
...
packages/flutter_tools/lib/src/devfs.dart
View file @
a19f5bac
...
...
@@ -302,7 +302,7 @@ class UpdateFSReport {
bool
success
=
false
,
int
invalidatedSourcesCount
=
0
,
int
syncedBytes
=
0
,
this
.
fastReassemble
,
this
.
fastReassemble
ClassName
,
})
:
_success
=
success
,
_invalidatedSourcesCount
=
invalidatedSourcesCount
,
_syncedBytes
=
syncedBytes
;
...
...
@@ -312,7 +312,7 @@ class UpdateFSReport {
int
get
syncedBytes
=>
_syncedBytes
;
bool
_success
;
bool
fastReassembl
e
;
String
fastReassembleClassNam
e
;
int
_invalidatedSourcesCount
;
int
_syncedBytes
;
...
...
@@ -320,11 +320,7 @@ class UpdateFSReport {
if
(!
report
.
_success
)
{
_success
=
false
;
}
if
(
report
.
fastReassemble
!=
null
&&
fastReassemble
!=
null
)
{
fastReassemble
&=
report
.
fastReassemble
;
}
else
if
(
report
.
fastReassemble
!=
null
)
{
fastReassemble
=
report
.
fastReassemble
;
}
fastReassembleClassName
??=
report
.
fastReassembleClassName
;
_invalidatedSourcesCount
+=
report
.
_invalidatedSourcesCount
;
_syncedBytes
+=
report
.
_syncedBytes
;
}
...
...
@@ -365,6 +361,7 @@ class DevFS {
List
<
Uri
>
sources
=
<
Uri
>[];
DateTime
lastCompiled
;
PackageConfig
lastPackageConfig
;
File
_widgetCacheOutputFile
;
Uri
_baseUri
;
Uri
get
baseUri
=>
_baseUri
;
...
...
@@ -404,6 +401,20 @@ class DevFS {
_logger
.
printTrace
(
'DevFS: Deleted filesystem on the device (
$_baseUri
)'
);
}
/// If the build method of a single widget was modified, return the widget name.
///
/// If any other changes were made, or there is an error scanning the file,
/// return `null`.
String
_checkIfSingleWidgetReloadApplied
()
{
if
(
_widgetCacheOutputFile
!=
null
&&
_widgetCacheOutputFile
.
existsSync
())
{
final
String
widget
=
_widgetCacheOutputFile
.
readAsStringSync
().
trim
();
if
(
widget
.
isNotEmpty
)
{
return
widget
;
}
}
return
null
;
}
/// Updates files on the device.
///
/// Returns the number of bytes synced.
...
...
@@ -427,6 +438,7 @@ class DevFS {
assert
(
generator
!=
null
);
final
DateTime
candidateCompileTime
=
DateTime
.
now
();
lastPackageConfig
=
packageConfig
;
_widgetCacheOutputFile
=
_fileSystem
.
file
(
'
$dillOutputPath
.incremental.dill.widget_cache'
);
// Update modified files
final
Map
<
Uri
,
DevFSContent
>
dirtyEntries
=
<
Uri
,
DevFSContent
>{};
...
...
@@ -502,8 +514,12 @@ class DevFS {
}
}
_logger
.
printTrace
(
'DevFS: Sync finished'
);
return
UpdateFSReport
(
success:
true
,
syncedBytes:
syncedBytes
,
invalidatedSourcesCount:
invalidatedFiles
.
length
);
return
UpdateFSReport
(
success:
true
,
syncedBytes:
syncedBytes
,
invalidatedSourcesCount:
invalidatedFiles
.
length
,
fastReassembleClassName:
_checkIfSingleWidgetReloadApplied
(),
);
}
/// Converts a platform-specific file path to a platform-independent URL path.
...
...
packages/flutter_tools/lib/src/features.dart
View file @
a19f5bac
...
...
@@ -239,6 +239,7 @@ const Feature flutterFuchsiaFeature = Feature(
const
Feature
singleWidgetReload
=
Feature
(
name:
'Hot reload optimization for changes to class body of a single widget'
,
configSetting:
'single-widget-reload-optimization'
,
environmentOverride:
'FLUTTER_SINGLE_WIDGET_RELOAD'
,
master:
FeatureChannelSetting
(
available:
true
,
enabledByDefault:
false
,
...
...
packages/flutter_tools/lib/src/reporting/events.dart
View file @
a19f5bac
...
...
@@ -40,6 +40,7 @@ class HotEvent extends UsageEvent {
@required
this
.
emulator
,
@required
this
.
fullRestart
,
@required
this
.
nullSafety
,
@required
this
.
fastReassemble
,
this
.
reason
,
this
.
finalLibraryCount
,
this
.
syncedLibraryCount
,
...
...
@@ -57,6 +58,7 @@ class HotEvent extends UsageEvent {
final
bool
emulator
;
final
bool
fullRestart
;
final
bool
nullSafety
;
final
bool
fastReassemble
;
final
int
finalLibraryCount
;
final
int
syncedLibraryCount
;
final
int
syncedClassesCount
;
...
...
@@ -93,6 +95,8 @@ class HotEvent extends UsageEvent {
CustomDimensions
.
hotEventOverallTimeInMs
:
overallTimeInMs
.
toString
(),
if
(
nullSafety
!=
null
)
CustomDimensions
.
nullSafety
:
nullSafety
.
toString
(),
if
(
fastReassemble
!=
null
)
CustomDimensions
.
fastReassemble
:
fastReassemble
.
toString
(),
});
flutterUsage
.
sendEvent
(
category
,
parameter
,
parameters:
parameters
);
}
...
...
packages/flutter_tools/lib/src/reporting/usage.dart
View file @
a19f5bac
...
...
@@ -58,6 +58,7 @@ enum CustomDimensions {
commandRunAndroidEmbeddingVersion
,
// cd45
commandPackagesAndroidEmbeddingVersion
,
// cd46
nullSafety
,
// cd47
fastReassemble
,
// cd48
}
String
cdKey
(
CustomDimensions
cd
)
=>
'cd
${cd.index + 1}
'
;
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
a19f5bac
...
...
@@ -34,7 +34,6 @@ import 'project.dart';
import
'run_cold.dart'
;
import
'run_hot.dart'
;
import
'vmservice.dart'
;
import
'widget_cache.dart'
;
class
FlutterDevice
{
FlutterDevice
(
...
...
@@ -46,7 +45,6 @@ class FlutterDevice {
TargetPlatform
targetPlatform
,
ResidentCompiler
generator
,
this
.
userIdentifier
,
this
.
widgetCache
,
})
:
assert
(
buildInfo
.
trackWidgetCreation
!=
null
),
generator
=
generator
??
ResidentCompiler
(
globals
.
artifacts
.
getArtifactPath
(
...
...
@@ -79,7 +77,6 @@ class FlutterDevice {
List
<
String
>
experimentalFlags
,
ResidentCompiler
generator
,
String
userIdentifier
,
WidgetCache
widgetCache
,
})
async
{
ResidentCompiler
generator
;
final
TargetPlatform
targetPlatform
=
await
device
.
targetPlatform
;
...
...
@@ -134,6 +131,14 @@ class FlutterDevice {
logger:
globals
.
logger
,
);
}
else
{
// The flutter-widget-cache feature only applies to run mode.
List
<
String
>
extraFrontEndOptions
=
buildInfo
.
extraFrontEndOptions
;
if
(
featureFlags
.
isSingleWidgetReloadEnabled
)
{
extraFrontEndOptions
=
<
String
>[
'--flutter-widget-cache'
,
...?
extraFrontEndOptions
,
];
}
generator
=
ResidentCompiler
(
globals
.
artifacts
.
getArtifactPath
(
Artifact
.
flutterPatchedSdkPath
,
...
...
@@ -146,11 +151,11 @@ class FlutterDevice {
fileSystemScheme:
fileSystemScheme
,
targetModel:
targetModel
,
dartDefines:
buildInfo
.
dartDefines
,
extraFrontEndOptions:
buildInfo
.
extraFrontEndOptions
,
extraFrontEndOptions:
extraFrontEndOptions
,
initializeFromDill:
getDefaultCachedKernelPath
(
trackWidgetCreation:
buildInfo
.
trackWidgetCreation
,
dartDefines:
buildInfo
.
dartDefines
,
extraFrontEndOptions:
buildInfo
.
extraFrontEndOptions
,
extraFrontEndOptions:
extraFrontEndOptions
,
),
packagesPath:
buildInfo
.
packagesPath
,
artifacts:
globals
.
artifacts
,
...
...
@@ -168,7 +173,6 @@ class FlutterDevice {
generator:
generator
,
buildInfo:
buildInfo
,
userIdentifier:
userIdentifier
,
widgetCache:
widgetCache
,
);
}
...
...
@@ -176,7 +180,6 @@ class FlutterDevice {
final
ResidentCompiler
generator
;
final
BuildInfo
buildInfo
;
final
String
userIdentifier
;
final
WidgetCache
widgetCache
;
Stream
<
Uri
>
observatoryUris
;
vm_service
.
VmService
vmService
;
DevFS
devFS
;
...
...
@@ -655,44 +658,6 @@ class FlutterDevice {
return
0
;
}
/// Validates whether this hot reload is a candidate for a fast reassemble.
Future
<
bool
>
_attemptFastReassembleCheck
(
List
<
Uri
>
invalidatedFiles
,
PackageConfig
packageConfig
)
async
{
if
(
invalidatedFiles
.
length
!=
1
||
widgetCache
==
null
)
{
return
false
;
}
final
List
<
FlutterView
>
views
=
await
vmService
.
getFlutterViews
();
final
String
widgetName
=
await
widgetCache
?.
validateLibrary
(
invalidatedFiles
.
single
);
if
(
widgetName
==
null
)
{
return
false
;
}
final
String
packageUri
=
packageConfig
.
toPackageUri
(
invalidatedFiles
.
single
)?.
toString
()
??
invalidatedFiles
.
single
.
toString
();
for
(
final
FlutterView
view
in
views
)
{
final
vm_service
.
Isolate
isolate
=
await
vmService
.
getIsolateOrNull
(
view
.
uiIsolate
.
id
);
final
vm_service
.
LibraryRef
targetLibrary
=
isolate
.
libraries
.
firstWhere
(
(
vm_service
.
LibraryRef
libraryRef
)
=>
libraryRef
.
uri
==
packageUri
,
orElse:
()
=>
null
,
);
if
(
targetLibrary
==
null
)
{
return
false
;
}
try
{
// Evaluate an expression to allow type checking for that invalidated widget
// name. For more information, see `debugFastReassembleMethod` in flutter/src/widgets/binding.dart
await
vmService
.
evaluate
(
view
.
uiIsolate
.
id
,
targetLibrary
.
id
,
'((){debugFastReassembleMethod=(Object _fastReassembleParam) => _fastReassembleParam is
$widgetName
})()'
,
);
}
on
Exception
catch
(
err
)
{
globals
.
printTrace
(
err
.
toString
());
return
false
;
}
}
return
true
;
}
Future
<
UpdateFSReport
>
updateDevFS
({
Uri
mainUri
,
String
target
,
...
...
@@ -712,10 +677,8 @@ class FlutterDevice {
timeout:
timeoutConfiguration
.
fastOperation
,
);
UpdateFSReport
report
;
bool
fastReassemble
=
false
;
try
{
await
Future
.
wait
(<
Future
<
void
>>[
devFS
.
update
(
report
=
await
devFS
.
update
(
mainUri:
mainUri
,
target:
target
,
bundle:
bundle
,
...
...
@@ -729,17 +692,7 @@ class FlutterDevice {
pathToReload:
pathToReload
,
invalidatedFiles:
invalidatedFiles
,
packageConfig:
packageConfig
,
).
then
((
UpdateFSReport
newReport
)
=>
report
=
newReport
),
if
(!
fullRestart
)
_attemptFastReassembleCheck
(
invalidatedFiles
,
packageConfig
,
).
then
((
bool
newFastReassemble
)
=>
fastReassemble
=
newFastReassemble
)
]);
if
(
fastReassemble
)
{
globals
.
logger
.
printTrace
(
'Attempting fast reassemble.'
);
}
report
.
fastReassemble
=
fastReassemble
;
);
}
on
DevFSException
{
devFSStatus
.
cancel
();
return
UpdateFSReport
(
success:
false
);
...
...
packages/flutter_tools/lib/src/run_hot.dart
View file @
a19f5bac
...
...
@@ -21,6 +21,7 @@ import 'convert.dart';
import
'dart/package_map.dart'
;
import
'devfs.dart'
;
import
'device.dart'
;
import
'features.dart'
;
import
'globals.dart'
as
globals
;
import
'reporting/reporting.dart'
;
import
'resident_runner.dart'
;
...
...
@@ -744,7 +745,9 @@ class HotRunner extends ResidentRunner {
emulator:
emulator
,
fullRestart:
true
,
nullSafety:
usageNullSafety
,
reason:
reason
).
send
();
reason:
reason
,
fastReassemble:
null
,
).
send
();
status
?.
cancel
();
}
return
result
;
...
...
@@ -787,6 +790,7 @@ class HotRunner extends ResidentRunner {
fullRestart:
false
,
nullSafety:
usageNullSafety
,
reason:
reason
,
fastReassemble:
null
,
).
send
();
return
OperationResult
(
1
,
'hot reload failed to complete'
,
fatal:
true
);
}
finally
{
...
...
@@ -866,6 +870,7 @@ class HotRunner extends ResidentRunner {
fullRestart:
false
,
reason:
reason
,
nullSafety:
usageNullSafety
,
fastReassemble:
null
,
).
send
();
return
OperationResult
(
1
,
'Reload rejected'
);
}
...
...
@@ -894,6 +899,7 @@ class HotRunner extends ResidentRunner {
fullRestart:
false
,
reason:
reason
,
nullSafety:
usageNullSafety
,
fastReassemble:
null
,
).
send
();
return
OperationResult
(
errorCode
,
errorMessage
);
}
...
...
@@ -936,9 +942,10 @@ class HotRunner extends ResidentRunner {
// If the tool identified a change in a single widget, do a fast instead
// of a full reassemble.
Future
<
void
>
reassembleWork
;
if
(
updatedDevFS
.
fastReassemble
==
true
)
{
if
(
updatedDevFS
.
fastReassemble
ClassName
!=
null
)
{
reassembleWork
=
device
.
vmService
.
flutterFastReassemble
(
isolateId:
view
.
uiIsolate
.
id
,
className:
updatedDevFS
.
fastReassembleClassName
,
);
}
else
{
reassembleWork
=
device
.
vmService
.
flutterReassemble
(
...
...
@@ -1030,6 +1037,9 @@ class HotRunner extends ResidentRunner {
invalidatedSourcesCount:
updatedDevFS
.
invalidatedSourcesCount
,
transferTimeInMs:
devFSTimer
.
elapsed
.
inMilliseconds
,
nullSafety:
usageNullSafety
,
fastReassemble:
featureFlags
.
isSingleWidgetReloadEnabled
?
updatedDevFS
.
fastReassembleClassName
!=
null
:
null
,
).
send
();
if
(
shouldReportReloadTime
)
{
...
...
packages/flutter_tools/lib/src/vmservice.dart
View file @
a19f5bac
...
...
@@ -628,11 +628,14 @@ extension FlutterVmService on vm_service.VmService {
Future
<
Map
<
String
,
dynamic
>>
flutterFastReassemble
({
@required
String
isolateId
,
@required
String
className
,
})
{
return
invokeFlutterExtensionRpcRaw
(
'ext.flutter.fastReassemble'
,
isolateId:
isolateId
,
args:
<
String
,
Object
>{},
args:
<
String
,
Object
>{
'className'
:
className
,
},
);
}
...
...
packages/flutter_tools/lib/src/widget_cache.dart
deleted
100644 → 0
View file @
ae630b42
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:meta/meta.dart'
;
import
'features.dart'
;
/// The widget cache determines if the body of a single widget was modified since
/// the last scan of the token stream.
class
WidgetCache
{
WidgetCache
({
@required
FeatureFlags
featureFlags
,
})
:
_featureFlags
=
featureFlags
;
final
FeatureFlags
_featureFlags
;
/// If the build method of a single widget was modified, return the widget name.
///
/// If any other changes were made, or there is an error scanning the file,
/// return `null`.
Future
<
String
>
validateLibrary
(
Uri
libraryUri
)
async
{
if
(!
_featureFlags
.
isSingleWidgetReloadEnabled
)
{
return
null
;
}
return
null
;
}
}
packages/flutter_tools/test/general.shard/resident_runner_test.dart
View file @
a19f5bac
...
...
@@ -6,7 +6,7 @@ import 'dart:async';
import
'package:flutter_tools/src/base/dds.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/
widget_cache
.dart'
;
import
'package:flutter_tools/src/
features
.dart'
;
import
'package:meta/meta.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:vm_service/vm_service.dart'
as
vm_service
;
...
...
@@ -714,22 +714,6 @@ void main() {
listViews
,
listViews
,
listViews
,
FakeVmServiceRequest
(
method:
'getIsolate'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
,
},
jsonResponse:
fakeUnpausedIsolate
.
toJson
(),
),
const
FakeVmServiceRequest
(
method:
'evaluate'
,
args:
<
String
,
String
>{
'isolateId'
:
'1'
,
'targetId'
:
'1'
,
'expression'
:
'((){debugFastReassembleMethod=(Object _fastReassembleParam) => _fastReassembleParam is FakeWidget})()'
,
}
),
listViews
,
const
FakeVmServiceRequest
(
method:
'_flutter.setAssetBundlePath'
,
args:
<
String
,
Object
>{
...
...
@@ -769,13 +753,13 @@ void main() {
method:
'ext.flutter.fastReassemble'
,
args:
<
String
,
Object
>{
'isolateId'
:
fakeUnpausedIsolate
.
id
,
'className'
:
'FOO'
,
},
),
]);
final
FakeFlutterDevice
flutterDevice
=
FakeFlutterDevice
(
mockDevice
,
BuildInfo
.
debug
,
FakeWidgetCache
(),
FakeResidentCompiler
(),
mockDevFS
,
)..
vmService
=
fakeVmServiceHost
.
vmService
;
...
...
@@ -811,7 +795,7 @@ void main() {
invalidatedFiles:
anyNamed
(
'invalidatedFiles'
),
packageConfig:
anyNamed
(
'packageConfig'
),
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
UpdateFSReport
(
success:
true
);
return
UpdateFSReport
(
success:
true
,
fastReassembleClassName:
'FOO'
);
});
final
Completer
<
DebugConnectionInfo
>
onConnectionInfo
=
Completer
<
DebugConnectionInfo
>.
sync
();
...
...
@@ -822,142 +806,21 @@ void main() {
));
final
OperationResult
result
=
await
residentRunner
.
restart
(
fullRestart:
false
);
expect
(
result
.
fatal
,
false
);
expect
(
result
.
code
,
0
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
Platform:
()
=>
FakePlatform
(
operatingSystem:
'linux'
),
ProjectFileInvalidator:
()
=>
FakeProjectFileInvalidator
(),
}));
testUsingContext
(
'ResidentRunner bails out of fast reassemble if evaluation fails'
,
()
=>
testbed
.
run
(()
async
{
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
listViews
,
FakeVmServiceRequest
(
method:
'getVM'
,
jsonResponse:
fakeVM
.
toJson
(),
),
listViews
,
listViews
,
listViews
,
FakeVmServiceRequest
(
method:
'getIsolate'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
,
},
jsonResponse:
fakeUnpausedIsolate
.
toJson
(),
),
const
FakeVmServiceRequest
(
method:
'evaluate'
,
args:
<
String
,
String
>{
'isolateId'
:
'1'
,
'targetId'
:
'1'
,
'expression'
:
'((){debugFastReassembleMethod=(Object _fastReassembleParam) => _fastReassembleParam is FakeWidget})()'
,
},
errorCode:
500
,
),
listViews
,
const
FakeVmServiceRequest
(
method:
'_flutter.setAssetBundlePath'
,
args:
<
String
,
Object
>{
'viewId'
:
'a'
,
'assetDirectory'
:
'build/flutter_assets'
,
'isolateId'
:
'1'
,
}
),
FakeVmServiceRequest
(
method:
'getVM'
,
jsonResponse:
fakeVM
.
toJson
(),
),
const
FakeVmServiceRequest
(
method:
'reloadSources'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
,
'pause'
:
false
,
'rootLibUri'
:
'lib/main.dart.incremental.dill'
,
},
jsonResponse:
<
String
,
Object
>{
'type'
:
'ReloadReport'
,
'success'
:
true
,
'details'
:
<
String
,
Object
>{
'loadedLibraryCount'
:
1
,
},
},
),
listViews
,
FakeVmServiceRequest
(
method:
'getIsolate'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
,
},
jsonResponse:
fakeUnpausedIsolate
.
toJson
(),
),
FakeVmServiceRequest
(
method:
'ext.flutter.reassemble'
,
args:
<
String
,
Object
>{
'isolateId'
:
fakeUnpausedIsolate
.
id
,
},
),
]);
final
FakeFlutterDevice
flutterDevice
=
FakeFlutterDevice
(
mockDevice
,
BuildInfo
.
debug
,
FakeWidgetCache
(),
FakeResidentCompiler
(),
mockDevFS
,
)..
vmService
=
fakeVmServiceHost
.
vmService
;
residentRunner
=
HotRunner
(
<
FlutterDevice
>[
flutterDevice
,
],
stayResident:
false
,
debuggingOptions:
DebuggingOptions
.
enabled
(
BuildInfo
.
debug
),
);
when
(
mockDevice
.
sdkNameAndVersion
).
thenAnswer
((
Invocation
invocation
)
async
{
return
'Example'
;
});
when
(
mockDevice
.
targetPlatform
).
thenAnswer
((
Invocation
invocation
)
async
{
return
TargetPlatform
.
android_arm
;
});
when
(
mockDevice
.
isLocalEmulator
).
thenAnswer
((
Invocation
invocation
)
async
{
return
false
;
});
when
(
mockDevice
.
getLogReader
(
app:
anyNamed
(
'app'
))).
thenReturn
(
NoOpDeviceLogReader
(
'test'
));
when
(
mockDevFS
.
update
(
mainUri:
anyNamed
(
'mainUri'
),
target:
anyNamed
(
'target'
),
bundle:
anyNamed
(
'bundle'
),
firstBuildTime:
anyNamed
(
'firstBuildTime'
),
bundleFirstUpload:
anyNamed
(
'bundleFirstUpload'
),
generator:
anyNamed
(
'generator'
),
fullRestart:
anyNamed
(
'fullRestart'
),
dillOutputPath:
anyNamed
(
'dillOutputPath'
),
trackWidgetCreation:
anyNamed
(
'trackWidgetCreation'
),
projectRootPath:
anyNamed
(
'projectRootPath'
),
pathToReload:
anyNamed
(
'pathToReload'
),
invalidatedFiles:
anyNamed
(
'invalidatedFiles'
),
packageConfig:
anyNamed
(
'packageConfig'
),
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
UpdateFSReport
(
success:
true
);
});
final
Completer
<
DebugConnectionInfo
>
onConnectionInfo
=
Completer
<
DebugConnectionInfo
>.
sync
();
final
Completer
<
void
>
onAppStart
=
Completer
<
void
>.
sync
();
unawaited
(
residentRunner
.
attach
(
appStartedCompleter:
onAppStart
,
connectionInfoCompleter:
onConnectionInfo
,
));
final
OperationResult
result
=
await
residentRunner
.
restart
(
fullRestart:
false
);
expect
(
result
.
fatal
,
false
);
expect
(
result
.
code
,
0
);
verify
(
globals
.
flutterUsage
.
sendEvent
(
'hot'
,
'reload'
,
parameters:
argThat
(
containsPair
(
'cd48'
,
'true'
),
named:
'parameters'
,
))).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
Platform:
()
=>
FakePlatform
(
operatingSystem:
'linux'
),
ProjectFileInvalidator:
()
=>
FakeProjectFileInvalidator
(),
Usage:
()
=>
MockUsage
(),
FeatureFlags:
()
=>
TestFeatureFlags
(
isSingleWidgetReloadEnabled:
true
),
}));
testUsingContext
(
'ResidentRunner can send target platform to analytics from full restart'
,
()
=>
testbed
.
run
(()
async
{
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
listViews
,
...
...
@@ -2251,6 +2114,34 @@ void main() {
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'FlutterDevice passes flutter-widget-cache flag when feature is enabled'
,
()
async
{
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[]);
final
MockDevice
mockDevice
=
MockDevice
();
when
(
mockDevice
.
targetPlatform
).
thenAnswer
((
Invocation
invocation
)
async
{
return
TargetPlatform
.
android_arm
;
});
final
DefaultResidentCompiler
residentCompiler
=
(
await
FlutterDevice
.
create
(
mockDevice
,
buildInfo:
const
BuildInfo
(
BuildMode
.
debug
,
''
,
treeShakeIcons:
false
,
extraFrontEndOptions:
<
String
>[],
),
flutterProject:
FlutterProject
.
current
(),
target:
null
,
)).
generator
as
DefaultResidentCompiler
;
expect
(
residentCompiler
.
extraFrontEndOptions
,
contains
(
'--flutter-widget-cache'
));
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
Artifacts
.
test
(),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
FeatureFlags:
()
=>
TestFeatureFlags
(
isSingleWidgetReloadEnabled:
true
)
});
testUsingContext
(
'connect sets up log reader'
,
()
=>
testbed
.
run
(()
async
{
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[]);
final
MockDevice
mockDevice
=
MockDevice
();
...
...
@@ -2325,21 +2216,13 @@ class ThrowingForwardingFileSystem extends ForwardingFileSystem {
}
}
class
FakeWidgetCache
implements
WidgetCache
{
@override
Future
<
String
>
validateLibrary
(
Uri
libraryUri
)
async
{
return
'FakeWidget'
;
}
}
class
FakeFlutterDevice
extends
FlutterDevice
{
FakeFlutterDevice
(
Device
device
,
BuildInfo
buildInfo
,
WidgetCache
widgetCache
,
ResidentCompiler
residentCompiler
,
this
.
fakeDevFS
,
)
:
super
(
device
,
buildInfo:
buildInfo
,
widgetCache:
widgetCache
,
generator:
residentCompiler
);
)
:
super
(
device
,
buildInfo:
buildInfo
,
generator:
residentCompiler
);
@override
Future
<
void
>
connect
({
...
...
packages/flutter_tools/test/general.shard/widget_cache_test.dart
deleted
100644 → 0
View file @
ae630b42
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_tools/src/widget_cache.dart'
;
import
'../src/common.dart'
;
import
'../src/testbed.dart'
;
void
main
(
)
{
testWithoutContext
(
'widget cache returns null when experiment is disabled'
,
()
async
{
final
WidgetCache
widgetCache
=
WidgetCache
(
featureFlags:
TestFeatureFlags
(
isSingleWidgetReloadEnabled:
false
));
expect
(
await
widgetCache
.
validateLibrary
(
Uri
.
parse
(
'package:hello_world/main.dart'
)),
null
);
});
testWithoutContext
(
'widget cache returns null because functionality is not complete'
,
()
async
{
final
WidgetCache
widgetCache
=
WidgetCache
(
featureFlags:
TestFeatureFlags
(
isSingleWidgetReloadEnabled:
true
));
expect
(
await
widgetCache
.
validateLibrary
(
Uri
.
parse
(
'package:hello_world/main.dart'
)),
null
);
});
}
packages/flutter_tools/test/integration.shard/hot_reload_test.dart
View file @
a19f5bac
...
...
@@ -7,7 +7,6 @@ import 'dart:async';
import
'package:file/file.dart'
;
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:vm_service/vm_service.dart'
;
import
'package:vm_service/vm_service_io.dart'
;
import
'../src/common.dart'
;
import
'test_data/hot_reload_project.dart'
;
...
...
@@ -82,73 +81,6 @@ void main() {
}
});
testWithoutContext
(
'fastReassemble behavior triggers hot reload behavior with evaluation of expression'
,
()
async
{
final
Completer
<
void
>
tick1
=
Completer
<
void
>();
final
Completer
<
void
>
tick2
=
Completer
<
void
>();
final
Completer
<
void
>
tick3
=
Completer
<
void
>();
final
StreamSubscription
<
String
>
subscription
=
flutter
.
stdout
.
listen
((
String
line
)
{
if
(
line
.
contains
(
'TICK 1'
))
{
tick1
.
complete
();
}
if
(
line
.
contains
(
'TICK 2'
))
{
tick2
.
complete
();
}
if
(
line
.
contains
(
'TICK 3'
))
{
tick3
.
complete
();
}
});
await
flutter
.
run
(
withDebugger:
true
);
final
int
port
=
flutter
.
vmServicePort
;
final
VmService
vmService
=
await
vmServiceConnectUri
(
'ws://localhost:
$port
/ws'
);
await
tick1
.
future
;
try
{
// Since the single-widget reload feature is not yet implemented, manually
// evaluate the expression for the reload.
final
Isolate
isolate
=
await
waitForExtension
(
vmService
);
final
LibraryRef
targetRef
=
isolate
.
libraries
.
firstWhere
((
LibraryRef
libraryRef
)
{
return
libraryRef
.
uri
==
'package:test/main.dart'
;
});
await
vmService
.
evaluate
(
isolate
.
id
,
targetRef
.
id
,
'((){debugFastReassembleMethod=(Object x) => x is MyApp})()'
,
);
final
Response
fastReassemble1
=
await
vmService
.
callServiceExtension
(
'ext.flutter.fastReassemble'
,
isolateId:
isolate
.
id
);
// _extensionType indicates success.
expect
(
fastReassemble1
.
type
,
'_extensionType'
);
await
tick2
.
future
;
// verify evaluation did not produce invalidat type by checking with dart:core
// type.
await
vmService
.
evaluate
(
isolate
.
id
,
targetRef
.
id
,
'((){debugFastReassembleMethod=(Object x) => x is bool})()'
,
);
final
Response
fastReassemble2
=
await
vmService
.
callServiceExtension
(
'ext.flutter.fastReassemble'
,
isolateId:
isolate
.
id
);
// _extensionType indicates success.
expect
(
fastReassemble2
.
type
,
'_extensionType'
);
unawaited
(
tick3
.
future
.
whenComplete
(()
{
fail
(
'Should not complete'
);
}));
// Invocation without evaluation leads to runtime error.
expect
(
vmService
.
callServiceExtension
(
'ext.flutter.fastReassemble'
,
isolateId:
isolate
.
id
),
throwsA
(
isA
<
Exception
>())
);
}
finally
{
await
subscription
.
cancel
();
}
});
testWithoutContext
(
'hot restart works without error'
,
()
async
{
await
flutter
.
run
();
await
flutter
.
hotRestart
();
...
...
packages/flutter_tools/test/integration.shard/single_widget_reload_test.dart
0 → 100644
View file @
a19f5bac
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'../src/common.dart'
;
import
'test_data/single_widget_reload_project.dart'
;
import
'test_driver.dart'
;
import
'test_utils.dart'
;
void
main
(
)
{
Directory
tempDir
;
final
SingleWidgetReloadProject
project
=
SingleWidgetReloadProject
();
FlutterRunTestDriver
flutter
;
setUp
(()
async
{
tempDir
=
createResolvedTempDirectorySync
(
'hot_reload_test.'
);
await
project
.
setUpIn
(
tempDir
);
flutter
=
FlutterRunTestDriver
(
tempDir
);
});
tearDown
(()
async
{
await
flutter
?.
stop
();
tryToDelete
(
tempDir
);
});
testWithoutContext
(
'newly added code executes during hot reload with single widget reloads, but only invalidated widget'
,
()
async
{
final
StringBuffer
stdout
=
StringBuffer
();
final
StreamSubscription
<
String
>
subscription
=
flutter
.
stdout
.
listen
(
stdout
.
writeln
);
await
flutter
.
run
(
singleWidgetReloads:
true
);
project
.
uncommentHotReloadPrint
();
try
{
await
flutter
.
hotReload
();
expect
(
stdout
.
toString
(),
allOf
(
contains
(
'(((TICK 1)))'
),
contains
(
'(((((RELOAD WORKED)))))'
),
// Does not invalidate parent widget, so second tick is not output.
isNot
(
contains
(
'(((TICK 2)))'
),
)));
}
finally
{
await
subscription
.
cancel
();
}
});
testWithoutContext
(
'changes outside of the class body triggers a full reload'
,
()
async
{
final
StringBuffer
stdout
=
StringBuffer
();
final
StreamSubscription
<
String
>
subscription
=
flutter
.
stdout
.
listen
(
stdout
.
writeln
);
await
flutter
.
run
(
singleWidgetReloads:
true
);
project
.
modifyFunction
();
try
{
await
flutter
.
hotReload
();
expect
(
stdout
.
toString
(),
allOf
(
contains
(
'(((TICK 1)))'
),
contains
(
'(((TICK 2)))'
),
));
}
finally
{
await
subscription
.
cancel
();
}
});
}
packages/flutter_tools/test/integration.shard/test_data/single_widget_reload_project.dart
0 → 100644
View file @
a19f5bac
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'../test_utils.dart'
;
import
'project.dart'
;
class
SingleWidgetReloadProject
extends
Project
{
@override
final
String
pubspec
=
'''
name: test
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
'''
;
@override
final
String
main
=
r''
'
import '
package:
flutter
/
material
.
dart
';
import '
package:
flutter
/
scheduler
.
dart
';
import '
package:
flutter
/
services
.
dart
';
import '
package:
flutter
/
widgets
.
dart
';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final ByteData message = const StringCodec().encodeMessage('
AppLifecycleState
.
resumed
');
await ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage('
flutter
/
lifecycle
', message, (_) { });
runApp(MyApp());
}
int count = 1;
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// PARENT WIDGET
print('
((((
TICK
$count
))))
');
count += 1;
return MaterialApp(
title: '
Flutter
Demo
',
home: SecondWidget(),
);
}
}
class SecondWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Do not remove the next line, it'
s
uncommented
by
a
test
to
verify
that
// hot reloading worked:
// printHotReloadWorked();
return
Container
();
}
}
void
printHotReloadWorked
()
{
// The call to this function is uncommented by a test to verify that hot
// reloading worked.
print
(
'(((((RELOAD WORKED)))))'
);
}
''';
Uri get parentWidgetUri => mainDart;
int get parentWidgetLine => lineContaining(main, '
// PARENT WIDGET');
void
uncommentHotReloadPrint
()
{
final
String
newMainContents
=
main
.
replaceAll
(
'// printHotReloadWorked();'
,
'printHotReloadWorked();'
,
);
writeFile
(
fileSystem
.
path
.
join
(
dir
.
path
,
'lib'
,
'main.dart'
),
newMainContents
);
}
void
modifyFunction
()
{
final
String
newMainContents
=
main
.
replaceAll
(
'(((((RELOAD WORKED)))))'
,
'(((((RELOAD WORKED 2)))))'
,
);
writeFile
(
fileSystem
.
path
.
join
(
dir
.
path
,
'lib'
,
'main.dart'
),
newMainContents
);
}
}
packages/flutter_tools/test/integration.shard/test_driver.dart
View file @
a19f5bac
...
...
@@ -84,6 +84,7 @@ abstract class FlutterTestDriver {
String
script
,
bool
withDebugger
=
false
,
File
pidFile
,
bool
singleWidgetReloads
=
false
,
})
async
{
final
String
flutterBin
=
fileSystem
.
path
.
join
(
getFlutterRoot
(),
'bin'
,
'flutter'
);
if
(
withDebugger
)
{
...
...
@@ -107,7 +108,12 @@ abstract class FlutterTestDriver {
.
toList
(),
workingDirectory:
_projectFolder
.
path
,
// The web environment variable has the same effect as `flutter config --enable-web`.
environment:
<
String
,
String
>{
'FLUTTER_TEST'
:
'true'
,
'FLUTTER_WEB'
:
'true'
},
environment:
<
String
,
String
>{
'FLUTTER_TEST'
:
'true'
,
'FLUTTER_WEB'
:
'true'
,
if
(
singleWidgetReloads
)
'FLUTTER_SINGLE_WIDGET_RELOAD'
:
'true'
,
},
);
// This class doesn't use the result of the future. It's made available
...
...
@@ -442,6 +448,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool
expressionEvaluation
=
true
,
bool
structuredErrors
=
false
,
bool
machine
=
true
,
bool
singleWidgetReloads
=
false
,
File
pidFile
,
String
script
,
})
async
{
...
...
@@ -470,6 +477,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
pauseOnExceptions:
pauseOnExceptions
,
pidFile:
pidFile
,
script:
script
,
singleWidgetReloads:
singleWidgetReloads
,
);
}
...
...
@@ -479,6 +487,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool
startPaused
=
false
,
bool
pauseOnExceptions
=
false
,
File
pidFile
,
bool
singleWidgetReloads
=
false
,
})
async
{
await
_setupProcess
(
<
String
>[
...
...
@@ -496,6 +505,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
startPaused:
startPaused
,
pauseOnExceptions:
pauseOnExceptions
,
pidFile:
pidFile
,
singleWidgetReloads:
singleWidgetReloads
,
);
}
...
...
@@ -506,6 +516,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool
withDebugger
=
false
,
bool
startPaused
=
false
,
bool
pauseOnExceptions
=
false
,
bool
singleWidgetReloads
=
false
,
File
pidFile
,
})
async
{
assert
(!
startPaused
||
withDebugger
);
...
...
@@ -514,6 +525,7 @@ class FlutterRunTestDriver extends FlutterTestDriver {
script:
script
,
withDebugger:
withDebugger
,
pidFile:
pidFile
,
singleWidgetReloads:
singleWidgetReloads
,
);
final
Completer
<
void
>
prematureExitGuard
=
Completer
<
void
>();
...
...
@@ -723,12 +735,14 @@ class FlutterTestTestDriver extends FlutterTestDriver {
bool
pauseOnExceptions
=
false
,
File
pidFile
,
Future
<
void
>
Function
()
beforeStart
,
bool
singleWidgetReloads
=
false
,
})
async
{
await
super
.
_setupProcess
(
args
,
script:
script
,
withDebugger:
withDebugger
,
pidFile:
pidFile
,
singleWidgetReloads:
singleWidgetReloads
,
);
// Stash the PID so that we can terminate the VM more reliably than using
...
...
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