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
a2fa98eb
Unverified
Commit
a2fa98eb
authored
Jan 09, 2019
by
Jonah Williams
Committed by
GitHub
Jan 09, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add polling module discovery for Fuchsia (#24994)
parent
32041c0c
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
214 additions
and
34 deletions
+214
-34
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+6
-34
fuchsia_device.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+104
-0
fuchsa_device_test.dart
packages/flutter_tools/test/fuchsia/fuchsa_device_test.dart
+104
-0
No files found.
packages/flutter_tools/lib/src/commands/attach.dart
View file @
a2fa98eb
...
...
@@ -7,7 +7,6 @@ import 'dart:async';
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/utils.dart'
;
import
'../cache.dart'
;
import
'../commands/daemon.dart'
;
...
...
@@ -138,34 +137,18 @@ class AttachCommand extends FlutterCommand {
if
(
module
==
null
)
{
throwToolExit
(
'
\'
--module
\'
is requried for attaching to a Fuchsia device'
);
}
usesIpv6
=
_isIpv6
(
device
.
id
);
final
List
<
int
>
ports
=
await
device
.
servicePorts
();
if
(
ports
.
isEmpty
)
{
throwToolExit
(
'No active service ports on
${device.name}
'
);
}
final
List
<
int
>
localPorts
=
<
int
>[];
for
(
int
port
in
ports
)
{
localPorts
.
add
(
await
device
.
portForwarder
.
forward
(
port
));
}
final
Status
status
=
logger
.
startProgress
(
'Waiting for a connection from Flutter on
${device.name}
...'
,
expectSlowOperation:
true
,
);
usesIpv6
=
device
.
ipv6
;
FuchsiaIsolateDiscoveryProtocol
isolateDiscoveryProtocol
;
try
{
final
int
localPort
=
await
device
.
findIsolatePort
(
module
,
localPorts
);
if
(
localPort
==
null
)
{
throwToolExit
(
'No active Observatory running module
\'
$module
\'
on
${device.name}
'
);
}
observatoryUri
=
usesIpv6
?
Uri
.
parse
(
'http://[
$ipv6Loopback
]:
$localPort
/'
)
:
Uri
.
parse
(
'http://
$ipv4Loopback
:
$localPort
/'
);
status
.
stop
();
isolateDiscoveryProtocol
=
device
.
getIsolateDiscoveryProtocol
(
module
);
observatoryUri
=
await
isolateDiscoveryProtocol
.
uri
;
printStatus
(
'Done.'
);
}
catch
(
_
)
{
isolateDiscoveryProtocol
?.
dispose
();
final
List
<
ForwardedPort
>
ports
=
device
.
portForwarder
.
forwardedPorts
.
toList
();
for
(
ForwardedPort
port
in
ports
)
{
await
device
.
portForwarder
.
unforward
(
port
);
}
status
.
cancel
();
rethrow
;
}
}
else
{
...
...
@@ -241,17 +224,6 @@ class AttachCommand extends FlutterCommand {
}
Future
<
void
>
_validateArguments
()
async
{}
bool
_isIpv6
(
String
address
)
{
// Workaround for https://github.com/dart-lang/sdk/issues/29456
final
String
fragment
=
address
.
split
(
'%'
).
first
;
try
{
Uri
.
parseIPv6Address
(
fragment
);
return
true
;
}
on
FormatException
{
return
false
;
}
}
}
class
HotRunnerFactory
{
...
...
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
View file @
a2fa98eb
...
...
@@ -9,6 +9,7 @@ import 'package:meta/meta.dart';
import
'../application_package.dart'
;
import
'../base/common.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/platform.dart'
;
import
'../base/process.dart'
;
import
'../base/process_manager.dart'
;
...
...
@@ -24,6 +25,11 @@ import 'fuchsia_workflow.dart';
final
String
_ipv4Loopback
=
InternetAddress
.
loopbackIPv4
.
address
;
final
String
_ipv6Loopback
=
InternetAddress
.
loopbackIPv6
.
address
;
// Enables testing the fuchsia isolate discovery
Future
<
VMService
>
_kDefaultFuchsiaIsolateDiscoveryConnector
(
Uri
uri
)
{
return
VMService
.
connect
(
uri
);
}
/// Read the log for a particular device.
class
_FuchsiaLogReader
extends
DeviceLogReader
{
_FuchsiaLogReader
(
this
.
_device
,
[
this
.
_app
]);
...
...
@@ -207,6 +213,17 @@ class FuchsiaDevice extends Device {
@override
bool
get
supportsScreenshot
=>
false
;
bool
get
ipv6
{
// Workaround for https://github.com/dart-lang/sdk/issues/29456
final
String
fragment
=
id
.
split
(
'%'
).
first
;
try
{
Uri
.
parseIPv6Address
(
fragment
);
return
true
;
}
on
FormatException
{
return
false
;
}
}
/// List the ports currently running a dart observatory.
Future
<
List
<
int
>>
servicePorts
()
async
{
final
String
findOutput
=
await
shell
(
'find /hub -name vmservice-port'
);
...
...
@@ -278,6 +295,93 @@ class FuchsiaDevice extends Device {
throwToolExit
(
'No ports found running
$isolateName
'
);
return
null
;
}
FuchsiaIsolateDiscoveryProtocol
getIsolateDiscoveryProtocol
(
String
isolateName
)
=>
FuchsiaIsolateDiscoveryProtocol
(
this
,
isolateName
);
}
class
FuchsiaIsolateDiscoveryProtocol
{
FuchsiaIsolateDiscoveryProtocol
(
this
.
_device
,
this
.
_isolateName
,
[
this
.
_vmServiceConnector
=
_kDefaultFuchsiaIsolateDiscoveryConnector
,
this
.
_pollOnce
=
false
,
]);
static
const
Duration
_pollDuration
=
Duration
(
seconds:
10
);
final
Map
<
int
,
VMService
>
_ports
=
<
int
,
VMService
>{};
final
FuchsiaDevice
_device
;
final
String
_isolateName
;
final
Completer
<
Uri
>
_foundUri
=
Completer
<
Uri
>();
final
Future
<
VMService
>
Function
(
Uri
)
_vmServiceConnector
;
// whether to only poll once.
final
bool
_pollOnce
;
Timer
_pollingTimer
;
Status
_status
;
FutureOr
<
Uri
>
get
uri
{
if
(
_uri
!=
null
)
{
return
_uri
;
}
_status
??=
logger
.
startProgress
(
'Waiting for a connection from
$_isolateName
on
${_device.name}
...'
,
expectSlowOperation:
true
,
);
_pollingTimer
??=
Timer
(
_pollDuration
,
_findIsolate
);
return
_foundUri
.
future
.
then
((
Uri
uri
)
{
_uri
=
uri
;
return
uri
;
});
}
Uri
_uri
;
void
dispose
()
{
if
(!
_foundUri
.
isCompleted
)
{
_status
?.
cancel
();
_status
=
null
;
_pollingTimer
?.
cancel
();
_pollingTimer
=
null
;
_foundUri
.
completeError
(
Exception
(
'Did not complete'
));
}
}
Future
<
void
>
_findIsolate
()
async
{
final
List
<
int
>
ports
=
await
_device
.
servicePorts
();
for
(
int
port
in
ports
)
{
VMService
service
;
if
(
_ports
.
containsKey
(
port
))
{
service
=
_ports
[
port
];
}
else
{
final
int
localPort
=
await
_device
.
portForwarder
.
forward
(
port
);
try
{
final
Uri
uri
=
Uri
.
parse
(
'http://[
$_ipv6Loopback
]:
$localPort
'
);
service
=
await
_vmServiceConnector
(
uri
);
_ports
[
port
]
=
service
;
}
on
SocketException
catch
(
err
)
{
printTrace
(
'Failed to connect to
$localPort
:
$err
'
);
continue
;
}
}
await
service
.
getVM
();
await
service
.
refreshViews
();
for
(
FlutterView
flutterView
in
service
.
vm
.
views
)
{
if
(
flutterView
.
uiIsolate
==
null
)
{
continue
;
}
final
Uri
address
=
flutterView
.
owner
.
vmService
.
httpAddress
;
if
(
flutterView
.
uiIsolate
.
name
.
contains
(
_isolateName
))
{
_foundUri
.
complete
(
_device
.
ipv6
?
Uri
.
parse
(
'http://[
$_ipv6Loopback
]:
${address.port}
/'
)
:
Uri
.
parse
(
'http://
$_ipv4Loopback
:
${address.port}
/'
));
_status
.
stop
();
return
;
}
}
}
if
(
_pollOnce
)
{
_foundUri
.
completeError
(
Exception
(
'Max iterations exceeded'
));
_status
.
stop
();
return
;
}
_pollingTimer
=
Timer
(
_pollDuration
,
_findIsolate
);
}
}
class
_FuchsiaPortForwarder
extends
DevicePortForwarder
{
...
...
packages/flutter_tools/test/fuchsia/fuchsa_device_test.dart
View file @
a2fa98eb
...
...
@@ -5,6 +5,8 @@
import
'dart:async'
;
import
'dart:convert'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/vmservice.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
...
...
@@ -198,6 +200,65 @@ void main() {
});
});
});
group
(
FuchsiaIsolateDiscoveryProtocol
,
()
{
Future
<
Uri
>
findUri
(
List
<
MockFlutterView
>
views
,
String
expectedIsolateName
)
{
final
MockPortForwarder
portForwarder
=
MockPortForwarder
();
final
MockVMService
vmService
=
MockVMService
();
final
MockVM
vm
=
MockVM
();
vm
.
vmService
=
vmService
;
vmService
.
vm
=
vm
;
vm
.
views
=
views
;
for
(
MockFlutterView
view
in
views
)
{
view
.
owner
=
vm
;
}
final
MockFuchsiaDevice
fuchsiaDevice
=
MockFuchsiaDevice
(
'123'
,
portForwarder
,
false
);
final
FuchsiaIsolateDiscoveryProtocol
discoveryProtocol
=
FuchsiaIsolateDiscoveryProtocol
(
fuchsiaDevice
,
expectedIsolateName
,
(
Uri
uri
)
async
=>
vmService
,
true
// only poll once.
);
when
(
fuchsiaDevice
.
servicePorts
()).
thenAnswer
((
Invocation
invocation
)
async
=>
<
int
>[
1
]);
when
(
portForwarder
.
forward
(
1
)).
thenAnswer
((
Invocation
invocation
)
async
=>
2
);
when
(
vmService
.
getVM
()).
thenAnswer
((
Invocation
invocation
)
=>
Future
<
void
>.
value
(
null
));
when
(
vmService
.
refreshViews
()).
thenAnswer
((
Invocation
invocation
)
=>
Future
<
void
>.
value
(
null
));
when
(
vmService
.
httpAddress
).
thenReturn
(
Uri
.
parse
(
'example'
));
return
discoveryProtocol
.
uri
;
}
testUsingContext
(
'can find flutter view with matching isolate name'
,
()
async
{
const
String
expectedIsolateName
=
'foobar'
;
final
Uri
uri
=
await
findUri
(<
MockFlutterView
>[
MockFlutterView
(
null
),
// no ui isolate.
MockFlutterView
(
MockIsolate
(
'wrong name'
)),
// wrong name.
MockFlutterView
(
MockIsolate
(
expectedIsolateName
)),
// matching name.
],
expectedIsolateName
);
expect
(
uri
.
toString
(),
'http://
${InternetAddress.loopbackIPv4.address}
:0/'
);
},
overrides:
<
Type
,
Generator
>{
Logger:
()
=>
StdoutLogger
(),
});
testUsingContext
(
'can handle flutter view without matching isolate name'
,
()
async
{
const
String
expectedIsolateName
=
'foobar'
;
final
Future
<
Uri
>
uri
=
findUri
(<
MockFlutterView
>[
MockFlutterView
(
null
),
// no ui isolate.
MockFlutterView
(
MockIsolate
(
'wrong name'
)),
// wrong name.
],
expectedIsolateName
);
expect
(
uri
,
throwsException
);
},
overrides:
<
Type
,
Generator
>{
Logger:
()
=>
StdoutLogger
(),
});
testUsingContext
(
'can handle non flutter view'
,
()
async
{
const
String
expectedIsolateName
=
'foobar'
;
final
Future
<
Uri
>
uri
=
findUri
(<
MockFlutterView
>[
MockFlutterView
(
null
),
// no ui isolate.
],
expectedIsolateName
);
expect
(
uri
,
throwsException
);
},
overrides:
<
Type
,
Generator
>{
Logger:
()
=>
StdoutLogger
(),
});
});
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
...
...
@@ -207,3 +268,46 @@ class MockProcessResult extends Mock implements ProcessResult {}
class
MockFile
extends
Mock
implements
File
{}
class
MockProcess
extends
Mock
implements
Process
{}
class
MockFuchsiaDevice
extends
Mock
implements
FuchsiaDevice
{
MockFuchsiaDevice
(
this
.
id
,
this
.
portForwarder
,
this
.
ipv6
);
@override
final
bool
ipv6
;
@override
final
String
id
;
@override
final
DevicePortForwarder
portForwarder
;
}
class
MockPortForwarder
extends
Mock
implements
DevicePortForwarder
{}
class
MockVMService
extends
Mock
implements
VMService
{
@override
VM
vm
;
}
class
MockVM
extends
Mock
implements
VM
{
@override
VMService
vmService
;
@override
List
<
FlutterView
>
views
;
}
class
MockFlutterView
extends
Mock
implements
FlutterView
{
MockFlutterView
(
this
.
uiIsolate
);
@override
final
Isolate
uiIsolate
;
@override
ServiceObjectOwner
owner
;
}
class
MockIsolate
extends
Mock
implements
Isolate
{
MockIsolate
(
this
.
name
);
@override
final
String
name
;
}
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