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
99e85b1c
Unverified
Commit
99e85b1c
authored
Nov 19, 2021
by
Danny Tuppeny
Committed by
GitHub
Nov 19, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Disable pause-on-exceptions for (outgoing) isolates during hot restart (#93411)
parent
e4b78ffc
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
120 additions
and
8 deletions
+120
-8
run_hot.dart
packages/flutter_tools/lib/src/run_hot.dart
+10
-5
resident_runner_test.dart
...lutter_tools/test/general.shard/resident_runner_test.dart
+8
-1
flutter_adapter_test.dart
...integration.shard/debug_adapter/flutter_adapter_test.dart
+33
-0
test_client.dart
...ols/test/integration.shard/debug_adapter/test_client.dart
+7
-2
basic_project.dart
...tools/test/integration.shard/test_data/basic_project.dart
+62
-0
No files found.
packages/flutter_tools/lib/src/run_hot.dart
View file @
99e85b1c
...
...
@@ -603,14 +603,19 @@ class HotRunner extends ResidentRunner {
// are not thread-safe, and thus must be run on the same thread that
// would be blocked by the pause. Simply un-pausing is not sufficient,
// because this does not prevent the isolate from immediately hitting
// a breakpoint, for example if the breakpoint was placed in a loop
// or in a frequently called method. Instead, all breakpoints are first
// disabled and then the isolate resumed.
final
List
<
Future
<
void
>>
breakpointRemoval
=
<
Future
<
void
>>[
// a breakpoint (for example if the breakpoint was placed in a loop
// or in a frequently called method) or an exception. Instead, all
// breakpoints are first disabled and exception pause mode set to
// None, and then the isolate resumed.
// These settings to not need restoring as Hot Restart results in
// new isolates, which will be configured by the editor as they are
// started.
final
List
<
Future
<
void
>>
breakpointAndExceptionRemoval
=
<
Future
<
void
>>[
device
.
vmService
.
service
.
setExceptionPauseMode
(
isolate
.
id
,
'None'
),
for
(
final
vm_service
.
Breakpoint
breakpoint
in
isolate
.
breakpoints
)
device
.
vmService
.
service
.
removeBreakpoint
(
isolate
.
id
,
breakpoint
.
id
)
];
await
Future
.
wait
(
breakpointRemoval
);
await
Future
.
wait
(
breakpoint
AndException
Removal
);
await
device
.
vmService
.
service
.
resume
(
view
.
uiIsolate
.
id
);
}
}));
...
...
packages/flutter_tools/test/general.shard/resident_runner_test.dart
View file @
99e85b1c
...
...
@@ -906,7 +906,7 @@ void main() {
Usage:
()
=>
TestUsage
(),
}));
testUsingContext
(
'ResidentRunner can remove breakpoints from paused isolate during hot restart'
,
()
=>
testbed
.
run
(()
async
{
testUsingContext
(
'ResidentRunner can remove breakpoints
and exception-pause-mode
from paused isolate during hot restart'
,
()
=>
testbed
.
run
(()
async
{
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
listViews
,
listViews
,
...
...
@@ -922,6 +922,13 @@ void main() {
method:
'getVM'
,
jsonResponse:
vm_service
.
VM
.
parse
(<
String
,
Object
>{}).
toJson
(),
),
const
FakeVmServiceRequest
(
method:
'setExceptionPauseMode'
,
args:
<
String
,
String
>{
'isolateId'
:
'1'
,
'mode'
:
'None'
,
}
),
const
FakeVmServiceRequest
(
method:
'removeBreakpoint'
,
args:
<
String
,
String
>{
...
...
packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart
View file @
99e85b1c
...
...
@@ -187,6 +187,39 @@ void main() {
await
dap
.
client
.
terminate
();
});
testWithoutContext
(
'can hot restart when exceptions occur on outgoing isolates'
,
()
async
{
final
BasicProjectThatThrows
_project
=
BasicProjectThatThrows
();
await
_project
.
setUpIn
(
tempDir
);
// Launch the app and wait for it to stop at an exception.
int
originalThreadId
,
newThreadId
;
await
Future
.
wait
(<
Future
<
Object
>>[
// Capture the thread ID of the stopped thread.
dap
.
client
.
stoppedEvents
.
first
.
then
((
StoppedEventBody
event
)
=>
originalThreadId
=
event
.
threadId
),
dap
.
client
.
start
(
exceptionPauseMode:
'All'
,
// Ensure we stop on all exceptions
launch:
()
=>
dap
.
client
.
launch
(
cwd:
_project
.
dir
.
path
,
toolArgs:
<
String
>[
'-d'
,
'flutter-tester'
],
),
),
],
eagerError:
true
);
// Hot restart, ensuring it completes and capturing the ID of the new thread
// to pause.
await
Future
.
wait
(<
Future
<
Object
>>[
// Capture the thread ID of the newly stopped thread.
dap
.
client
.
stoppedEvents
.
first
.
then
((
StoppedEventBody
event
)
=>
newThreadId
=
event
.
threadId
),
dap
.
client
.
hotRestart
(),
],
eagerError:
true
);
// We should not have stopped on the original thread, but the new thread
// from after the restart.
expect
(
newThreadId
,
isNot
(
equals
(
originalThreadId
)));
await
dap
.
client
.
terminate
();
});
}
/// Extracts the output from a set of [OutputEventBody], removing any
...
...
packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart
View file @
99e85b1c
...
...
@@ -56,6 +56,10 @@ class DapTestClient {
Stream
<
OutputEventBody
>
get
outputEvents
=>
events
(
'output'
)
.
map
((
Event
e
)
=>
OutputEventBody
.
fromJson
(
e
.
body
!
as
Map
<
String
,
Object
?>));
/// Returns a stream of [StoppedEventBody] events.
Stream
<
StoppedEventBody
>
get
stoppedEvents
=>
events
(
'stopped'
)
.
map
((
Event
e
)
=>
StoppedEventBody
.
fromJson
(
e
.
body
!
as
Map
<
String
,
Object
?>));
/// Returns a stream of the string output from [OutputEventBody] events.
Stream
<
String
>
get
output
=>
outputEvents
.
map
((
OutputEventBody
output
)
=>
output
.
output
);
...
...
@@ -172,10 +176,11 @@ class DapTestClient {
Future
<
void
>
start
({
String
?
program
,
String
?
cwd
,
String
exceptionPauseMode
=
'None'
,
Future
<
Object
?>
Function
()?
launch
,
})
{
return
Future
.
wait
(<
Future
<
Object
?>>[
initialize
(),
initialize
(
exceptionPauseMode:
exceptionPauseMode
),
launch
?.
call
()
??
this
.
launch
(
program:
program
,
cwd:
cwd
),
],
eagerError:
true
);
}
...
...
@@ -201,7 +206,7 @@ class DapTestClient {
}
else
{
completer
.
completeError
(
message
);
}
}
else
if
(
message
is
Event
)
{
}
else
if
(
message
is
Event
&&
!
_eventController
.
isClosed
)
{
_eventController
.
add
(
message
);
// When we see a terminated event, close the event stream so if any
...
...
packages/flutter_tools/test/integration.shard/test_data/basic_project.dart
View file @
99e85b1c
...
...
@@ -53,6 +53,68 @@ class BasicProject extends Project {
int
get
topLevelFunctionBreakpointLine
=>
lineContaining
(
main
,
'// TOP LEVEL BREAKPOINT'
);
}
/// A project that throws multiple exceptions during Widget builds.
///
/// A repro for the issue at https://github.com/Dart-Code/Dart-Code/issues/3448
/// where Hot Restart could become stuck on exceptions and never complete.
class
BasicProjectThatThrows
extends
Project
{
@override
final
String
pubspec
=
'''
name: test
environment:
sdk: ">=2.12.0-0 <3.0.0"
dependencies:
flutter:
sdk: flutter
'''
;
@override
final
String
main
=
r''
'
import '
package:
flutter
/
material
.
dart
';
void a() {
throw Exception('
a
');
}
void b() {
try {
a();
} catch (e) {
throw Exception('
b
');
}
}
void c() {
try {
b();
} catch (e) {
throw Exception('
c
');
}
}
void main() {
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
c();
return MaterialApp(
debugShowCheckedModeBanner: false,
title: '
Study
Flutter
',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Container(),
);
}
}
'''
;
}
class
BasicProjectWithTimelineTraces
extends
Project
{
@override
final
String
pubspec
=
'''
...
...
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