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
e67f14e5
Unverified
Commit
e67f14e5
authored
Apr 22, 2021
by
Jonah Williams
Committed by
GitHub
Apr 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] handle missing method on exit, debugDumpX (#80890)
parent
35bffd20
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
163 additions
and
19 deletions
+163
-19
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+8
-6
vmservice.dart
packages/flutter_tools/lib/src/vmservice.dart
+24
-13
resident_runner_test.dart
...lutter_tools/test/general.shard/resident_runner_test.dart
+36
-0
vmservice_test.dart
...ages/flutter_tools/test/general.shard/vmservice_test.dart
+95
-0
No files found.
packages/flutter_tools/lib/src/resident_runner.dart
View file @
e67f14e5
...
...
@@ -364,10 +364,16 @@ class FlutterDevice {
}
for
(
final
FlutterView
view
in
views
)
{
if
(
view
!=
null
&&
view
.
uiIsolate
!=
null
)
{
// If successful, there will be no response from flutterExit.
// If successful, there will be no response from flutterExit. If the exit
// method is not registered, this will complete with `false`.
unawaited
(
vmService
.
flutterExit
(
isolateId:
view
.
uiIsolate
.
id
,
));
).
then
((
bool
exited
)
async
{
// If exiting the app failed, fall back to stopApp
if
(!
exited
)
{
await
device
.
stopApp
(
package
,
userIdentifier:
userIdentifier
);
}
}));
}
}
return
vmService
.
service
.
onDone
...
...
@@ -378,10 +384,6 @@ class FlutterDevice {
);
})
.
timeout
(
timeoutDelay
,
onTimeout:
()
{
// TODO(jonahwilliams): this only seems to fail on CI in the
// flutter_attach_android_test. This log should help verify this
// is where the tool is getting stuck.
globals
.
logger
.
printTrace
(
'error: vm service shutdown failed'
);
return
device
.
stopApp
(
package
,
userIdentifier:
userIdentifier
);
});
}
...
...
packages/flutter_tools/lib/src/vmservice.dart
View file @
e67f14e5
...
...
@@ -545,7 +545,7 @@ class FlutterVmService {
'ext.flutter.debugDumpApp'
,
isolateId:
isolateId
,
);
return
response
[
'data'
]?.
toString
()
;
return
response
!=
null
?
response
[
'data'
]?.
toString
()
:
''
;
}
Future
<
String
>
flutterDebugDumpRenderTree
({
...
...
@@ -556,7 +556,7 @@ class FlutterVmService {
isolateId:
isolateId
,
args:
<
String
,
Object
>{}
);
return
response
[
'data'
]?.
toString
()
;
return
response
!=
null
?
response
[
'data'
]?.
toString
()
:
''
;
}
Future
<
String
>
flutterDebugDumpLayerTree
({
...
...
@@ -566,7 +566,7 @@ class FlutterVmService {
'ext.flutter.debugDumpLayerTree'
,
isolateId:
isolateId
,
);
return
response
[
'data'
]?.
toString
()
;
return
response
!=
null
?
response
[
'data'
]?.
toString
()
:
''
;
}
Future
<
String
>
flutterDebugDumpSemanticsTreeInTraversalOrder
({
...
...
@@ -576,7 +576,7 @@ class FlutterVmService {
'ext.flutter.debugDumpSemanticsTreeInTraversalOrder'
,
isolateId:
isolateId
,
);
return
response
[
'data'
]?.
toString
()
;
return
response
!=
null
?
response
[
'data'
]?.
toString
()
:
''
;
}
Future
<
String
>
flutterDebugDumpSemanticsTreeInInverseHitTestOrder
({
...
...
@@ -586,7 +586,7 @@ class FlutterVmService {
'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder'
,
isolateId:
isolateId
,
);
return
response
[
'data'
]?.
toString
()
;
return
response
!=
null
?
response
[
'data'
]?.
toString
()
:
''
;
}
Future
<
Map
<
String
,
dynamic
>>
_flutterToggle
(
String
name
,
{
...
...
@@ -701,15 +701,26 @@ class FlutterVmService {
///
/// This method is only supported by certain embedders. This is
/// described by [Device.supportsFlutterExit].
Future
<
void
>
flutterExit
({
Future
<
bool
>
flutterExit
({
@required
String
isolateId
,
})
{
return
invokeFlutterExtensionRpcRaw
(
'ext.flutter.exit'
,
isolateId:
isolateId
,
).
catchError
((
dynamic
error
,
StackTrace
stackTrace
)
{
// Do nothing on sentinel or exception, the isolate already exited.
},
test:
(
dynamic
error
)
=>
error
is
vm_service
.
SentinelException
||
error
is
vm_service
.
RPCError
);
})
async
{
try
{
final
Map
<
String
,
Object
>
result
=
await
invokeFlutterExtensionRpcRaw
(
'ext.flutter.exit'
,
isolateId:
isolateId
,
);
// A response of `null` indicates that `invokeFlutterExtensionRpcRaw` caught an RPCError
// with a missing method code. This can happen when attempting to quit a flutter app
// that never registered the methods in the bindings.
if
(
result
==
null
)
{
return
false
;
}
}
on
vm_service
.
SentinelException
{
// Do nothing on sentinel, the isolate already exited.
}
on
vm_service
.
RPCError
{
// Do nothing on RPCError, the isolate already exited.
}
return
true
;
}
/// Return the current platform override for the flutter view running with
...
...
packages/flutter_tools/test/general.shard/resident_runner_test.dart
View file @
e67f14e5
...
...
@@ -1674,6 +1674,42 @@ void main() {
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
}));
testUsingContext
(
'FlutterDevice will exit an isolate that did not register the exit extension method'
,
()
=>
testbed
.
run
(()
async
{
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
FakeVmServiceRequest
(
method:
'_flutter.listViews'
,
jsonResponse:
<
String
,
Object
>{
'views'
:
<
Object
>[
fakeFlutterView
.
toJson
(),
],
},
),
FakeVmServiceRequest
(
method:
'getIsolate'
,
args:
<
String
,
Object
>{
'isolateId'
:
fakeUnpausedIsolate
.
id
,
},
jsonResponse:
fakeUnpausedIsolate
.
toJson
(),
),
FakeVmServiceRequest
(
method:
'ext.flutter.exit'
,
args:
<
String
,
Object
>{
'isolateId'
:
fakeUnpausedIsolate
.
id
,
},
errorCode:
RPCErrorCodes
.
kMethodNotFound
,
),
]);
final
TestFlutterDevice
flutterDevice
=
TestFlutterDevice
(
mockDevice
,
);
flutterDevice
.
vmService
=
fakeVmServiceHost
.
vmService
;
await
flutterDevice
.
exitApps
(
timeoutDelay:
Duration
.
zero
);
expect
(
mockDevice
.
appStopped
,
true
);
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
}));
testUsingContext
(
'FlutterDevice can exit from a release mode isolate with no VmService'
,
()
=>
testbed
.
run
(()
async
{
final
TestFlutterDevice
flutterDevice
=
TestFlutterDevice
(
mockDevice
,
...
...
packages/flutter_tools/test/general.shard/vmservice_test.dart
View file @
e67f14e5
...
...
@@ -331,6 +331,101 @@ void main() {
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
});
testWithoutContext
(
'flutterDebugDumpSemanticsTreeInTraversalOrder handles missing method'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
const
FakeVmServiceRequest
(
method:
'ext.flutter.debugDumpSemanticsTreeInTraversalOrder'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
},
errorCode:
RPCErrorCodes
.
kMethodNotFound
,
),
]
);
expect
(
await
fakeVmServiceHost
.
vmService
.
flutterDebugDumpSemanticsTreeInTraversalOrder
(
isolateId:
'1'
,
),
''
);
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
});
testWithoutContext
(
'flutterDebugDumpSemanticsTreeInInverseHitTestOrder handles missing method'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
const
FakeVmServiceRequest
(
method:
'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
},
errorCode:
RPCErrorCodes
.
kMethodNotFound
,
),
]
);
expect
(
await
fakeVmServiceHost
.
vmService
.
flutterDebugDumpSemanticsTreeInInverseHitTestOrder
(
isolateId:
'1'
,
),
''
);
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
});
testWithoutContext
(
'flutterDebugDumpLayerTree handles missing method'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
const
FakeVmServiceRequest
(
method:
'ext.flutter.debugDumpLayerTree'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
},
errorCode:
RPCErrorCodes
.
kMethodNotFound
,
),
]
);
expect
(
await
fakeVmServiceHost
.
vmService
.
flutterDebugDumpLayerTree
(
isolateId:
'1'
,
),
''
);
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
});
testWithoutContext
(
'flutterDebugDumpRenderTree handles missing method'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
const
FakeVmServiceRequest
(
method:
'ext.flutter.debugDumpRenderTree'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
},
errorCode:
RPCErrorCodes
.
kMethodNotFound
,
),
]
);
expect
(
await
fakeVmServiceHost
.
vmService
.
flutterDebugDumpRenderTree
(
isolateId:
'1'
,
),
''
);
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
});
testWithoutContext
(
'flutterDebugDumpApp handles missing method'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
const
FakeVmServiceRequest
(
method:
'ext.flutter.debugDumpApp'
,
args:
<
String
,
Object
>{
'isolateId'
:
'1'
},
errorCode:
RPCErrorCodes
.
kMethodNotFound
,
),
]
);
expect
(
await
fakeVmServiceHost
.
vmService
.
flutterDebugDumpApp
(
isolateId:
'1'
,
),
''
);
expect
(
fakeVmServiceHost
.
hasRemainingExpectations
,
false
);
});
testWithoutContext
(
'Framework service extension invocations return null if service disappears '
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
VmServiceExpectation
>[
...
...
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