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
3b884aa6
Unverified
Commit
3b884aa6
authored
Feb 03, 2021
by
Jonah Williams
Committed by
GitHub
Feb 03, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Catch VM Service disappearance from run/attach handler code (#75298)
parent
998d1c65
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
224 additions
and
48 deletions
+224
-48
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+7
-0
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+70
-46
attach_test.dart
...utter_tools/test/commands.shard/hermetic/attach_test.dart
+78
-0
run_test.dart
.../flutter_tools/test/commands.shard/hermetic/run_test.dart
+69
-2
No files found.
packages/flutter_tools/lib/src/commands/attach.dart
View file @
3b884aa6
...
...
@@ -7,6 +7,7 @@
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:vm_service/vm_service.dart'
;
import
'../android/android_device.dart'
;
import
'../artifacts.dart'
;
...
...
@@ -29,6 +30,7 @@ import '../resident_runner.dart';
import
'../run_cold.dart'
;
import
'../run_hot.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../vmservice.dart'
;
/// A Flutter-command that attaches to applications that have been launched
/// without `flutter run`.
...
...
@@ -379,6 +381,11 @@ known, it can be explicitly provided to attach via the command-line, e.g.
}
globals
.
printStatus
(
'Waiting for a new connection from Flutter on
${device.name}
...'
);
}
}
on
RPCError
catch
(
err
)
{
if
(
err
.
code
==
RPCErrorCodes
.
kServiceDisappeared
)
{
throwToolExit
(
'Lost connection to device.'
);
}
rethrow
;
}
finally
{
final
List
<
ForwardedPort
>
ports
=
device
.
portForwarder
.
forwardedPorts
.
toList
();
for
(
final
ForwardedPort
port
in
ports
)
{
...
...
packages/flutter_tools/lib/src/commands/run.dart
View file @
3b884aa6
...
...
@@ -6,6 +6,9 @@
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:vm_service/vm_service.dart'
;
import
'../android/android_device.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
...
...
@@ -22,6 +25,7 @@ import '../run_cold.dart';
import
'../run_hot.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../tracing.dart'
;
import
'../vmservice.dart'
;
import
'../web/web_runner.dart'
;
import
'daemon.dart'
;
...
...
@@ -456,6 +460,52 @@ class RunCommand extends RunCommandBase {
await
devices
.
single
.
targetPlatform
==
TargetPlatform
.
web_javascript
;
}
@visibleForTesting
Future
<
ResidentRunner
>
createRunner
({
@required
bool
hotMode
,
@required
List
<
FlutterDevice
>
flutterDevices
,
@required
String
applicationBinaryPath
,
@required
FlutterProject
flutterProject
,
})
async
{
if
(
hotMode
&&
!
webMode
)
{
return
HotRunner
(
flutterDevices
,
target:
targetFile
,
debuggingOptions:
await
createDebuggingOptions
(
webMode
),
benchmarkMode:
boolArg
(
'benchmark'
),
applicationBinary:
applicationBinaryPath
==
null
?
null
:
globals
.
fs
.
file
(
applicationBinaryPath
),
projectRootPath:
stringArg
(
'project-root'
),
dillOutputPath:
stringArg
(
'output-dill'
),
stayResident:
stayResident
,
ipv6:
ipv6
,
);
}
else
if
(
webMode
)
{
return
webRunnerFactory
.
createWebRunner
(
flutterDevices
.
single
,
target:
targetFile
,
flutterProject:
flutterProject
,
ipv6:
ipv6
,
debuggingOptions:
await
createDebuggingOptions
(
webMode
),
stayResident:
stayResident
,
urlTunneller:
null
,
);
}
return
ColdRunner
(
flutterDevices
,
target:
targetFile
,
debuggingOptions:
await
createDebuggingOptions
(
webMode
),
traceStartup:
traceStartup
,
awaitFirstFrameWhenTracing:
awaitFirstFrameWhenTracing
,
applicationBinary:
applicationBinaryPath
==
null
?
null
:
globals
.
fs
.
file
(
applicationBinaryPath
),
ipv6:
ipv6
,
stayResident:
stayResident
,
);
}
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
// Enable hot mode by default if `--no-hot` was not passed and we are in
...
...
@@ -557,45 +607,12 @@ class RunCommand extends RunCommandBase {
),
];
ResidentRunner
runner
;
if
(
hotMode
&&
!
webMode
)
{
runner
=
HotRunner
(
flutterDevices
,
target:
targetFile
,
debuggingOptions:
await
createDebuggingOptions
(
webMode
),
benchmarkMode:
boolArg
(
'benchmark'
),
applicationBinary:
applicationBinaryPath
==
null
?
null
:
globals
.
fs
.
file
(
applicationBinaryPath
),
projectRootPath:
stringArg
(
'project-root'
),
dillOutputPath:
stringArg
(
'output-dill'
),
stayResident:
stayResident
,
ipv6:
ipv6
,
);
}
else
if
(
webMode
)
{
runner
=
webRunnerFactory
.
createWebRunner
(
flutterDevices
.
single
,
target:
targetFile
,
flutterProject:
flutterProject
,
ipv6:
ipv6
,
debuggingOptions:
await
createDebuggingOptions
(
webMode
),
stayResident:
stayResident
,
urlTunneller:
null
,
);
}
else
{
runner
=
ColdRunner
(
flutterDevices
,
target:
targetFile
,
debuggingOptions:
await
createDebuggingOptions
(
webMode
),
traceStartup:
traceStartup
,
awaitFirstFrameWhenTracing:
awaitFirstFrameWhenTracing
,
applicationBinary:
applicationBinaryPath
==
null
?
null
:
globals
.
fs
.
file
(
applicationBinaryPath
),
ipv6:
ipv6
,
stayResident:
stayResident
,
);
}
final
ResidentRunner
runner
=
await
createRunner
(
applicationBinaryPath:
applicationBinaryPath
,
flutterDevices:
flutterDevices
,
flutterProject:
flutterProject
,
hotMode:
hotMode
,
);
DateTime
appStartedTime
;
// Sync completer so the completing agent attaching to the resident doesn't
...
...
@@ -620,13 +637,20 @@ class RunCommand extends RunCommandBase {
}
));
final
int
result
=
await
runner
.
run
(
appStartedCompleter:
appStartedTimeRecorder
,
enableDevTools:
stayResident
&&
boolArg
(
FlutterCommand
.
kEnableDevTools
),
route:
route
,
);
if
(
result
!=
0
)
{
throwToolExit
(
null
,
exitCode:
result
);
try
{
final
int
result
=
await
runner
.
run
(
appStartedCompleter:
appStartedTimeRecorder
,
enableDevTools:
stayResident
&&
boolArg
(
FlutterCommand
.
kEnableDevTools
),
route:
route
,
);
if
(
result
!=
0
)
{
throwToolExit
(
null
,
exitCode:
result
);
}
}
on
RPCError
catch
(
err
)
{
if
(
err
.
code
==
RPCErrorCodes
.
kServiceDisappeared
)
{
throwToolExit
(
'Lost connection to device.'
);
}
rethrow
;
}
return
FlutterCommandResult
(
ExitStatus
.
success
,
...
...
packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
View file @
3b884aa6
...
...
@@ -642,6 +642,84 @@ void main() {
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Catches service disappeared error'
,
()
async
{
final
MockAndroidDevice
device
=
MockAndroidDevice
();
final
MockHotRunner
mockHotRunner
=
MockHotRunner
();
final
MockHotRunnerFactory
mockHotRunnerFactory
=
MockHotRunnerFactory
();
when
(
device
.
portForwarder
).
thenReturn
(
const
NoOpDevicePortForwarder
());
when
(
mockHotRunner
.
attach
(
appStartedCompleter:
anyNamed
(
'appStartedCompleter'
),
allowExistingDdsInstance:
true
,
enableDevTools:
anyNamed
(
'enableDevTools'
),
)).
thenAnswer
((
_
)
async
{
await
null
;
throw
vm_service
.
RPCError
(
'flutter._listViews'
,
RPCErrorCodes
.
kServiceDisappeared
,
''
);
});
when
(
mockHotRunnerFactory
.
build
(
any
,
target:
anyNamed
(
'target'
),
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
packagesFilePath:
anyNamed
(
'packagesFilePath'
),
flutterProject:
anyNamed
(
'flutterProject'
),
ipv6:
false
,
)).
thenReturn
(
mockHotRunner
);
testDeviceManager
.
addDevice
(
device
);
when
(
device
.
getLogReader
(
includePastLogs:
anyNamed
(
'includePastLogs'
)))
.
thenAnswer
((
_
)
{
return
NoOpDeviceLogReader
(
'test'
);
});
testFileSystem
.
file
(
'lib/main.dart'
).
createSync
();
final
AttachCommand
command
=
AttachCommand
(
hotRunnerFactory:
mockHotRunnerFactory
);
await
expectLater
(
createTestCommandRunner
(
command
).
run
(<
String
>[
'attach'
,
]),
throwsToolExit
(
message:
'Lost connection to device.'
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Does not catch generic RPC error'
,
()
async
{
final
MockAndroidDevice
device
=
MockAndroidDevice
();
final
MockHotRunner
mockHotRunner
=
MockHotRunner
();
final
MockHotRunnerFactory
mockHotRunnerFactory
=
MockHotRunnerFactory
();
when
(
device
.
portForwarder
).
thenReturn
(
const
NoOpDevicePortForwarder
());
when
(
mockHotRunner
.
attach
(
appStartedCompleter:
anyNamed
(
'appStartedCompleter'
),
allowExistingDdsInstance:
true
,
enableDevTools:
anyNamed
(
'enableDevTools'
),
)).
thenAnswer
((
_
)
async
{
await
null
;
throw
vm_service
.
RPCError
(
'flutter._listViews'
,
RPCErrorCodes
.
kInvalidParams
,
''
);
});
when
(
mockHotRunnerFactory
.
build
(
any
,
target:
anyNamed
(
'target'
),
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
packagesFilePath:
anyNamed
(
'packagesFilePath'
),
flutterProject:
anyNamed
(
'flutterProject'
),
ipv6:
false
,
)).
thenReturn
(
mockHotRunner
);
testDeviceManager
.
addDevice
(
device
);
when
(
device
.
getLogReader
(
includePastLogs:
anyNamed
(
'includePastLogs'
)))
.
thenAnswer
((
_
)
{
return
NoOpDeviceLogReader
(
'test'
);
});
testFileSystem
.
file
(
'lib/main.dart'
).
createSync
();
final
AttachCommand
command
=
AttachCommand
(
hotRunnerFactory:
mockHotRunnerFactory
);
await
expectLater
(
createTestCommandRunner
(
command
).
run
(<
String
>[
'attach'
,
]),
throwsA
(
isA
<
vm_service
.
RPCError
>()));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
}
...
...
packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
View file @
3b884aa6
...
...
@@ -22,9 +22,14 @@ import 'package:flutter_tools/src/commands/run.dart';
import
'package:flutter_tools/src/convert.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/reporting.dart'
;
import
'package:flutter_tools/src/resident_runner.dart'
;
import
'package:flutter_tools/src/runner/flutter_command.dart'
;
import
'package:flutter_tools/src/vmservice.dart'
;
import
'package:meta/meta.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:vm_service/vm_service.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
...
...
@@ -542,6 +547,30 @@ void main() {
expect
(
dartDefines
,
<
String
>[
'FLUTTER_WEB_AUTO_DETECT=false'
,
'FLUTTER_WEB_USE_SKIA=false'
]);
});
});
testUsingContext
(
'Flutter run catches service has disappear errors and throws a tool exit'
,
()
async
{
final
FakeResidentRunner
residentRunner
=
FakeResidentRunner
();
residentRunner
.
rpcError
=
RPCError
(
'flutter._listViews'
,
RPCErrorCodes
.
kServiceDisappeared
,
''
);
final
TestRunCommandWithFakeResidentRunner
command
=
TestRunCommandWithFakeResidentRunner
();
command
.
fakeResidentRunner
=
residentRunner
;
await
expectToolExitLater
(
createTestCommandRunner
(
command
).
run
(<
String
>[
'run'
,
'--no-pub'
,
]),
contains
(
'Lost connection to device.'
));
});
testUsingContext
(
'Flutter run does not catch other RPC errors'
,
()
async
{
final
FakeResidentRunner
residentRunner
=
FakeResidentRunner
();
residentRunner
.
rpcError
=
RPCError
(
'flutter._listViews'
,
RPCErrorCodes
.
kInvalidParams
,
''
);
final
TestRunCommandWithFakeResidentRunner
command
=
TestRunCommandWithFakeResidentRunner
();
command
.
fakeResidentRunner
=
residentRunner
;
await
expectLater
(()
=>
createTestCommandRunner
(
command
).
run
(<
String
>[
'run'
,
'--no-pub'
,
]),
throwsA
(
isA
<
RPCError
>()));
});
}
class
MockCache
extends
Mock
implements
Cache
{}
...
...
@@ -585,7 +614,7 @@ class FakeDevice extends Fake implements Device {
bool
supportsRuntimeMode
(
BuildMode
mode
)
=>
true
;
@override
bool
get
supportsHotReload
=>
false
;
bool
supportsHotReload
=
false
;
@override
bool
get
supportsFastStart
=>
false
;
...
...
@@ -641,7 +670,7 @@ class FakeDevice extends Fake implements Device {
}
}
class
FakeApplicationPackageFactory
extends
Fake
implements
ApplicationPackageFactory
{
class
FakeApplicationPackageFactory
extends
Fake
implements
ApplicationPackageFactory
{
ApplicationPackage
package
;
@override
...
...
@@ -653,3 +682,41 @@ class FakeApplicationPackageFactory extends Fake implements ApplicationPackageF
return
package
;
}
}
class
TestRunCommandWithFakeResidentRunner
extends
RunCommand
{
FakeResidentRunner
fakeResidentRunner
;
@override
Future
<
ResidentRunner
>
createRunner
({
@required
bool
hotMode
,
@required
List
<
FlutterDevice
>
flutterDevices
,
@required
String
applicationBinaryPath
,
@required
FlutterProject
flutterProject
,
})
async
{
return
fakeResidentRunner
;
}
@override
// ignore: must_call_super
Future
<
void
>
validateCommand
()
async
{
devices
=
<
Device
>[
FakeDevice
()..
supportsHotReload
=
true
];
}
}
class
FakeResidentRunner
extends
Fake
implements
ResidentRunner
{
RPCError
rpcError
;
@override
Future
<
int
>
run
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
void
>
appStartedCompleter
,
bool
enableDevTools
=
false
,
String
route
,
})
async
{
await
null
;
if
(
rpcError
!=
null
)
{
throw
rpcError
;
}
return
0
;
}
}
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