[fuchsia_reload] More information from --list (#9503)

diff --git a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
index 3dcbf92..2d6ac06 100644
--- a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
+++ b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:collection';
 import 'dart:math';
 
 import '../base/common.dart';
@@ -93,7 +94,7 @@
       printTrace('Fuchsia service port: $port');
 
     if (_list) {
-      await _listViews(servicePorts);
+      await _listVMs(servicePorts);
       return;
     }
 
@@ -125,12 +126,23 @@
     await hotRunner.attach(observatoryUris, isolateFilter: isolateName);
   }
 
-  Future<List<FlutterView>> _getViews(List<int> ports) async {
-    final List<FlutterView> views = <FlutterView>[];
-    for (int port in ports) {
+  // A cache of VMService connections.
+  HashMap<int, VMService> _vmServiceCache = new HashMap<int, VMService>();
+
+  VMService _getVMService(int port) {
+    if (!_vmServiceCache.containsKey(port)) {
       final String addr = 'http://$_address:$port';
       final Uri uri = Uri.parse(addr);
       final VMService vmService = VMService.connect(uri);
+      _vmServiceCache[port] = vmService;
+    }
+    return _vmServiceCache[port];
+  }
+
+  Future<List<FlutterView>> _getViews(List<int> ports) async {
+    final List<FlutterView> views = <FlutterView>[];
+    for (int port in ports) {
+      final VMService vmService = _getVMService(port);
       await vmService.getVM();
       await vmService.waitForViews();
       views.addAll(vmService.vm.views);
@@ -150,31 +162,89 @@
     return result;
   }
 
-  Future<Null> _listViews(List<int> ports) async {
-    const String bold = '\u001B[0;1m';
-    const String reset = '\u001B[0m';
-    for (FlutterView v in await _getViews(ports)) {
-      final Uri addr = v.owner.vmService.httpAddress;
-      final Isolate i = v.uiIsolate;
-      final String name = i.name;
-      final String shortName = name.substring(0, name.indexOf('\$'));
-      final String main = '\$main-';
-      final String number = name.substring(name.indexOf(main) + main.length);
-      final String newUsed = getSizeAsMB(i.newSpace.used);
-      final String newCap = getSizeAsMB(i.newSpace.capacity);
-      final String newFreq = '${i.newSpace.avgCollectionTime.inMilliseconds}ms';
-      final String newPer = '${i.newSpace.avgCollectionPeriod.inSeconds}s';
-      final String oldUsed = getSizeAsMB(i.oldSpace.used);
-      final String oldCap = getSizeAsMB(i.oldSpace.capacity);
-      final String oldFreq = '${i.oldSpace.avgCollectionTime.inMilliseconds}ms';
-      final String oldPer = '${i.oldSpace.avgCollectionPeriod.inSeconds}s';
-      printStatus(
-        '$bold$shortName$reset\n'
-        '\tIsolate number: $number\n'
-        '\tObservatory: $addr\n'
-        '\tNew gen: $newUsed used of $newCap, GC: $newFreq every $newPer\n'
-        '\tOld gen: $oldUsed used of $oldCap, GC: $oldFreq every $oldPer\n'
-      );
+  static const String _bold = '\u001B[0;1m';
+  static const String _reset = '\u001B[0m';
+
+  String _vmServiceToString(VMService vmService, {int tabDepth: 0}) {
+    final Uri addr = vmService.httpAddress;
+    final int numIsolates = vmService.vm.isolates.length;
+    final String maxRSS = getSizeAsMB(vmService.vm.maxRSS);
+    final String heapSize = getSizeAsMB(vmService.vm.heapAllocatedMemoryUsage);
+    int totalNewUsed = 0;
+    int totalNewCap = 0;
+    int totalOldUsed = 0;
+    int totalOldCap = 0;
+    int totalExternal = 0;
+    for (Isolate i in vmService.vm.isolates) {
+      totalNewUsed += i.newSpace.used;
+      totalNewCap += i.newSpace.capacity;
+      totalOldUsed += i.oldSpace.used;
+      totalOldCap += i.oldSpace.capacity;
+      totalExternal += i.newSpace.external;
+      totalExternal += i.oldSpace.external;
+    }
+    final String newUsed = getSizeAsMB(totalNewUsed);
+    final String newCap = getSizeAsMB(totalNewCap);
+    final String oldUsed = getSizeAsMB(totalOldUsed);
+    final String oldCap = getSizeAsMB(totalOldCap);
+    final String external = getSizeAsMB(totalExternal);
+    final String tabs = '\t' * tabDepth;
+    final String extraTabs = '\t' * (tabDepth + 1);
+    final StringBuffer stringBuffer = new StringBuffer(
+      '$tabs${_bold}VM at $addr$_reset\n'
+      '${extraTabs}RSS: $maxRSS\n'
+      '${extraTabs}Native allocations: $heapSize\n'
+      '${extraTabs}New Spaces: $newUsed of $newCap\n'
+      '${extraTabs}Old Spaces: $oldUsed of $oldCap\n'
+      '${extraTabs}External: $external\n'
+      '${extraTabs}Isolates: $numIsolates\n'
+    );
+    for (Isolate isolate in vmService.vm.isolates) {
+      stringBuffer.write(_isolateToString(isolate, tabDepth: tabDepth + 1));
+    }
+    return stringBuffer.toString();
+  }
+
+  String _isolateToString(Isolate isolate, {int tabDepth: 0}) {
+    final Uri vmServiceAddr = isolate.owner.vmService.httpAddress;
+    final String name = isolate.name;
+    final String shortName = name.substring(0, name.indexOf('\$'));
+    final String main = '\$main-';
+    final String number = name.substring(name.indexOf(main) + main.length);
+
+    // The Observatory requires somewhat non-standard URIs that the Uri class
+    // can't build for us, so instead we build them by hand.
+    final String isolateIdQuery = "?isolateId=isolates%2F$number";
+    final String isolateAddr = "$vmServiceAddr/#/inspect$isolateIdQuery";
+    final String debuggerAddr = "$vmServiceAddr/#/debugger$isolateIdQuery";
+
+    final String newUsed = getSizeAsMB(isolate.newSpace.used);
+    final String newCap = getSizeAsMB(isolate.newSpace.capacity);
+    final String newFreq = '${isolate.newSpace.avgCollectionTime.inMilliseconds}ms';
+    final String newPer = '${isolate.newSpace.avgCollectionPeriod.inSeconds}s';
+    final String oldUsed = getSizeAsMB(isolate.oldSpace.used);
+    final String oldCap = getSizeAsMB(isolate.oldSpace.capacity);
+    final String oldFreq = '${isolate.oldSpace.avgCollectionTime.inMilliseconds}ms';
+    final String oldPer = '${isolate.oldSpace.avgCollectionPeriod.inSeconds}s';
+    final String external = getSizeAsMB(isolate.newSpace.external + isolate.oldSpace.external);
+    final String tabs = '\t' * tabDepth;
+    final String extraTabs = '\t' * (tabDepth + 1);
+    return
+      '$tabs$_bold$shortName$_reset\n'
+      '${extraTabs}Isolate number: $number\n'
+      '${extraTabs}Observatory: $isolateAddr\n'
+      '${extraTabs}Debugger: $debuggerAddr\n'
+      '${extraTabs}New gen: $newUsed used of $newCap, GC: $newFreq every $newPer\n'
+      '${extraTabs}Old gen: $oldUsed used of $oldCap, GC: $oldFreq every $oldPer\n'
+      '${extraTabs}External: $external\n';
+  }
+
+  Future<Null> _listVMs(List<int> ports) async {
+    for (int port in ports) {
+      final VMService vmService = _getVMService(port);
+      await vmService.getVM();
+      await vmService.waitForViews();
+      printStatus(_vmServiceToString(vmService));
     }
   }
 
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index 332f352..e8447c2 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -512,6 +512,10 @@
 
     // TODO(johnmccutchan): Extract any properties we care about here.
     _pid = map['pid'];
+    if (map['_heapAllocatedMemoryUsage'] != null) {
+      _heapAllocatedMemoryUsage = map['_heapAllocatedMemoryUsage'];
+    }
+    _maxRSS = map['_maxRSS'];
 
     // Remove any isolates which are now dead from the isolate cache.
     _removeDeadIsolates(map['isolates']);
@@ -528,9 +532,18 @@
 
   /// The pid of the VM's process.
   int _pid;
-
   int get pid => _pid;
 
+  /// The number of bytes allocated (e.g. by malloc) in the native heap.
+  int _heapAllocatedMemoryUsage;
+  int get heapAllocatedMemoryUsage {
+    return _heapAllocatedMemoryUsage == null ? 0 : _heapAllocatedMemoryUsage;
+  }
+
+  /// The peak resident set size for the process.
+  int _maxRSS;
+  int get maxRSS => _maxRSS == null ? 0 : _maxRSS;
+
   int _compareIsolates(Isolate a, Isolate b) {
     final DateTime aStart = a.startTime;
     final DateTime bStart = b.startTime;