[fuchsia_remote_debug_protocol] Adds the fuchsia remote debug protocol package.
Adds a package that will support connecting to and debugging devices with multiple instances of the Dart VM, and operate on multiple Isolates and Flutter Views.
Currently supports connecting to all existing Dart VMs and extracting information about all Flutter Views running across each VM.
diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml
index 2a24d66..615f9ad 100644
--- a/dev/automated_tests/pubspec.yaml
+++ b/dev/automated_tests/pubspec.yaml
@@ -7,7 +7,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -58,4 +58,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: 633a
+# PUBSPEC CHECKSUM: d33b
diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml
index 8e8f4c2..7515444 100644
--- a/dev/benchmarks/complex_layout/pubspec.yaml
+++ b/dev/benchmarks/complex_layout/pubspec.yaml
@@ -37,7 +37,7 @@
sdk: flutter
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -79,4 +79,4 @@
- packages/flutter_gallery_assets/ali_connors_sml.png
- packages/flutter_gallery_assets/top_10_australian_beaches.png
-# PUBSPEC CHECKSUM: e1fb
+# PUBSPEC CHECKSUM: c6fc
diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml
index e1d5f1d..599cbb7 100644
--- a/dev/benchmarks/microbenchmarks/pubspec.yaml
+++ b/dev/benchmarks/microbenchmarks/pubspec.yaml
@@ -11,7 +11,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -65,4 +65,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: 4bb8
+# PUBSPEC CHECKSUM: 48b9
diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml
index d54cc6c..29660bd 100644
--- a/dev/bots/pubspec.yaml
+++ b/dev/bots/pubspec.yaml
@@ -23,7 +23,7 @@
test: 0.12.32+2
mockito: 2.2.3
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -59,4 +59,4 @@
web_socket_channel: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-# PUBSPEC CHECKSUM: f192
+# PUBSPEC CHECKSUM: 9a93
diff --git a/dev/bots/test.dart b/dev/bots/test.dart
index 6a00621..14bf481 100644
--- a/dev/bots/test.dart
+++ b/dev/bots/test.dart
@@ -189,6 +189,8 @@
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), options: options);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), options: options);
+ await _runFlutterTest(path.join(flutterRoot, 'packages',
+ 'fuchsia_remote_debug_protocol'), options: options);
await _pubRunTest(path.join(flutterRoot, 'packages', 'flutter_tools'));
await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'));
diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml
index 5d6dc7a..8ba4a96 100644
--- a/dev/devicelab/pubspec.yaml
+++ b/dev/devicelab/pubspec.yaml
@@ -39,7 +39,7 @@
# See packages/flutter_test/pubspec.yaml for why we're pinning this version.
test: 0.12.32+2
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -71,4 +71,4 @@
watcher: 0.9.7+7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-# PUBSPEC CHECKSUM: a29e
+# PUBSPEC CHECKSUM: e59f
diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml
index 67f698b..9bd4af8 100644
--- a/dev/integration_tests/ui/pubspec.yaml
+++ b/dev/integration_tests/ui/pubspec.yaml
@@ -38,7 +38,7 @@
sdk: flutter
test: 0.12.32+2
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -74,4 +74,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: a8a4
+# PUBSPEC CHECKSUM: f1a5
diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml
index d6e751e..4c533e5 100644
--- a/dev/manual_tests/pubspec.yaml
+++ b/dev/manual_tests/pubspec.yaml
@@ -17,7 +17,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -64,4 +64,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: 1427
+# PUBSPEC CHECKSUM: 9c28
diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml
index 7b36930..2b5f504 100644
--- a/dev/tools/pubspec.yaml
+++ b/dev/tools/pubspec.yaml
@@ -26,7 +26,7 @@
test: 0.12.32+2
mockito: 2.2.3
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -60,4 +60,4 @@
web_socket_channel: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-# PUBSPEC CHECKSUM: d99b
+# PUBSPEC CHECKSUM: 829c
diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml
index 9dcc45f..83d2192 100644
--- a/dev/tools/vitool/pubspec.yaml
+++ b/dev/tools/vitool/pubspec.yaml
@@ -22,7 +22,7 @@
test: 0.12.32+2
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -63,4 +63,4 @@
web_socket_channel: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-# PUBSPEC CHECKSUM: c269
+# PUBSPEC CHECKSUM: 4b6a
diff --git a/examples/catalog/pubspec.yaml b/examples/catalog/pubspec.yaml
index ba16f40..a3384a4 100644
--- a/examples/catalog/pubspec.yaml
+++ b/examples/catalog/pubspec.yaml
@@ -18,7 +18,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -68,4 +68,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: e1fb
+# PUBSPEC CHECKSUM: c6fc
diff --git a/examples/flutter_gallery/pubspec.yaml b/examples/flutter_gallery/pubspec.yaml
index 38bc9ec..8f99388 100644
--- a/examples/flutter_gallery/pubspec.yaml
+++ b/examples/flutter_gallery/pubspec.yaml
@@ -32,7 +32,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -166,4 +166,4 @@
fonts:
- asset: packages/flutter_gallery_assets/shrine/fonts/abrilfatface/AbrilFatface-Regular.ttf
-# PUBSPEC CHECKSUM: 5fb8
+# PUBSPEC CHECKSUM: f2b9
diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml
index 08a6552..f8cd918 100644
--- a/examples/hello_world/pubspec.yaml
+++ b/examples/hello_world/pubspec.yaml
@@ -15,7 +15,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -62,4 +62,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: 633a
+# PUBSPEC CHECKSUM: d33b
diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml
index bfa96e5..a9d16b2 100644
--- a/examples/layers/pubspec.yaml
+++ b/examples/layers/pubspec.yaml
@@ -14,7 +14,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -63,4 +63,4 @@
- services/data.json
uses-material-design: true
-# PUBSPEC CHECKSUM: 633a
+# PUBSPEC CHECKSUM: d33b
diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml
index a4e967d..ad1d6dd 100644
--- a/examples/platform_channel/pubspec.yaml
+++ b/examples/platform_channel/pubspec.yaml
@@ -17,7 +17,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -68,4 +68,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: e1fb
+# PUBSPEC CHECKSUM: c6fc
diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml
index 01493d6..33e9dc3 100644
--- a/examples/platform_channel_swift/pubspec.yaml
+++ b/examples/platform_channel_swift/pubspec.yaml
@@ -17,7 +17,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -68,4 +68,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: e1fb
+# PUBSPEC CHECKSUM: c6fc
diff --git a/examples/stocks/pubspec.yaml b/examples/stocks/pubspec.yaml
index 038aca1..bdf15fe 100644
--- a/examples/stocks/pubspec.yaml
+++ b/examples/stocks/pubspec.yaml
@@ -11,7 +11,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -72,4 +72,4 @@
flutter:
uses-material-design: true
-# PUBSPEC CHECKSUM: b601
+# PUBSPEC CHECKSUM: 802
diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml
index 48ccb8f..e2f5df35 100644
--- a/packages/flutter/pubspec.yaml
+++ b/packages/flutter/pubspec.yaml
@@ -20,7 +20,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -67,4 +67,4 @@
environment:
sdk: '>=1.19.0 <2.0.0'
-# PUBSPEC CHECKSUM: 1427
+# PUBSPEC CHECKSUM: 9c28
diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml
index c1a6377..3dd98b7 100644
--- a/packages/flutter_driver/pubspec.yaml
+++ b/packages/flutter_driver/pubspec.yaml
@@ -20,7 +20,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -69,4 +69,4 @@
mockito: 2.2.3
quiver: 0.28.0
-# PUBSPEC CHECKSUM: 77e8
+# PUBSPEC CHECKSUM: 74e9
diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml
index 65bb80e..146e837 100644
--- a/packages/flutter_localizations/pubspec.yaml
+++ b/packages/flutter_localizations/pubspec.yaml
@@ -19,7 +19,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -62,4 +62,4 @@
web_socket_channel: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-# PUBSPEC CHECKSUM: 5707
+# PUBSPEC CHECKSUM: f308
diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml
index ee243c2..9500c82 100644
--- a/packages/flutter_test/pubspec.yaml
+++ b/packages/flutter_test/pubspec.yaml
@@ -23,7 +23,7 @@
args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -67,4 +67,4 @@
web_socket_channel: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-# PUBSPEC CHECKSUM: 633a
+# PUBSPEC CHECKSUM: d33b
diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
index 6f568e0..8be98d1 100644
--- a/packages/flutter_tools/pubspec.yaml
+++ b/packages/flutter_tools/pubspec.yaml
@@ -44,7 +44,7 @@
front_end: any
async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
- barback: 0.15.2+14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -95,4 +95,4 @@
kernel:
path: ../../bin/cache/dart-sdk/lib/kernel
-# PUBSPEC CHECKSUM: 15a5
+# PUBSPEC CHECKSUM: d6a6
diff --git a/packages/fuchsia_remote_debug_protocol/examples/list_vms_and_flutter_views.dart b/packages/fuchsia_remote_debug_protocol/examples/list_vms_and_flutter_views.dart
new file mode 100644
index 0000000..987ec9d
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/examples/list_vms_and_flutter_views.dart
@@ -0,0 +1,48 @@
+// Copyright 2018 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 'dart:core';
+
+import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart';
+import 'package:fuchsia_remote_debug_protocol/logging.dart';
+
+/// Runs through a simple usage of the fuchsia_remote_debug_protocol library:
+/// connects to a remote machine at the address in argument 1 (interface
+/// optional for argument 2) to list all active flutter views and Dart VMs
+/// running on said device. This uses an SSH config file (optional, depending
+/// on your setup).
+///
+/// Example usage:
+///
+/// $ dart examples/list_vms_and_flutter_views.dart \
+/// fe80::8eae:4cff:fef4:9247 eno1
+Future<Null> main(List<String> args) async {
+ // Log only at info level within the library. If issues arise, this can be
+ // changed to [LoggingLevel.all] or [LoggingLevel.fine] to see more
+ // information.
+ Logger.globalLevel = LoggingLevel.info;
+ if (args.isEmpty) {
+ print('Expects an IP address and/or network interface');
+ return;
+ }
+ final String address = args[0];
+ final String interface = args.length > 1 ? args[1] : '';
+ // Example ssh config path for the Fuchsia device after having made a local
+ // build.
+ const String sshConfigPath = '../../out/release-x86-64/ssh-keys/ssh_config';
+ final FuchsiaRemoteConnection connection =
+ await FuchsiaRemoteConnection.connect(address, interface, sshConfigPath);
+ print('On $address, the following Dart VM ports are running:');
+ for (int port in await connection.getDeviceServicePorts()) {
+ print('\t$port');
+ }
+ print('');
+
+ print('The following Flutter views are running:');
+ for (FlutterView view in await connection.getFlutterViews()) {
+ print('\t${view.name ?? view.id}');
+ }
+ await connection.stop();
+}
diff --git a/packages/fuchsia_remote_debug_protocol/lib/fuchsia_remote_debug_protocol.dart b/packages/fuchsia_remote_debug_protocol/lib/fuchsia_remote_debug_protocol.dart
new file mode 100644
index 0000000..6c08b94
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/fuchsia_remote_debug_protocol.dart
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+/// Provides an API to test/debug Flutter applications on remote Fuchsia devices
+/// and emulators.
+///
+/// The application typically runs in a separate process from the actual
+/// test, wherein the user can supply the process with various events to test
+/// the behavior of said application.
+///
+/// The API will provide methods to connect to one or more instances of the
+/// Dart VM and operate on Isolates and Flutter Views, including affordances to
+/// subscribe to creation and destruction of Dart VM instances, Isolates, and
+/// Flutter Views. Not all of these features are yet implemented, as this
+/// library is a work in progress.
+library fuchsia_remote_debug_protocol;
+
+export 'src/common/network.dart';
+export 'src/dart/dart_vm.dart';
+export 'src/fuchsia_remote_connection.dart';
+export 'src/runners/ssh_command_runner.dart';
diff --git a/packages/fuchsia_remote_debug_protocol/lib/logging.dart b/packages/fuchsia_remote_debug_protocol/lib/logging.dart
new file mode 100644
index 0000000..4b38acf
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/logging.dart
@@ -0,0 +1,12 @@
+// Copyright 2018 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.
+
+/// Library for logging the remote debug protocol internals.
+///
+/// Useful for determining connection issues and the like. This is included as a
+/// separate library so that it can be imported under a separate namespace in
+/// the event that you are using a logging package with similar class names.
+library logging;
+
+export 'src/common/logging.dart';
diff --git a/packages/fuchsia_remote_debug_protocol/lib/src/common/logging.dart b/packages/fuchsia_remote_debug_protocol/lib/src/common/logging.dart
new file mode 100644
index 0000000..6e72822
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/src/common/logging.dart
@@ -0,0 +1,150 @@
+// Copyright 2018 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:core';
+import 'dart:io';
+
+/// Determines the level of logging.
+///
+/// Verbosity is increasing from one (none) to five (fine). The sixth level
+/// (all) logs everything.
+enum LoggingLevel {
+ /// Logs no logs.
+ none,
+
+ /// Logs severe messages at the most (note that severe messages are always
+ /// logged).
+ ///
+ /// Severe means that the process has encountered a critical level of failure
+ /// in which it cannot recover and will terminate as a result.
+ severe,
+
+ /// Logs warning messages at the most.
+ ///
+ /// Warning implies that an error was encountered, but the process will
+ /// attempt to continue, and may/may not succeed.
+ warning,
+
+ /// Logs info messages at the most.
+ ///
+ /// An info message is for determining information about the state of the
+ /// application as it runs through execution.
+ info,
+
+ /// Logs fine logs at the most.
+ ///
+ /// A fine message is one that is not important for logging outside of
+ /// debugging potential issues in the application.
+ fine,
+
+ /// Logs everything.
+ all,
+}
+
+/// Signature of a function that logs a [LogMessage].
+typedef void LoggingFunction(LogMessage log);
+
+/// The default logging function.
+///
+/// Runs the [print] function using the format string:
+/// '[${log.levelName}]::${log.tag}--${log.time}: ${log.message}'
+///
+/// Exits with status code 1 if the `log` is [LoggingLevel.severe].
+LoggingFunction defaultLoggingFunction = (LogMessage log) {
+ print('[${log.levelName}]::${log.tag}--${log.time}: ${log.message}');
+ if (log.level == LoggingLevel.severe) {
+ exit(1);
+ }
+};
+
+/// Represents a logging message created by the logger.
+///
+/// Includes a message, the time the message was created, the level of the log
+/// as an enum, the name of the level as a string, and a tag. This class is used
+/// to print from the global logging function defined in
+/// [Logger.loggingFunction] (a function that can be user-defined).
+class LogMessage {
+ /// Creates a log, including the level of the log, the time it was created,
+ /// and the actual log message.
+ ///
+ /// When this message is created, it sets its [time] to [DateTime.now].
+ LogMessage(this.message, this.tag, this.level)
+ : this.levelName =
+ level.toString().substring(level.toString().indexOf('.') + 1),
+ this.time = new DateTime.now();
+
+ /// The actual log message.
+ final String message;
+
+ /// The time the log message was created.
+ final DateTime time;
+
+ /// The level of this log.
+ final LoggingLevel level;
+
+ /// The human readable level of this log.
+ final String levelName;
+
+ /// The tag associated with the message. This is set to [Logger.tag] when
+ /// emitted by a [Logger] object.
+ final String tag;
+}
+
+/// Logs messages using the global [LoggingFunction] and logging level.
+///
+/// Example of setting log level to [LoggingLevel.warning] and creating a
+/// logging function:
+///
+/// ```dart
+/// Logger.globalLevel = LoggingLevel.warning;
+/// ```
+class Logger {
+ /// Creates a logger with the given [tag].
+ Logger(this.tag);
+
+ /// The tag associated with the log message (usable in the logging function).
+ /// [LogMessage] objects emitted by this class will have [LogMessage.tag] set
+ /// to this value.
+ final String tag;
+
+ /// Determines what to do when the [Logger] creates and attempts to log a
+ /// [LogMessage] object.
+ ///
+ /// This function can be reassigned to whatever functionality of your
+ /// choosing, so long as it has the same signature of [LoggingFunction] (it
+ /// can also be an asynchronous function, if doing file I/O, for
+ /// example).
+ static LoggingFunction loggingFunction = defaultLoggingFunction;
+
+ /// Determines the logging level all [Logger] instances use.
+ static LoggingLevel globalLevel = LoggingLevel.none;
+
+ /// Logs a [LoggingLevel.severe] level `message`.
+ ///
+ /// Severe messages are always logged, regardless of what level is set.
+ void severe(String message) {
+ loggingFunction(new LogMessage(message, tag, LoggingLevel.severe));
+ }
+
+ /// Logs a [LoggingLevel.warning] level `message`.
+ void warning(String message) {
+ if (globalLevel.index >= LoggingLevel.warning.index) {
+ loggingFunction(new LogMessage(message, tag, LoggingLevel.warning));
+ }
+ }
+
+ /// Logs a [LoggingLevel.info] level `message`.
+ void info(String message) {
+ if (globalLevel.index >= LoggingLevel.info.index) {
+ loggingFunction(new LogMessage(message, tag, LoggingLevel.info));
+ }
+ }
+
+ /// Logs a [LoggingLevel.fine] level `message`.
+ void fine(String message) {
+ if (globalLevel.index >= LoggingLevel.fine.index) {
+ loggingFunction(new LogMessage(message, tag, LoggingLevel.fine));
+ }
+ }
+}
diff --git a/packages/fuchsia_remote_debug_protocol/lib/src/common/network.dart b/packages/fuchsia_remote_debug_protocol/lib/src/common/network.dart
new file mode 100644
index 0000000..ecd4117
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/src/common/network.dart
@@ -0,0 +1,35 @@
+// Copyright 2018 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:core';
+
+/// Determines whether `address` is a valid IPv6 or IPv4 address.
+///
+/// Throws an [ArgumentError] if the address is neither.
+void validateAddress(String address) {
+ if (!(isIpV4Address(address) || isIpV6Address(address))) {
+ throw new ArgumentError(
+ '"$address" is neither a valid IPv4 nor IPv6 address');
+ }
+}
+
+/// Returns true if `address` is a valid IPv6 address.
+bool isIpV6Address(String address) {
+ try {
+ Uri.parseIPv6Address(address);
+ return true;
+ } on FormatException {
+ return false;
+ }
+}
+
+/// Returns true if `address` is a valid IPv4 address.
+bool isIpV4Address(String address) {
+ try {
+ Uri.parseIPv4Address(address);
+ return true;
+ } on FormatException {
+ return false;
+ }
+}
diff --git a/packages/fuchsia_remote_debug_protocol/lib/src/dart/dart_vm.dart b/packages/fuchsia_remote_debug_protocol/lib/src/dart/dart_vm.dart
new file mode 100644
index 0000000..5709ade
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/src/dart/dart_vm.dart
@@ -0,0 +1,203 @@
+// Copyright 2018 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 'dart:io';
+
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:web_socket_channel/io.dart';
+
+import '../common/logging.dart';
+
+const Duration _kConnectTimeout = const Duration(seconds: 30);
+
+const Duration _kReconnectAttemptInterval = const Duration(seconds: 3);
+
+const Duration _kRpcTimeout = const Duration(seconds: 5);
+
+final Logger _log = new Logger('DartVm');
+
+/// Signature of an asynchronous function for astablishing a JSON RPC-2
+/// connection to a [Uri].
+typedef Future<json_rpc.Peer> RpcPeerConnectionFunction(Uri uri);
+
+/// [DartVm] uses this function to connect to the Dart VM on Fuchsia.
+///
+/// This function can be assigned to a different one in the event that a
+/// custom connection function is needed.
+RpcPeerConnectionFunction fuchsiaVmServiceConnectionFunction = _waitAndConnect;
+
+/// Attempts to connect to a Dart VM service.
+///
+/// Gives up after `_kConnectTimeout` has elapsed.
+Future<json_rpc.Peer> _waitAndConnect(Uri uri) async {
+ final Stopwatch timer = new Stopwatch()..start();
+
+ Future<json_rpc.Peer> attemptConnection(Uri uri) async {
+ WebSocket socket;
+ json_rpc.Peer peer;
+ try {
+ socket = await WebSocket.connect(uri.toString());
+ peer = new json_rpc.Peer(new IOWebSocketChannel(socket).cast())..listen();
+ return peer;
+ } catch (e) {
+ await peer?.close();
+ await socket?.close();
+ if (timer.elapsed < _kConnectTimeout) {
+ _log.info('Attempting to reconnect');
+ await new Future<Null>.delayed(_kReconnectAttemptInterval);
+ return attemptConnection(uri);
+ } else {
+ _log.severe('Connection to Fuchsia\'s Dart VM timed out at '
+ '${uri.toString()}');
+ rethrow;
+ }
+ }
+ }
+
+ return attemptConnection(uri);
+}
+
+/// Restores the VM service connection function to the default implementation.
+void restoreVmServiceConnectionFunction() {
+ fuchsiaVmServiceConnectionFunction = _waitAndConnect;
+}
+
+/// An error raised when a malformed RPC response is received from the Dart VM.
+///
+/// A more detailed description of the error is found within the [message]
+/// field.
+class RpcFormatError extends Error {
+ /// Basic constructor outlining the reason for the format error.
+ RpcFormatError(this.message);
+
+ /// The reason for format error.
+ final String message;
+
+ @override
+ String toString() {
+ return '$RpcFormatError: $message\n${super.stackTrace}';
+ }
+}
+
+/// Handles JSON RPC-2 communication with a Dart VM service.
+///
+/// Either wraps existing RPC calls to the Dart VM service, or runs raw RPC
+/// function calls via [invokeRpc].
+class DartVm {
+ DartVm._(this._peer);
+
+ final json_rpc.Peer _peer;
+
+ /// Attempts to connect to the given [Uri].
+ ///
+ /// Throws an error if unable to connect.
+ static Future<DartVm> connect(Uri uri) async {
+ if (uri.scheme == 'http') {
+ uri = uri.replace(scheme: 'ws', path: '/ws');
+ }
+ final json_rpc.Peer peer = await fuchsiaVmServiceConnectionFunction(uri);
+ if (peer == null) {
+ return null;
+ }
+ return new DartVm._(peer);
+ }
+
+ /// Invokes a raw JSON RPC command with the VM service.
+ ///
+ /// When `timeout` is set and reached, throws a [TimeoutException].
+ ///
+ /// If the function returns, it is with a parsed JSON response.
+ Future<Map<String, dynamic>> invokeRpc(
+ String function, {
+ Map<String, dynamic> params,
+ Duration timeout,
+ }) async {
+ final Future<Map<String, dynamic>> future = _peer.sendRequest(
+ function,
+ params ?? <String, dynamic>{},
+ );
+ if (timeout == null) {
+ return future;
+ }
+ return future.timeout(timeout, onTimeout: () {
+ throw new TimeoutException(
+ 'Peer connection timed out during RPC call',
+ timeout,
+ );
+ });
+ }
+
+ /// Returns a list of [FlutterView] objects running across all Dart VM's.
+ ///
+ /// If there is no associated isolate with the flutter view (used to determine
+ /// the flutter view's name), then the flutter view's ID will be added
+ /// instead. If none of these things can be found (isolate has no name or the
+ /// flutter view has no ID), then the result will not be added to the list.
+ Future<List<FlutterView>> getAllFlutterViews() async {
+ final List<FlutterView> views = <FlutterView>[];
+ final Map<String, dynamic> rpcResponse =
+ await invokeRpc('_flutter.listViews', timeout: _kRpcTimeout);
+ final List<Map<String, dynamic>> flutterViewsJson = rpcResponse['views'];
+ for (Map<String, dynamic> jsonView in flutterViewsJson) {
+ final FlutterView flutterView = new FlutterView._fromJson(jsonView);
+ if (flutterView != null) {
+ views.add(flutterView);
+ }
+ }
+ return views;
+ }
+
+ /// Disconnects from the Dart VM Service.
+ ///
+ /// After this function completes this object is no longer usable.
+ Future<Null> stop() async {
+ await _peer?.close();
+ }
+}
+
+/// Represents an instance of a Flutter view running on a Fuchsia device.
+class FlutterView {
+ FlutterView._(this._name, this._id);
+
+ /// Attempts to construct a [FlutterView] from a json representation.
+ ///
+ /// If there is no isolate and no ID for the view, throws an [RpcFormatError].
+ /// If there is an associated isolate, and there is no name for said isolate,
+ /// also throws an [RpcFormatError].
+ ///
+ /// All other cases return a [FlutterView] instance. The name of the
+ /// view may be null, but the id will always be set.
+ factory FlutterView._fromJson(Map<String, dynamic> json) {
+ final Map<String, dynamic> isolate = json['isolate'];
+ final String id = json['id'];
+ String name;
+ if (isolate != null) {
+ name = isolate['name'];
+ if (name == null) {
+ throw new RpcFormatError('Unable to find name for isolate "$isolate"');
+ }
+ }
+ if (id == null) {
+ throw new RpcFormatError(
+ 'Unable to find view name for the following JSON structure "$json"');
+ }
+ return new FlutterView._(name, id);
+ }
+
+ /// Determines the name of the isolate associated with this view. If there is
+ /// no associated isolate, this will be set to the view's ID.
+ final String _name;
+
+ /// The ID of the Flutter view.
+ final String _id;
+
+ /// The ID of the [FlutterView].
+ String get id => _id;
+
+ /// Returns the name of the [FlutterView].
+ ///
+ /// May be null if there is no associated isolate.
+ String get name => _name;
+}
diff --git a/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart b/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart
new file mode 100644
index 0000000..ce2d51d
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart
@@ -0,0 +1,348 @@
+// Copyright 2018 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 'dart:io';
+
+import 'package:meta/meta.dart';
+import 'package:process/process.dart';
+
+import 'common/logging.dart';
+import 'common/network.dart';
+import 'dart/dart_vm.dart';
+import 'runners/ssh_command_runner.dart';
+
+final String _ipv4Loopback = InternetAddress.LOOPBACK_IP_V4.address;
+
+final String _ipv6Loopback = InternetAddress.LOOPBACK_IP_V6.address;
+
+const ProcessManager _processManager = const LocalProcessManager();
+
+final Logger _log = new Logger('FuchsiaRemoteConnection');
+
+/// A function for forwarding ports on the local machine to a remote device.
+///
+/// Takes a remote `address`, the target device's port, and an optional
+/// `interface` and `configFile`. The config file is used primarily for the
+/// default SSH port forwarding configuration.
+typedef Future<PortForwarder> PortForwardingFunction(
+ String address, int remotePort,
+ [String interface, String configFile]);
+
+/// The function for forwarding the local machine's ports to a remote Fuchsia
+/// device.
+///
+/// Can be overwritten in the event that a different method is required.
+/// Defaults to using SSH port forwarding.
+PortForwardingFunction fuchsiaPortForwardingFunction = _SshPortForwarder.start;
+
+/// Sets [fuchsiaPortForwardingFunction] back to the default SSH port forwarding
+/// implementation.
+void restoreFuchsiaPortForwardingFunction() {
+ fuchsiaPortForwardingFunction = _SshPortForwarder.start;
+}
+
+/// Manages a remote connection to a Fuchsia Device.
+///
+/// Provides affordances to observe and connect to Flutter views, isolates, and
+/// perform actions on the Fuchsia device's various VM services.
+///
+/// Note that this class can be connected to several instances of the Fuchsia
+/// device's Dart VM at any given time.
+class FuchsiaRemoteConnection {
+ final List<PortForwarder> _forwardedVmServicePorts = <PortForwarder>[];
+ final SshCommandRunner _sshCommandRunner;
+ final bool _useIpV6Loopback;
+
+ /// VM service cache to avoid repeating handshakes across function
+ /// calls. Keys a forwarded port to a DartVm connection instance.
+ final Map<int, DartVm> _dartVmCache = <int, DartVm>{};
+
+ FuchsiaRemoteConnection._(this._useIpV6Loopback, this._sshCommandRunner);
+
+ /// Same as [FuchsiaRemoteConnection.connect] albeit with a provided
+ /// [SshCommandRunner] instance.
+ @visibleForTesting
+ static Future<FuchsiaRemoteConnection> connectWithSshCommandRunner(
+ SshCommandRunner commandRunner) async {
+ final FuchsiaRemoteConnection connection = new FuchsiaRemoteConnection._(
+ isIpV6Address(commandRunner.address), commandRunner);
+ await connection._forwardLocalPortsToDeviceServicePorts();
+ return connection;
+ }
+
+ /// Opens a connection to a Fuchsia device.
+ ///
+ /// Accepts an `address` to a Fuchsia device, and optionally a `sshConfigPath`
+ /// in order to open the associated ssh_config for port forwarding.
+ ///
+ /// Will throw an [ArgumentError] if `address` is malformed.
+ ///
+ /// Once this function is called, the instance of [FuchsiaRemoteConnection]
+ /// returned will keep all associated DartVM connections opened over the
+ /// lifetime of the object.
+ ///
+ /// At its current state Dart VM connections will not be added or removed over
+ /// the lifetime of this object.
+ ///
+ /// Throws an [ArgumentError] if the supplied `address` is not valid IPv6 or
+ /// IPv4.
+ ///
+ /// Note that if `address` is ipv6 link local (usually starts with fe80::),
+ /// then `interface` will probably need to be set in order to connect
+ /// successfully (that being the outgoing interface of your machine, not the
+ /// interface on the target machine).
+ static Future<FuchsiaRemoteConnection> connect(
+ String address, [
+ String interface = '',
+ String sshConfigPath,
+ ]) async {
+ return await FuchsiaRemoteConnection.connectWithSshCommandRunner(
+ new SshCommandRunner(
+ address: address,
+ interface: interface,
+ sshConfigPath: sshConfigPath,
+ ),
+ );
+ }
+
+ /// Closes all open connections.
+ ///
+ /// Any objects that this class returns (including any child objects from
+ /// those objects) will subsequently have its connection closed as well, so
+ /// behavior for them will be undefined.
+ Future<Null> stop() async {
+ for (PortForwarder fp in _forwardedVmServicePorts) {
+ // Closes VM service first to ensure that the connection is closed cleanly
+ // on the target before shutting down the forwarding itself.
+ final DartVm vmService = _dartVmCache[fp.port];
+ _dartVmCache[fp.port] = null;
+ await vmService?.stop();
+ await fp.stop();
+ }
+ _dartVmCache.clear();
+ _forwardedVmServicePorts.clear();
+ }
+
+ /// Returns a list of [FlutterView] objects.
+ ///
+ /// This is run across all connected DartVM connections that this class is
+ /// managing.
+ Future<List<FlutterView>> getFlutterViews() async {
+ final List<FlutterView> views = <FlutterView>[];
+ if (_forwardedVmServicePorts.isEmpty) {
+ return views;
+ }
+ for (PortForwarder fp in _forwardedVmServicePorts) {
+ final DartVm vmService = await _getDartVm(fp.port);
+ views.addAll(await vmService.getAllFlutterViews());
+ }
+ return new List<FlutterView>.unmodifiable(views);
+ }
+
+ Future<DartVm> _getDartVm(int port) async {
+ if (!_dartVmCache.containsKey(port)) {
+ // While the IPv4 loopback can be used for the initial port forwarding
+ // (see [PortForwarder.start]), the address is actually bound to the IPv6
+ // loopback device, so connecting to the IPv4 loopback would fail when the
+ // target address is IPv6 link-local.
+ final String addr = _useIpV6Loopback
+ ? 'http://\[$_ipv6Loopback\]:$port'
+ : 'http://$_ipv4Loopback:$port';
+ final Uri uri = Uri.parse(addr);
+ final DartVm dartVm = await DartVm.connect(uri);
+ _dartVmCache[port] = dartVm;
+ }
+ return _dartVmCache[port];
+ }
+
+ /// Forwards a series of local device ports to the remote device.
+ ///
+ /// When this function is run, all existing forwarded ports and connections
+ /// are reset by way of [stop].
+ Future<Null> _forwardLocalPortsToDeviceServicePorts() async {
+ await stop();
+ final List<int> servicePorts = await getDeviceServicePorts();
+ _forwardedVmServicePorts
+ .addAll(await Future.wait(servicePorts.map((int deviceServicePort) {
+ return fuchsiaPortForwardingFunction(
+ _sshCommandRunner.address,
+ deviceServicePort,
+ _sshCommandRunner.interface,
+ _sshCommandRunner.sshConfigPath);
+ })));
+ }
+
+ /// Gets the open Dart VM service ports on a remote Fuchsia device.
+ ///
+ /// The method attempts to get service ports through an SSH connection. Upon
+ /// successfully getting the VM service ports, returns them as a list of
+ /// integers. If an empty list is returned, then no Dart VM instances could be
+ /// found. An exception is thrown in the event of an actual error when
+ /// attempting to acquire the ports.
+ Future<List<int>> getDeviceServicePorts() async {
+ // TODO(awdavies): This is using a temporary workaround rather than a
+ // well-defined service, and will be deprecated in the near future.
+ final List<String> lsOutput =
+ await _sshCommandRunner.run('ls /tmp/dart.services');
+ final List<int> ports = <int>[];
+
+ // The output of lsOutput is a list of available ports as the Fuchsia dart
+ // service advertises. An example lsOutput would look like:
+ //
+ // [ '31782\n', '1234\n', '11967' ]
+ for (String s in lsOutput) {
+ final String trimmed = s.trim();
+ final int lastSpace = trimmed.lastIndexOf(' ');
+ final String lastWord = trimmed.substring(lastSpace + 1);
+ if ((lastWord != '.') && (lastWord != '..')) {
+ final int value = int.parse(lastWord, onError: (_) => null);
+ if (value != null) {
+ ports.add(value);
+ }
+ }
+ }
+ return ports;
+ }
+}
+
+/// Defines an interface for port forwarding.
+///
+/// When a port forwarder is initialized, it is intended to save a port through
+/// which a connection is persisted along the lifetime of this object.
+///
+/// To shut down a port forwarder you must call the [stop] function.
+abstract class PortForwarder {
+ /// Determines the port which is being forwarded from the local machine.
+ int get port;
+
+ /// The destination port on the other end of the port forwarding tunnel.
+ int get remotePort;
+
+ /// Shuts down and cleans up port forwarding.
+ Future<Null> stop();
+}
+
+/// Instances of this class represent a running SSH tunnel.
+///
+/// The SSH tunnel is from the host to a VM service running on a Fuchsia device.
+class _SshPortForwarder implements PortForwarder {
+ _SshPortForwarder._(
+ this._remoteAddress,
+ this._remotePort,
+ this._localSocket,
+ this._process,
+ this._interface,
+ this._sshConfigPath,
+ this._ipV6,
+ );
+
+ final String _remoteAddress;
+ final int _remotePort;
+ final ServerSocket _localSocket;
+ final Process _process;
+ final String _sshConfigPath;
+ final String _interface;
+ final bool _ipV6;
+
+ @override
+ int get port => _localSocket.port;
+
+ @override
+ int get remotePort => _remotePort;
+
+ /// Starts SSH forwarding through a subprocess, and returns an instance of
+ /// [_SshPortForwarder].
+ static Future<_SshPortForwarder> start(String address, int remotePort,
+ [String interface, String sshConfigPath]) async {
+ final bool isIpV6 = isIpV6Address(address);
+ final ServerSocket localSocket = await _createLocalSocket();
+ if (localSocket == null || localSocket.port == 0) {
+ _log.warning('_SshPortForwarder failed to find a local port for '
+ '$address:$remotePort');
+ return null;
+ }
+ // TODO(awdavies): The square-bracket enclosure for using the IPv6 loopback
+ // didn't appear to work, but when assigning to the IPv4 loopback device,
+ // netstat shows that the local port is actually being used on the IPv6
+ // loopback (::1). While this can be used for forwarding to the destination
+ // IPv6 interface, it cannot be used to connect to a websocket.
+ final String formattedForwardingUrl =
+ '${localSocket.port}:$_ipv4Loopback:$remotePort';
+ final List<String> command = <String>['ssh'];
+ if (isIpV6) {
+ command.add('-6');
+ }
+ if (sshConfigPath != null) {
+ command.addAll(<String>['-F', sshConfigPath]);
+ }
+ final String targetAddress =
+ isIpV6 && interface.isNotEmpty ? '$address%$interface' : address;
+ command.addAll(<String>[
+ '-nNT',
+ '-L',
+ formattedForwardingUrl,
+ targetAddress,
+ ]);
+ _log.fine("_SshPortForwarder running '${command.join(' ')}'");
+ final Process process = await _processManager.start(command);
+ process.exitCode.then((int c) {
+ _log.fine("'${command.join(' ')}' exited with exit code $c");
+ });
+ _log.fine(
+ 'Set up forwarding from ${localSocket.port} to $address port $remotePort');
+ return new _SshPortForwarder._(address, remotePort, localSocket, process,
+ interface, sshConfigPath, isIpV6);
+ }
+
+ /// Kills the SSH forwarding command, then to ensure no ports are forwarded,
+ /// runs the SSH 'cancel' command to shut down port forwarding completely.
+ @override
+ Future<Null> stop() async {
+ // Kill the original SSH process if it is still around.
+ _process.kill();
+ // Cancel the forwarding request. See [start] for commentary about why this
+ // uses the IPv4 loopback.
+ final String formattedForwardingUrl =
+ '${_localSocket.port}:$_ipv4Loopback:$_remotePort';
+ final List<String> command = <String>['ssh'];
+ final String targetAddress = _ipV6 && _interface.isNotEmpty
+ ? '$_remoteAddress%$_interface'
+ : _remoteAddress;
+ if (_sshConfigPath != null) {
+ command.addAll(<String>['-F', _sshConfigPath]);
+ }
+ command.addAll(<String>[
+ '-O',
+ 'cancel',
+ '-L',
+ formattedForwardingUrl,
+ targetAddress,
+ ]);
+ _log.fine(
+ 'Shutting down SSH forwarding with command: ${command.join(' ')}');
+ final ProcessResult result = await _processManager.run(command);
+ if (result.exitCode != 0) {
+ _log.warning(
+ 'Command failed:\nstdout: ${result.stdout}\nstderr: ${result.stderr}');
+ }
+ _localSocket.close();
+ }
+
+ /// Attempts to find an available port.
+ ///
+ /// If successful returns a valid [ServerSocket] (which must be disconnected
+ /// later).
+ static Future<ServerSocket> _createLocalSocket() async {
+ ServerSocket s;
+ try {
+ s = await ServerSocket.bind(_ipv4Loopback, 0);
+ } catch (e) {
+ // Failures are signaled by a return value of 0 from this function.
+ _log.warning('_createLocalSocket failed: $e');
+ return null;
+ }
+ return s;
+ }
+}
diff --git a/packages/fuchsia_remote_debug_protocol/lib/src/runners/ssh_command_runner.dart b/packages/fuchsia_remote_debug_protocol/lib/src/runners/ssh_command_runner.dart
new file mode 100644
index 0000000..d57518c
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/lib/src/runners/ssh_command_runner.dart
@@ -0,0 +1,107 @@
+// Copyright 2018 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 'dart:io' show ProcessResult;
+
+import 'package:meta/meta.dart';
+import 'package:process/process.dart';
+
+import '../common/logging.dart';
+import '../common/network.dart';
+
+/// An error raised when a command fails to run within the [SshCommandRunner].
+///
+/// This occurs for both connection failures, and for failure to
+/// run the command on the remote device. This error is raised when the
+/// subprocess running the SSH command returns a nonzero exit code.
+class SshCommandError extends Error {
+ /// Basic constructor outlining the reason for the SSH command failure through
+ /// the message string.
+ SshCommandError(this.message);
+
+ /// The reason for the command failure.
+ final String message;
+
+ @override
+ String toString() {
+ return '$SshCommandError: $message\n${super.stackTrace}';
+ }
+}
+
+/// Runs commands remotely on a Fuchsia device.
+///
+/// Requires a Fuchsia root and build type (to load the ssh config),
+/// and the address of the Fuchsia device.
+class SshCommandRunner {
+ /// Instantiates the command runner, pointing to an `address` as well as
+ /// an optional SSH config file path.
+ ///
+ /// If the SSH config path is supplied as an empty string, behavior is
+ /// undefined.
+ ///
+ /// [ArgumentError] is thrown in the event that `address` is neither valid
+ /// IPv4 nor IPv6. Note that when connecting to a link local address (fe80::
+ /// is usually at the start of the address), then an interface should be
+ /// supplied.
+ SshCommandRunner({
+ this.address,
+ this.interface = '',
+ this.sshConfigPath,
+ }) : _processManager = const LocalProcessManager() {
+ validateAddress(address);
+ }
+
+ /// Private constructor for dependency injection of the process manager.
+ @visibleForTesting
+ SshCommandRunner.withProcessManager(
+ this._processManager, {
+ this.address,
+ this.interface = '',
+ this.sshConfigPath,
+ }) {
+ validateAddress(address);
+ }
+
+ final Logger _log = new Logger('SshCommandRunner');
+
+ final ProcessManager _processManager;
+
+ /// The IPv4 address to access the Fuchsia machine over SSH.
+ final String address;
+
+ /// The path to the SSH config (optional).
+ final String sshConfigPath;
+
+ /// The name of the machine's network interface (for use with IPv6
+ /// connections. Ignored otherwise).
+ final String interface;
+
+ /// Runs a command on a Fuchsia device through an SSH tunnel.
+ ///
+ /// If the subprocess creating the SSH tunnel returns a nonzero exit status,
+ /// then an [SshCommandError] is raised.
+ Future<List<String>> run(String command) async {
+ final List<String> args = <String>['ssh'];
+ if (sshConfigPath != null) {
+ args.addAll(<String>['-F', sshConfigPath]);
+ }
+ if (isIpV6Address(address)) {
+ final String fullAddress =
+ interface.isEmpty ? address : '$address%$interface';
+ args.addAll(<String>['-6', fullAddress]);
+ } else {
+ args.add(address);
+ }
+ args.add(command);
+ _log.fine('Running command through SSH: ${args.join(' ')}');
+ final ProcessResult result = await _processManager.run(args);
+ if (result.exitCode != 0) {
+ throw new SshCommandError(
+ 'Command failed: $command\nstdout: ${result.stdout}\nstderr: ${result.stderr}');
+ }
+ _log.fine('SSH command stdout in brackets:[${result.stdout}]');
+ return result.stdout.split('\n');
+ }
+}
diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml
new file mode 100644
index 0000000..eb8f47f
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml
@@ -0,0 +1,68 @@
+name: fuchsia_remote_debug_protocol
+description: Provides an API to test/debug Flutter applications on remote Fuchsia devices and emulators.
+homepage: http://flutter.io
+author: Flutter Authors <flutter-dev@googlegroups.com>
+
+dependencies:
+ json_rpc_2: 2.0.7
+ process: 2.0.9
+ meta: 1.1.2
+ web_socket_channel: 1.0.7
+ flutter_test:
+ sdk: flutter
+
+ args: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ async: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ barback: 0.15.2+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ boolean_selector: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ charcode: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ cli_util: 0.1.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ collection: 1.14.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ convert: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ crypto: 2.0.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ csslib: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ file: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ glob: 1.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ html: 0.13.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ http: 0.11.3+16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ http_multi_server: 2.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ http_parser: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ intl: 0.15.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ io: 0.3.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ isolate: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ js: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ logging: 0.11.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ matcher: 0.12.1+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ mime: 0.9.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ multi_server_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ node_preamble: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ package_config: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ package_resolver: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ path: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ platform: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ plugin: 0.2.0+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ pool: 1.3.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ pub_semver: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ quiver: 0.28.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ shelf: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ shelf_packages_handler: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ shelf_static: 0.2.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ shelf_web_socket: 0.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ source_map_stack_trace: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ source_maps: 0.10.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ source_span: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ stack_trace: 1.9.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ stream_channel: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ string_scanner: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ term_glyph: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ typed_data: 1.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ utf: 0.9.0+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ vector_math: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ watcher: 0.9.7+7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+ yaml: 2.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+
+dev_dependencies:
+ mockito: 2.2.3
+ test: 0.12.32+2
+
+# PUBSPEC CHECKSUM: 97d6
diff --git a/packages/fuchsia_remote_debug_protocol/test/fuchsia_remote_connection_test.dart b/packages/fuchsia_remote_debug_protocol/test/fuchsia_remote_connection_test.dart
new file mode 100644
index 0000000..7d7bab6
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/test/fuchsia_remote_connection_test.dart
@@ -0,0 +1,150 @@
+// Copyright 2018 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:test/test.dart';
+import 'package:mockito/mockito.dart';
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+
+import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart';
+
+void main() {
+ group('FuchsiaRemoteConnection.connect', () {
+ MockSshCommandRunner mockRunner;
+
+ setUp(() {
+ mockRunner = new MockSshCommandRunner();
+ });
+
+ tearDown(() {
+ /// Most tests will mock out the port forwarding and connection
+ /// functions.
+ restoreFuchsiaPortForwardingFunction();
+ restoreVmServiceConnectionFunction();
+ });
+
+ test('end-to-end with three vm connections and flutter view query',
+ () async {
+ const String address = 'fe80::8eae:4cff:fef4:9247';
+ const String interface = 'eno1';
+ // Adds some extra junk to make sure the strings will be cleaned up.
+ when(mockRunner.run(typed(any)))
+ .thenReturn(<String>['123\n\n\n', '456 ', '789']);
+ when(mockRunner.address).thenReturn(address);
+ when(mockRunner.interface).thenReturn(interface);
+ int port = 0;
+ final List<MockPortForwarder> forwardedPorts = <MockPortForwarder>[];
+ Future<PortForwarder> mockPortForwardingFunction(
+ String address, int remotePort,
+ [String interface = '', String configFile]) {
+ return new Future<PortForwarder>(() {
+ final MockPortForwarder pf = new MockPortForwarder();
+ forwardedPorts.add(pf);
+ when(pf.port).thenReturn(port++);
+ when(pf.remotePort).thenReturn(remotePort);
+ return pf;
+ });
+ }
+
+ int flutterViewIndex = 0;
+ final List<Map<String, dynamic>> flutterViewCannedResponses =
+ <Map<String, dynamic>>[
+ <String, dynamic>{
+ 'views': <Map<String, dynamic>>[
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView0',
+ },
+ ],
+ },
+ <String, dynamic>{
+ 'views': <Map<String, dynamic>>[
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView1',
+ 'isolate': <String, dynamic>{
+ 'type': '@Isolate',
+ 'fixedId': 'true',
+ 'id': 'isolates/1',
+ 'name': 'file://flutterBinary1',
+ 'number': '1',
+ },
+ }
+ ],
+ },
+ <String, dynamic>{
+ 'views': <Map<String, dynamic>>[
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView2',
+ 'isolate': <String, dynamic>{
+ 'type': '@Isolate',
+ 'fixedId': 'true',
+ 'id': 'isolates/2',
+ 'name': 'file://flutterBinary2',
+ 'number': '2',
+ },
+ }
+ ],
+ },
+ ];
+
+ final List<MockPeer> mockPeerConnections = <MockPeer>[];
+ final List<Uri> uriConnections = <Uri>[];
+ Future<json_rpc.Peer> mockVmConnectionFunction(Uri uri) {
+ return new Future<json_rpc.Peer>(() async {
+ final MockPeer mp = new MockPeer();
+ mockPeerConnections.add(mp);
+ uriConnections.add(uri);
+ when(mp.sendRequest(typed<String>(any), typed<String>(any)))
+ .thenReturn(new Future<Map<String, dynamic>>(
+ () => flutterViewCannedResponses[flutterViewIndex++]));
+ return mp;
+ });
+ }
+
+ fuchsiaPortForwardingFunction = mockPortForwardingFunction;
+ fuchsiaVmServiceConnectionFunction = mockVmConnectionFunction;
+
+ final FuchsiaRemoteConnection connection =
+ await FuchsiaRemoteConnection.connectWithSshCommandRunner(mockRunner);
+
+ // [mockPortForwardingFunction] will have returned three different
+ // forwarded ports, incrementing the port each time by one. (Just a sanity
+ // check that the forwarding port was called).
+ expect(forwardedPorts.length, 3);
+ expect(forwardedPorts[0].remotePort, 123);
+ expect(forwardedPorts[1].remotePort, 456);
+ expect(forwardedPorts[2].remotePort, 789);
+ expect(forwardedPorts[0].port, 0);
+ expect(forwardedPorts[1].port, 1);
+ expect(forwardedPorts[2].port, 2);
+
+ final List<FlutterView> views = await connection.getFlutterViews();
+ expect(views, isNot(null));
+ expect(views.length, 3);
+ // Since name can be null, check for the ID on all of them.
+ expect(views[0].id, 'flutterView0');
+ expect(views[1].id, 'flutterView1');
+ expect(views[2].id, 'flutterView2');
+
+ expect(views[0].name, equals(null));
+ expect(views[1].name, 'file://flutterBinary1');
+ expect(views[2].name, 'file://flutterBinary2');
+
+ // Ensure the ports are all closed after stop was called.
+ await connection.stop();
+ verify(forwardedPorts[0].stop());
+ verify(forwardedPorts[1].stop());
+ verify(forwardedPorts[2].stop());
+ });
+ });
+}
+
+class MockSshCommandRunner extends Mock implements SshCommandRunner {}
+
+class MockPortForwarder extends Mock implements PortForwarder {}
+
+class MockPeer extends Mock implements json_rpc.Peer {}
diff --git a/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart b/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart
new file mode 100644
index 0000000..aec9690
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart
@@ -0,0 +1,228 @@
+// Copyright 2018 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:fuchsia_remote_debug_protocol/src/dart/dart_vm.dart';
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:mockito/mockito.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('DartVm.connect', () {
+ tearDown(() {
+ restoreVmServiceConnectionFunction();
+ });
+
+ test('null connector', () async {
+ Future<json_rpc.Peer> mockServiceFunction(Uri uri) {
+ return new Future<json_rpc.Peer>(() => null);
+ }
+
+ fuchsiaVmServiceConnectionFunction = mockServiceFunction;
+ expect(await DartVm.connect(Uri.parse('http://this.whatever/ws')),
+ equals(null));
+ });
+
+ test('disconnect closes peer', () async {
+ final MockPeer peer = new MockPeer();
+ Future<json_rpc.Peer> mockServiceFunction(Uri uri) {
+ return new Future<json_rpc.Peer>(() => peer);
+ }
+
+ fuchsiaVmServiceConnectionFunction = mockServiceFunction;
+ final DartVm vm =
+ await DartVm.connect(Uri.parse('http://this.whatever/ws'));
+ expect(vm, isNot(null));
+ await vm.stop();
+ verify(peer.close());
+ });
+ });
+
+ group('DartVm.getAllFlutterViews', () {
+ MockPeer mockPeer;
+
+ setUp(() {
+ mockPeer = new MockPeer();
+ });
+
+ tearDown(() {
+ restoreVmServiceConnectionFunction();
+ });
+
+ test('basic flutter view parsing', () async {
+ final Map<String, dynamic> flutterViewCannedResponses = <String, dynamic>{
+ 'views': <Map<String, dynamic>>[
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView0',
+ },
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView1',
+ 'isolate': <String, dynamic>{
+ 'type': '@Isolate',
+ 'fixedId': 'true',
+ 'id': 'isolates/1',
+ 'name': 'file://flutterBinary1',
+ 'number': '1',
+ },
+ },
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView2',
+ 'isolate': <String, dynamic>{
+ 'type': '@Isolate',
+ 'fixedId': 'true',
+ 'id': 'isolates/2',
+ 'name': 'file://flutterBinary2',
+ 'number': '2',
+ },
+ },
+ ],
+ };
+
+ Future<json_rpc.Peer> mockVmConnectionFunction(Uri uri) {
+ when(mockPeer.sendRequest(
+ typed<String>(any), typed<Map<String, dynamic>>(any)))
+ .thenReturn(new Future<Map<String, dynamic>>(
+ () => flutterViewCannedResponses));
+ return new Future<json_rpc.Peer>(() => mockPeer);
+ }
+
+ fuchsiaVmServiceConnectionFunction = mockVmConnectionFunction;
+ final DartVm vm =
+ await DartVm.connect(Uri.parse('http://whatever.com/ws'));
+ expect(vm, isNot(null));
+ final List<FlutterView> views = await vm.getAllFlutterViews();
+ expect(views.length, 3);
+ // Check ID's as they cannot be null.
+ expect(views[0].id, 'flutterView0');
+ expect(views[1].id, 'flutterView1');
+ expect(views[2].id, 'flutterView2');
+
+ // Verify names.
+ expect(views[0].name, equals(null));
+ expect(views[1].name, 'file://flutterBinary1');
+ expect(views[2].name, 'file://flutterBinary2');
+ });
+
+ test('invalid flutter view missing ID', () async {
+ final Map<String, dynamic> flutterViewCannedResponseMissingId =
+ <String, dynamic>{
+ 'views': <Map<String, dynamic>>[
+ // Valid flutter view.
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView1',
+ 'isolate': <String, dynamic>{
+ 'type': '@Isolate',
+ 'name': 'IsolateThing',
+ 'fixedId': 'true',
+ 'id': 'isolates/1',
+ 'number': '1',
+ },
+ },
+
+ // Missing ID.
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ },
+ ]
+ };
+
+ Future<json_rpc.Peer> mockVmConnectionFunction(Uri uri) {
+ when(mockPeer.sendRequest(
+ typed<String>(any), typed<Map<String, dynamic>>(any)))
+ .thenReturn(new Future<Map<String, dynamic>>(
+ () => flutterViewCannedResponseMissingId));
+ return new Future<json_rpc.Peer>(() => mockPeer);
+ }
+
+ fuchsiaVmServiceConnectionFunction = mockVmConnectionFunction;
+ final DartVm vm =
+ await DartVm.connect(Uri.parse('http://whatever.com/ws'));
+ expect(vm, isNot(null));
+ Future<Null> failingFunction() async {
+ await vm.getAllFlutterViews();
+ }
+
+ // Both views should be invalid as they were missing required fields.
+ expect(failingFunction, throwsA(const isInstanceOf<RpcFormatError>()));
+ });
+
+ test('invalid flutter view missing ID', () async {
+ final Map<String, dynamic> flutterViewCannedResponseMissingIsolateName =
+ <String, dynamic>{
+ 'views': <Map<String, dynamic>>[
+ // Missing isolate name.
+ <String, dynamic>{
+ 'type': 'FlutterView',
+ 'id': 'flutterView1',
+ 'isolate': <String, dynamic>{
+ 'type': '@Isolate',
+ 'fixedId': 'true',
+ 'id': 'isolates/1',
+ 'number': '1',
+ },
+ },
+ ],
+ };
+
+ Future<json_rpc.Peer> mockVmConnectionFunction(Uri uri) {
+ when(mockPeer.sendRequest(
+ typed<String>(any), typed<Map<String, dynamic>>(any)))
+ .thenReturn(new Future<Map<String, dynamic>>(
+ () => flutterViewCannedResponseMissingIsolateName));
+ return new Future<json_rpc.Peer>(() => mockPeer);
+ }
+
+ fuchsiaVmServiceConnectionFunction = mockVmConnectionFunction;
+ final DartVm vm =
+ await DartVm.connect(Uri.parse('http://whatever.com/ws'));
+ expect(vm, isNot(null));
+ Future<Null> failingFunction() async {
+ await vm.getAllFlutterViews();
+ }
+
+ // Both views should be invalid as they were missing required fields.
+ expect(failingFunction, throwsA(const isInstanceOf<RpcFormatError>()));
+ });
+ });
+
+ group('DartVm.invokeRpc', () {
+ MockPeer mockPeer;
+
+ setUp(() {
+ mockPeer = new MockPeer();
+ });
+
+ tearDown(() {
+ restoreVmServiceConnectionFunction();
+ });
+
+ test('verify timeout fires', () async {
+ const Duration timeoutTime = const Duration(milliseconds: 100);
+ Future<json_rpc.Peer> mockVmConnectionFunction(Uri uri) {
+ // Return a command that will never complete.
+ when(mockPeer.sendRequest(
+ typed<String>(any), typed<Map<String, dynamic>>(any)))
+ .thenReturn(new Completer<Map<String, dynamic>>().future);
+ return new Future<json_rpc.Peer>(() => mockPeer);
+ }
+
+ fuchsiaVmServiceConnectionFunction = mockVmConnectionFunction;
+ final DartVm vm =
+ await DartVm.connect(Uri.parse('http://whatever.com/ws'));
+ expect(vm, isNot(null));
+ Future<Null> failingFunction() async {
+ await vm.invokeRpc('somesillyfunction', timeout: timeoutTime);
+ }
+
+ expect(failingFunction, throwsA(const isInstanceOf<TimeoutException>()));
+ });
+ });
+}
+
+class MockPeer extends Mock implements json_rpc.Peer {}
diff --git a/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart b/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart
new file mode 100644
index 0000000..068ce16
--- /dev/null
+++ b/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart
@@ -0,0 +1,142 @@
+// Copyright 2018 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 'dart:io' show ProcessResult;
+
+import 'package:test/test.dart';
+import 'package:mockito/mockito.dart';
+import 'package:process/process.dart';
+import 'package:fuchsia_remote_debug_protocol/src/runners/ssh_command_runner.dart';
+
+void main() {
+ group('SshCommandRunner.constructors', () {
+ test('throws exception with invalid address', () async {
+ SshCommandRunner newCommandRunner() {
+ return new SshCommandRunner(address: 'sillyaddress.what');
+ }
+
+ expect(newCommandRunner, throwsArgumentError);
+ });
+
+ test('throws exception from injection constructor with invalid addr',
+ () async {
+ SshCommandRunner newCommandRunner() {
+ return new SshCommandRunner.withProcessManager(
+ const LocalProcessManager(),
+ address: '192.168.1.1.1');
+ }
+
+ expect(newCommandRunner, throwsArgumentError);
+ });
+ });
+
+ group('SshCommandRunner.run', () {
+ MockProcessManager mockProcessManager;
+ MockProcessResult mockProcessResult;
+ SshCommandRunner runner;
+
+ setUp(() {
+ mockProcessManager = new MockProcessManager();
+ mockProcessResult = new MockProcessResult();
+ when(mockProcessManager.run(typed(any))).thenReturn(mockProcessResult);
+ });
+
+ test('verify interface is appended to ipv6 address', () async {
+ const String ipV6Addr = 'fe80::8eae:4cff:fef4:9247';
+ const String interface = 'eno1';
+ runner = new SshCommandRunner.withProcessManager(
+ mockProcessManager,
+ address: ipV6Addr,
+ interface: interface,
+ sshConfigPath: '/whatever',
+ );
+ when<String>(mockProcessResult.stdout).thenReturn('somestuff');
+ when(mockProcessResult.exitCode).thenReturn(0);
+ await runner.run('ls /whatever');
+ final List<String> passedCommand =
+ verify(mockProcessManager.run(typed(captureAny))).captured.single;
+ expect(passedCommand, contains('$ipV6Addr%$interface'));
+ });
+
+ test('verify no percentage symbol is added when no ipv6 interface',
+ () async {
+ const String ipV6Addr = 'fe80::8eae:4cff:fef4:9247';
+ runner = new SshCommandRunner.withProcessManager(
+ mockProcessManager,
+ address: ipV6Addr,
+ );
+ when<String>(mockProcessResult.stdout).thenReturn('somestuff');
+ when(mockProcessResult.exitCode).thenReturn(0);
+ await runner.run('ls /whatever');
+ final List<String> passedCommand =
+ verify(mockProcessManager.run(typed(captureAny))).captured.single;
+ expect(passedCommand, contains(ipV6Addr));
+ });
+
+ test('verify commands are split into multiple lines', () async {
+ const String addr = '192.168.1.1';
+ runner = new SshCommandRunner.withProcessManager(mockProcessManager,
+ address: addr);
+ when<String>(mockProcessResult.stdout).thenReturn('''this
+ has
+ four
+ lines''');
+ when(mockProcessResult.exitCode).thenReturn(0);
+ final List<String> result = await runner.run('oihaw');
+ expect(result, hasLength(4));
+ });
+
+ test('verify exception on nonzero process result exit code', () async {
+ const String addr = '192.168.1.1';
+ runner = new SshCommandRunner.withProcessManager(mockProcessManager,
+ address: addr);
+ when<String>(mockProcessResult.stdout).thenReturn('whatever');
+ when(mockProcessResult.exitCode).thenReturn(1);
+ Future<Null> failingFunction() async {
+ await runner.run('oihaw');
+ }
+
+ expect(failingFunction, throwsA(const isInstanceOf<SshCommandError>()));
+ });
+
+ test('verify correct args with config', () async {
+ const String addr = 'fe80::8eae:4cff:fef4:9247';
+ const String config = '/this/that/this/and/uh';
+ runner = new SshCommandRunner.withProcessManager(
+ mockProcessManager,
+ address: addr,
+ sshConfigPath: config,
+ );
+ when<String>(mockProcessResult.stdout).thenReturn('somestuff');
+ when(mockProcessResult.exitCode).thenReturn(0);
+ await runner.run('ls /whatever');
+ final List<String> passedCommand =
+ verify(mockProcessManager.run(typed(captureAny))).captured.single;
+ expect(passedCommand, contains('-F'));
+ final int indexOfFlag = passedCommand.indexOf('-F');
+ final String passedConfig = passedCommand[indexOfFlag + 1];
+ expect(passedConfig, config);
+ });
+
+ test('verify config is excluded correctly', () async {
+ const String addr = 'fe80::8eae:4cff:fef4:9247';
+ runner = new SshCommandRunner.withProcessManager(
+ mockProcessManager,
+ address: addr,
+ );
+ when<String>(mockProcessResult.stdout).thenReturn('somestuff');
+ when(mockProcessResult.exitCode).thenReturn(0);
+ await runner.run('ls /whatever');
+ final List<String> passedCommand =
+ verify(mockProcessManager.run(typed(captureAny))).captured.single;
+ final int indexOfFlag = passedCommand.indexOf('-F');
+ expect(indexOfFlag, equals(-1));
+ });
+ });
+}
+
+class MockProcessManager extends Mock implements ProcessManager {}
+
+class MockProcessResult extends Mock implements ProcessResult {}