Register hotRestart service in flutter_tools. (#26669)

* Register hot restart service in flutter_tools.
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 82f5a0f..d5928e3 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -68,7 +68,11 @@
   /// expressions requested during debugging of the application.
   /// This ensures that the reload process follows the normal orchestration of
   /// the Flutter Tools and not just the VM internal service.
-  Future<void> _connect({ReloadSources reloadSources, CompileExpression compileExpression}) async {
+  Future<void> _connect({
+    ReloadSources reloadSources,
+    Restart restart,
+    CompileExpression compileExpression,
+  }) async {
     if (vmServices != null)
       return;
     final List<VMService> localVmServices = List<VMService>(observatoryUris.length);
@@ -76,6 +80,7 @@
       printTrace('Connecting to service protocol: ${observatoryUris[i]}');
       localVmServices[i] = await VMService.connect(observatoryUris[i],
           reloadSources: reloadSources,
+          restart: restart,
           compileExpression: compileExpression);
       printTrace('Successfully connected to service protocol: ${observatoryUris[i]}');
     }
@@ -677,14 +682,21 @@
 
   /// If the [reloadSources] parameter is not null the 'reloadSources' service
   /// will be registered
-  Future<void> connectToServiceProtocol({ReloadSources reloadSources, CompileExpression compileExpression}) async {
+  Future<void> connectToServiceProtocol({
+    ReloadSources reloadSources,
+    Restart restart,
+    CompileExpression compileExpression,
+  }) async {
     if (!debuggingOptions.debuggingEnabled)
       return Future<void>.error('Error the service protocol is not enabled.');
 
     bool viewFound = false;
     for (FlutterDevice device in flutterDevices) {
-      await device._connect(reloadSources: reloadSources,
-          compileExpression: compileExpression);
+      await device._connect(
+        reloadSources: reloadSources,
+        restart: restart,
+        compileExpression: compileExpression,
+      );
       await device.getVMs();
       await device.refreshViews();
       if (device.views.isEmpty)
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 08b93b4..3127b37 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -143,6 +143,17 @@
     }
   }
 
+  Future<void> _restartService({ bool pause = false }) async {
+    final OperationResult result =
+      await restart(fullRestart: true, pauseAfterRestart: pause);
+    if (!result.isOk) {
+      throw rpc.RpcException(
+        rpc_error_code.INTERNAL_ERROR,
+        'Unable to restart',
+      );
+    }
+  }
+
   Future<String> _compileExpressionService(String isolateId, String expression,
       List<String> definitions, List<String> typeDefinitions,
       String libraryUri, String klass, bool isStatic,
@@ -168,6 +179,7 @@
     try {
       await connectToServiceProtocol(
         reloadSources: _reloadSourcesService,
+        restart: _restartService,
         compileExpression: _compileExpressionService,
       );
     } catch (error) {
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index 83f837a..48a8c8a 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -43,6 +43,8 @@
   bool pause,
 });
 
+typedef Restart = Future<void> Function({ bool pause });
+
 typedef CompileExpression = Future<String> Function(
   String isolateId,
   String expression,
@@ -111,6 +113,7 @@
     this.wsAddress,
     this._requestTimeout,
     ReloadSources reloadSources,
+    Restart restart,
     CompileExpression compileExpression,
   ) {
     _vm = VM._empty(this);
@@ -148,7 +151,33 @@
       // have no effect
       _peer.sendNotification('_registerService', <String, String>{
         'service': 'reloadSources',
-        'alias': 'Flutter Tools'
+        'alias': 'Flutter Tools',
+      });
+    }
+
+    if (restart != null) {
+      _peer.registerMethod('hotRestart', (rpc.Parameters params) async {
+        final bool pause = params.asMap['pause'] ?? false;
+
+        if (pause is! bool)
+          throw rpc.RpcException.invalidParams('Invalid \'pause\': $pause');
+
+        try {
+          await restart(pause: pause);
+          return <String, String>{'type': 'Success'};
+        } on rpc.RpcException {
+          rethrow;
+        } catch (e, st) {
+          throw rpc.RpcException(rpc_error_code.SERVER_ERROR,
+              'Error during Hot Restart: $e\n$st');
+        }
+      });
+
+      // If the Flutter Engine doesn't support service registration this will
+      // have no effect
+      _peer.sendNotification('_registerService', <String, String>{
+        'service': 'hotRestart',
+        'alias': 'Flutter Tools',
       });
     }
 
@@ -231,12 +260,13 @@
     Uri httpUri, {
     Duration requestTimeout = kDefaultRequestTimeout,
     ReloadSources reloadSources,
+    Restart restart,
     CompileExpression compileExpression,
   }) async {
     final Uri wsUri = httpUri.replace(scheme: 'ws', path: fs.path.join(httpUri.path, 'ws'));
     final StreamChannel<String> channel = await _openChannel(wsUri);
     final rpc.Peer peer = rpc.Peer.withoutJson(jsonDocument.bind(channel));
-    final VMService service = VMService(peer, httpUri, wsUri, requestTimeout, reloadSources, compileExpression);
+    final VMService service = VMService(peer, httpUri, wsUri, requestTimeout, reloadSources, restart, compileExpression);
     // This call is to ensure we are able to establish a connection instead of
     // keeping on trucking and failing farther down the process.
     await service._sendRequest('getVersion', const <String, dynamic>{});
diff --git a/packages/flutter_tools/test/vmservice_test.dart b/packages/flutter_tools/test/vmservice_test.dart
index 6f056ce..0421764 100644
--- a/packages/flutter_tools/test/vmservice_test.dart
+++ b/packages/flutter_tools/test/vmservice_test.dart
@@ -167,7 +167,7 @@
         bool done = false;
         final MockPeer mockPeer = MockPeer();
         expect(mockPeer.returnedFromSendRequest, 0);
-        final VMService vmService = VMService(mockPeer, null, null, const Duration(seconds: 1), null, null);
+        final VMService vmService = VMService(mockPeer, null, null, const Duration(seconds: 1), null, null, null);
         vmService.getVM().then((void value) { done = true; });
         expect(done, isFalse);
         expect(mockPeer.returnedFromSendRequest, 0);