// Copyright 2014 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:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:meta/meta.dart';
import 'package:pool/pool.dart';

import 'base/async_guard.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/logger.dart';
import 'base/platform.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'bundle.dart';
import 'compile.dart';
import 'convert.dart';
import 'dart/package_map.dart';
import 'devfs.dart';
import 'device.dart';
import 'globals.dart' as globals;
import 'reporting/reporting.dart';
import 'resident_runner.dart';
import 'vmservice.dart';

ProjectFileInvalidator get projectFileInvalidator => context.get<ProjectFileInvalidator>() ?? _defaultInvalidator;
final ProjectFileInvalidator _defaultInvalidator = ProjectFileInvalidator(
  fileSystem: globals.fs,
  platform: globals.platform,
  logger: globals.logger,
);

HotRunnerConfig get hotRunnerConfig => context.get<HotRunnerConfig>();

class HotRunnerConfig {
  /// Should the hot runner assume that the minimal Dart dependencies do not change?
  bool stableDartDependencies = false;

  /// Whether the hot runner should scan for modified files asynchronously.
  bool asyncScanning = false;

  /// A hook for implementations to perform any necessary initialization prior
  /// to a hot restart. Should return true if the hot restart should continue.
  Future<bool> setupHotRestart() async {
    return true;
  }
  /// A hook for implementations to perform any necessary operations right
  /// before the runner is about to be shut down.
  Future<void> runPreShutdownOperations() async {
    return;
  }
}

const bool kHotReloadDefault = true;

class DeviceReloadReport {
  DeviceReloadReport(this.device, this.reports);

  FlutterDevice device;
  List<vm_service.ReloadReport> reports; // List has one report per Flutter view.
}

// TODO(mklim): Test this, flutter/flutter#23031.
class HotRunner extends ResidentRunner {
  HotRunner(
    List<FlutterDevice> devices, {
    String target,
    DebuggingOptions debuggingOptions,
    this.benchmarkMode = false,
    this.applicationBinary,
    this.hostIsIde = false,
    String projectRootPath,
    String packagesFilePath,
    String dillOutputPath,
    bool stayResident = true,
    bool ipv6 = false,
  }) : super(devices,
             target: target,
             debuggingOptions: debuggingOptions,
             projectRootPath: projectRootPath,
             packagesFilePath: packagesFilePath,
             stayResident: stayResident,
             hotMode: true,
             dillOutputPath: dillOutputPath,
             ipv6: ipv6);

  final bool benchmarkMode;
  final File applicationBinary;
  final bool hostIsIde;
  bool _didAttach = false;

  final Map<String, List<int>> benchmarkData = <String, List<int>>{};

  DateTime firstBuildTime;
  bool _shouldResetAssetDirectory = true;

  void _addBenchmarkData(String name, int value) {
    benchmarkData[name] ??= <int>[];
    benchmarkData[name].add(value);
  }

  Future<void> _reloadSourcesService(
    String isolateId, {
    bool force = false,
    bool pause = false,
  }) async {
    // TODO(cbernaschina): check that isolateId is the id of the UI isolate.
    final OperationResult result = await restart(pause: pause);
    if (!result.isOk) {
      throw vm_service.RPCError(
        'Unable to reload sources',
        RPCErrorCodes.kInternalError,
        '',
      );
    }
  }

  Future<void> _restartService({ bool pause = false }) async {
    final OperationResult result =
      await restart(fullRestart: true, pause: pause);
    if (!result.isOk) {
      throw vm_service.RPCError(
        'Unable to restart',
        RPCErrorCodes.kInternalError,
        '',
      );
    }
  }

  Future<String> _compileExpressionService(
    String isolateId,
    String expression,
    List<String> definitions,
    List<String> typeDefinitions,
    String libraryUri,
    String klass,
    bool isStatic,
  ) async {
    for (final FlutterDevice device in flutterDevices) {
      if (device.generator != null) {
        final CompilerOutput compilerOutput =
            await device.generator.compileExpression(expression, definitions,
                typeDefinitions, libraryUri, klass, isStatic);
        if (compilerOutput != null && compilerOutput.outputFilename != null) {
          return base64.encode(globals.fs.file(compilerOutput.outputFilename).readAsBytesSync());
        }
      }
    }
    throw 'Failed to compile $expression';
  }

  @override
  Future<OperationResult> reloadMethod({ String libraryId, String classId }) async {
    final Stopwatch stopwatch = Stopwatch()..start();
    final UpdateFSReport results = UpdateFSReport(success: true);
    final List<Uri> invalidated =  <Uri>[Uri.parse(libraryId)];
    final PackageConfig packageConfig = await loadPackageConfigWithLogging(
      globals.fs.file(globalPackagesPath),
      logger: globals.logger,
    );
    for (final FlutterDevice device in flutterDevices) {
      results.incorporateResults(await device.updateDevFS(
        mainUri: globals.fs.file(mainPath).absolute.uri,
        target: target,
        bundle: assetBundle,
        firstBuildTime: firstBuildTime,
        bundleFirstUpload: false,
        bundleDirty: false,
        fullRestart: false,
        projectRootPath: projectRootPath,
        pathToReload: getReloadPath(fullRestart: false),
        invalidatedFiles: invalidated,
        packageConfig: packageConfig,
        dillOutputPath: dillOutputPath,
      ));
    }
    if (!results.success) {
      return OperationResult(1, 'Failed to compile');
    }
    try {
      final String entryPath = globals.fs.path.relative(
        getReloadPath(fullRestart: false),
        from: projectRootPath,
      );
      for (final FlutterDevice device in flutterDevices) {
        final List<Future<vm_service.ReloadReport>> reportFutures = await device.reloadSources(
          entryPath, pause: false,
        );
        final List<vm_service.ReloadReport> reports = await Future.wait(reportFutures);
        final vm_service.ReloadReport firstReport = reports.first;
        await device.updateReloadStatus(validateReloadReport(firstReport.json, printErrors: false));
      }
    } on Exception catch (error) {
      return OperationResult(1, error.toString());
    }

    for (final FlutterDevice device in flutterDevices) {
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      for (final FlutterView view in views) {
        await device.vmService.flutterFastReassemble(
          classId,
          isolateId: view.uiIsolate.id,
        );
      }
    }

    globals.printStatus('reloadMethod took ${stopwatch.elapsedMilliseconds}');
    globals.flutterUsage.sendTiming('hot', 'ui', stopwatch.elapsed);
    return OperationResult.ok;
  }

  // Returns the exit code of the flutter tool process, like [run].
  @override
  Future<int> attach({
    Completer<DebugConnectionInfo> connectionInfoCompleter,
    Completer<void> appStartedCompleter,
  }) async {
    _didAttach = true;
    try {
      await connectToServiceProtocol(
        reloadSources: _reloadSourcesService,
        restart: _restartService,
        compileExpression: _compileExpressionService,
        reloadMethod: reloadMethod,
        getSkSLMethod: writeSkSL,
      );
    // Catches all exceptions, non-Exception objects are rethrown.
    } catch (error) { // ignore: avoid_catches_without_on_clauses
      if (error is! Exception && error is! String) {
        rethrow;
      }
      globals.printError('Error connecting to the service protocol: $error');
      // https://github.com/flutter/flutter/issues/33050
      // TODO(blasten): Remove this check once
      // https://issuetracker.google.com/issues/132325318 has been fixed.
      if (await hasDeviceRunningAndroidQ(flutterDevices) &&
          error.toString().contains(kAndroidQHttpConnectionClosedExp)) {
        globals.printStatus(
          '🔨 If you are using an emulator running Android Q Beta, '
          'consider using an emulator running API level 29 or lower.',
        );
        globals.printStatus(
          'Learn more about the status of this issue on '
          'https://issuetracker.google.com/issues/132325318.',
        );
      }
      return 2;
    }

    for (final FlutterDevice device in flutterDevices) {
      await device.initLogReader();
    }
    try {
      final List<Uri> baseUris = await _initDevFS();
      if (connectionInfoCompleter != null) {
        // Only handle one debugger connection.
        connectionInfoCompleter.complete(
          DebugConnectionInfo(
            httpUri: flutterDevices.first.vmService.httpAddress,
            wsUri: flutterDevices.first.vmService.wsAddress,
            baseUri: baseUris.first.toString(),
          ),
        );
      }
    } on Exception catch (error) {
      globals.printError('Error initializing DevFS: $error');
      return 3;
    }
    final Stopwatch initialUpdateDevFSsTimer = Stopwatch()..start();
    final UpdateFSReport devfsResult = await _updateDevFS(fullRestart: true);
    _addBenchmarkData(
      'hotReloadInitialDevFSSyncMilliseconds',
      initialUpdateDevFSsTimer.elapsed.inMilliseconds,
    );
    if (!devfsResult.success) {
      return 3;
    }

    for (final FlutterDevice device in flutterDevices) {
      // VM must have accepted the kernel binary, there will be no reload
      // report, so we let incremental compiler know that source code was accepted.
      if (device.generator != null) {
        device.generator.accept();
      }
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      for (final FlutterView view in views) {
        globals.printTrace('Connected to $view.');
      }
    }

    // In fast-start mode, apps are initialized from a placeholder splashscreen
    // app. We must do a restart here to load the program and assets for the
    // real app.
    if (debuggingOptions.fastStart) {
      await restart(
        fullRestart: true,
        benchmarkMode: !debuggingOptions.startPaused,
        reason: 'restart',
        silent: true,
      );
    }

    appStartedCompleter?.complete();

    if (benchmarkMode) {
      // We are running in benchmark mode.
      globals.printStatus('Running in benchmark mode.');
      // Measure time to perform a hot restart.
      globals.printStatus('Benchmarking hot restart');
      await restart(fullRestart: true, benchmarkMode: true);
      // Wait for notifications to finish. attempt to work around
      // timing issue caused by sentinel.
      await Future<void>.delayed(const Duration(seconds: 1));
      globals.printStatus('Benchmarking hot reload');
      // Measure time to perform a hot reload.
      await restart(fullRestart: false);
      if (stayResident) {
        await waitForAppToFinish();
      } else {
        globals.printStatus('Benchmark completed. Exiting application.');
        await _cleanupDevFS();
        await stopEchoingDeviceLog();
        await exitApp();
      }
      final File benchmarkOutput = globals.fs.file('hot_benchmark.json');
      benchmarkOutput.writeAsStringSync(toPrettyJson(benchmarkData));
      return 0;
    }
    writeVmserviceFile();

    int result = 0;
    if (stayResident) {
      result = await waitForAppToFinish();
    }
    await cleanupAtFinish();
    return result;
  }

  @override
  Future<int> run({
    Completer<DebugConnectionInfo> connectionInfoCompleter,
    Completer<void> appStartedCompleter,
    String route,
  }) async {
    if (!globals.fs.isFileSync(mainPath)) {
      String message = 'Tried to run $mainPath, but that file does not exist.';
      if (target == null) {
        message += '\nConsider using the -t option to specify the Dart file to start.';
      }
      globals.printError(message);
      return 1;
    }

    firstBuildTime = DateTime.now();

    final List<Future<bool>> startupTasks = <Future<bool>>[];
    final PackageConfig packageConfig = await loadPackageConfigWithLogging(
      globals.fs.file(globalPackagesPath),
      logger: globals.logger,
    );
    for (final FlutterDevice device in flutterDevices) {
      // Here we initialize the frontend_server concurrently with the platform
      // build, reducing overall initialization time. This is safe because the first
      // invocation of the frontend server produces a full dill file that the
      // subsequent invocation in devfs will not overwrite.
      await runSourceGenerators();
      if (device.generator != null) {
        startupTasks.add(
          device.generator.recompile(
            globals.fs.file(mainPath).uri,
            <Uri>[],
            // When running without a provided applicationBinary, the tool will
            // simultaneously run the initial frontend_server compilation and
            // the native build step. If there is a Dart compilation error, it
            // should only be displayed once.
            suppressErrors: applicationBinary == null,
            outputPath: dillOutputPath ??
              getDefaultApplicationKernelPath(trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation),
            packageConfig: packageConfig,
          ).then((CompilerOutput output) => output?.errorCount == 0)
        );
      }
      startupTasks.add(device.runHot(
        hotRunner: this,
        route: route,
      ).then((int result) => result == 0));
    }
    try {
      final List<bool> results = await Future.wait(startupTasks);
      if (!results.every((bool passed) => passed)) {
        return 1;
      }
    } on Exception catch (err) {
      globals.printError(err.toString());
      return 1;
    }

    return attach(
      connectionInfoCompleter: connectionInfoCompleter,
      appStartedCompleter: appStartedCompleter,
    );
  }

  Future<List<Uri>> _initDevFS() async {
    final String fsName = globals.fs.path.basename(projectRootPath);
    return <Uri>[
      for (final FlutterDevice device in flutterDevices)
        await device.setupDevFS(
          fsName,
          globals.fs.directory(projectRootPath),
          packagesFilePath: packagesFilePath,
        ),
    ];
  }

  Future<UpdateFSReport> _updateDevFS({ bool fullRestart = false }) async {
    final bool isFirstUpload = !assetBundle.wasBuiltOnce();
    final bool rebuildBundle = assetBundle.needsBuild();
    if (rebuildBundle) {
      globals.printTrace('Updating assets');
      final int result = await assetBundle.build();
      if (result != 0) {
        return UpdateFSReport(success: false);
      }
    }

    final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated(
      lastCompiled: flutterDevices[0].devFS.lastCompiled,
      urisToMonitor: flutterDevices[0].devFS.sources,
      packagesPath: packagesFilePath,
      asyncScanning: hotRunnerConfig.asyncScanning,
      packageConfig: flutterDevices[0].devFS.lastPackageConfig,
    );
    final UpdateFSReport results = UpdateFSReport(success: true);
    for (final FlutterDevice device in flutterDevices) {
      results.incorporateResults(await device.updateDevFS(
        mainUri: globals.fs.file(mainPath).absolute.uri,
        target: target,
        bundle: assetBundle,
        firstBuildTime: firstBuildTime,
        bundleFirstUpload: isFirstUpload,
        bundleDirty: !isFirstUpload && rebuildBundle,
        fullRestart: fullRestart,
        projectRootPath: projectRootPath,
        pathToReload: getReloadPath(fullRestart: fullRestart),
        invalidatedFiles: invalidationResult.uris,
        packageConfig: invalidationResult.packageConfig,
        dillOutputPath: dillOutputPath,
      ));
    }
    return results;
  }

  void _resetDirtyAssets() {
    for (final FlutterDevice device in flutterDevices) {
      device.devFS.assetPathsToEvict.clear();
    }
  }

  Future<void> _cleanupDevFS() async {
    final List<Future<void>> futures = <Future<void>>[];
    for (final FlutterDevice device in flutterDevices) {
      if (device.devFS != null) {
        // Cleanup the devFS, but don't wait indefinitely.
        // We ignore any errors, because it's not clear what we would do anyway.
        futures.add(device.devFS.destroy()
          .timeout(const Duration(milliseconds: 250))
          .catchError((dynamic error) {
            globals.printTrace('Ignored error while cleaning up DevFS: $error');
          }));
      }
      device.devFS = null;
    }
    await Future.wait(futures);
  }

  Future<void> _launchInView(
    FlutterDevice device,
    Uri main,
    Uri assetsDirectory,
  ) async {
    final List<FlutterView> views = await device.vmService.getFlutterViews();
    await Future.wait(<Future<void>>[
      for (final FlutterView view in views)
        device.vmService.runInView(
          viewId: view.id,
          main: main,
          assetsDirectory: assetsDirectory,
        ),
    ]);
  }

  Future<void> _launchFromDevFS(String mainScript) async {
    final String entryUri = globals.fs.path.relative(mainScript, from: projectRootPath);
    final List<Future<void>> futures = <Future<void>>[];
    for (final FlutterDevice device in flutterDevices) {
      final Uri deviceEntryUri = device.devFS.baseUri.resolveUri(
        globals.fs.path.toUri(entryUri));
      final Uri deviceAssetsDirectoryUri = device.devFS.baseUri.resolveUri(
        globals.fs.path.toUri(getAssetBuildDirectory()));
      futures.add(_launchInView(device,
                          deviceEntryUri,
                          deviceAssetsDirectoryUri));
    }
    await Future.wait(futures);
    if (benchmarkMode) {
      futures.clear();
      for (final FlutterDevice device in flutterDevices) {
        final List<FlutterView> views = await device.vmService.getFlutterViews();
        for (final FlutterView view in views) {
          futures.add(device.vmService
            .flushUIThreadTasks(uiIsolateId: view.uiIsolate.id));
        }
      }
      await Future.wait(futures);
    }
  }

  Future<OperationResult> _restartFromSources({
    String reason,
    bool benchmarkMode = false,
  }) async {
    final Stopwatch restartTimer = Stopwatch()..start();
    // TODO(aam): Add generator reset logic once we switch to using incremental
    // compiler for full application recompilation on restart.
    final UpdateFSReport updatedDevFS = await _updateDevFS(fullRestart: true);
    if (!updatedDevFS.success) {
      for (final FlutterDevice device in flutterDevices) {
        if (device.generator != null) {
          await device.generator.reject();
        }
      }
      return OperationResult(1, 'DevFS synchronization failed');
    }
    _resetDirtyAssets();
    for (final FlutterDevice device in flutterDevices) {
      // VM must have accepted the kernel binary, there will be no reload
      // report, so we let incremental compiler know that source code was accepted.
      if (device.generator != null) {
        device.generator.accept();
      }
    }
    // Check if the isolate is paused and resume it.
    final List<Future<void>> operations = <Future<void>>[];
    for (final FlutterDevice device in flutterDevices) {
      final Set<String> uiIsolatesIds = <String>{};
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      for (final FlutterView view in views) {
        if (view.uiIsolate == null) {
          continue;
        }
        uiIsolatesIds.add(view.uiIsolate.id);
        // Reload the isolate.
        final Future<vm_service.Isolate> reloadIsolate = device.vmService
          .getIsolateOrNull(view.uiIsolate.id);
        operations.add(reloadIsolate.then((vm_service.Isolate isolate) async {
          if ((isolate != null) && isPauseEvent(isolate.pauseEvent.kind)) {
            // Resume the isolate so that it can be killed by the embedder.
            await device.vmService.resume(view.uiIsolate.id);
          }
        }));
      }

      // The engine handles killing and recreating isolates that it has spawned
      // ("uiIsolates"). The isolates that were spawned from these uiIsolates
      // will not be restared, and so they must be manually killed.
      final vm_service.VM vm = await device.vmService.getVM();
      for (final vm_service.IsolateRef isolateRef in vm.isolates) {
        if (uiIsolatesIds.contains(isolateRef.id)) {
          continue;
        }
        operations.add(device.vmService.kill(isolateRef.id)
          .catchError((dynamic error, StackTrace stackTrace) {
            // Do nothing on a SentinelException since it means the isolate
            // has already been killed.
          }, test: (dynamic error) => error is vm_service.SentinelException));
      }
    }
    await Future.wait(operations);

    await _launchFromDevFS(mainPath + '.dill');
    restartTimer.stop();
    globals.printTrace('Hot restart performed in ${getElapsedAsMilliseconds(restartTimer.elapsed)}.');
    _addBenchmarkData('hotRestartMillisecondsToFrame',
        restartTimer.elapsed.inMilliseconds);

    // Send timing analytics.
    globals.flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed);

    // In benchmark mode, make sure all stream notifications have finished.
    if (benchmarkMode) {
      final List<Future<void>> isolateNotifications = <Future<void>>[];
      for (final FlutterDevice device in flutterDevices) {
        try {
          await device.vmService.streamListen('Isolate');
        } on vm_service.RPCError {
          // Do nothing, we're already subcribed.
        }
        isolateNotifications.add(
          device.vmService.onIsolateEvent.firstWhere((vm_service.Event event) {
            return event.kind == vm_service.EventKind.kIsolateRunnable;
          }),
        );
      }
      await Future.wait(isolateNotifications);
    }
    return OperationResult.ok;
  }

  /// Returns [true] if the reload was successful.
  /// Prints errors if [printErrors] is [true].
  static bool validateReloadReport(
    Map<String, dynamic> reloadReport, {
    bool printErrors = true,
  }) {
    if (reloadReport == null) {
      if (printErrors) {
        globals.printError('Hot reload did not receive reload report.');
      }
      return false;
    }
    if (!(reloadReport['type'] == 'ReloadReport' &&
          (reloadReport['success'] == true ||
           (reloadReport['success'] == false &&
            (reloadReport['details'] is Map<String, dynamic> &&
             reloadReport['details']['notices'] is List<dynamic> &&
             (reloadReport['details']['notices'] as List<dynamic>).isNotEmpty &&
             (reloadReport['details']['notices'] as List<dynamic>).every(
               (dynamic item) => item is Map<String, dynamic> && item['message'] is String
             )
            )
           )
          )
         )) {
      if (printErrors) {
        globals.printError('Hot reload received invalid response: $reloadReport');
      }
      return false;
    }
    if (!(reloadReport['success'] as bool)) {
      if (printErrors) {
        globals.printError('Hot reload was rejected:');
        for (final Map<String, dynamic> notice in (reloadReport['details']['notices'] as List<dynamic>).cast<Map<String, dynamic>>()) {
          globals.printError('${notice['message']}');
        }
      }
      return false;
    }
    return true;
  }

  @override
  bool get supportsRestart => true;

  @override
  Future<OperationResult> restart({
    bool fullRestart = false,
    String reason,
    bool benchmarkMode = false,
    bool silent = false,
    bool pause = false,
  }) async {
    String targetPlatform;
    String sdkName;
    bool emulator;
    if (flutterDevices.length == 1) {
      final Device device = flutterDevices.first.device;
      targetPlatform = getNameForTargetPlatform(await device.targetPlatform);
      sdkName = await device.sdkNameAndVersion;
      emulator = await device.isLocalEmulator;
    } else if (flutterDevices.length > 1) {
      targetPlatform = 'multiple';
      sdkName = 'multiple';
      emulator = false;
    } else {
      targetPlatform = 'unknown';
      sdkName = 'unknown';
      emulator = false;
    }
    final Stopwatch timer = Stopwatch()..start();

    // Run source generation if needed.
    await runSourceGenerators();

    if (fullRestart) {
      final OperationResult result = await _fullRestartHelper(
        targetPlatform: targetPlatform,
        sdkName: sdkName,
        emulator: emulator,
        reason: reason,
        benchmarkMode: benchmarkMode,
        silent: silent,
      );
      if (!silent) {
        globals.printStatus('Restarted application in ${getElapsedAsMilliseconds(timer.elapsed)}.');
      }
      return result;
    }
    final OperationResult result = await _hotReloadHelper(
      targetPlatform: targetPlatform,
      sdkName: sdkName,
      emulator: emulator,
      reason: reason,
      pause: pause,
    );
    if (result.isOk) {
      final String elapsed = getElapsedAsMilliseconds(timer.elapsed);
      if (!silent) {
        globals.printStatus('${result.message} in $elapsed.');
      }
    }
    return result;
  }

  Future<OperationResult> _fullRestartHelper({
    String targetPlatform,
    String sdkName,
    bool emulator,
    String reason,
    bool benchmarkMode,
    bool silent,
  }) async {
    if (!canHotRestart) {
      return OperationResult(1, 'hotRestart not supported');
    }
    Status status;
    if (!silent) {
      status = globals.logger.startProgress(
        'Performing hot restart...',
        timeout: timeoutConfiguration.fastOperation,
        progressId: 'hot.restart',
      );
    }
    OperationResult result;
    String restartEvent = 'restart';
    try {
      if (!(await hotRunnerConfig.setupHotRestart())) {
        return OperationResult(1, 'setupHotRestart failed');
      }
      // The current implementation of the vmservice and JSON rpc may throw
      // unhandled exceptions into the zone that cannot be caught with a regular
      // try catch. The usage is [asyncGuard] is required to normalize the error
      // handling, at least until we can refactor the underlying code.
      result = await asyncGuard(() => _restartFromSources(
        reason: reason,
        benchmarkMode: benchmarkMode,
      ));
      if (!result.isOk) {
        restartEvent = 'restart-failed';
      }
    } on vm_service.SentinelException catch (err, st) {
      restartEvent = 'exception';
      return OperationResult(1, 'hot restart failed to complete: $err\n$st', fatal: true);
    } on vm_service.RPCError  catch (err, st) {
      restartEvent = 'exception';
      return OperationResult(1, 'hot restart failed to complete: $err\n$st', fatal: true);
    } finally {
      HotEvent(restartEvent,
        targetPlatform: targetPlatform,
        sdkName: sdkName,
        emulator: emulator,
        fullRestart: true,
        reason: reason).send();
      status?.cancel();
    }
    return result;
  }

  Future<OperationResult> _hotReloadHelper({
    String targetPlatform,
    String sdkName,
    bool emulator,
    String reason,
    bool pause,
  }) async {
    Status status = globals.logger.startProgress(
      'Performing hot reload...',
      timeout: timeoutConfiguration.fastOperation,
      progressId: 'hot.reload',
    );
    OperationResult result;
    try {
      result = await _reloadSources(
        targetPlatform: targetPlatform,
        sdkName: sdkName,
        emulator: emulator,
        reason: reason,
        pause: pause,
        onSlow: (String message) {
          status?.cancel();
          status = globals.logger.startProgress(
            message,
            timeout: timeoutConfiguration.slowOperation,
            progressId: 'hot.reload',
          );
        },
      );
    } on vm_service.RPCError {
      HotEvent('exception',
        targetPlatform: targetPlatform,
        sdkName: sdkName,
        emulator: emulator,
        fullRestart: false,
        reason: reason).send();
      return OperationResult(1, 'hot reload failed to complete', fatal: true);
    } finally {
      status.cancel();
    }
    return result;
  }

  Future<OperationResult> _reloadSources({
    String targetPlatform,
    String sdkName,
    bool emulator,
    bool pause = false,
    String reason,
    void Function(String message) onSlow,
  }) async {
    for (final FlutterDevice device in flutterDevices) {
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      for (final FlutterView view in views) {
        if (view.uiIsolate == null) {
          return OperationResult(2, 'Application isolate not found', fatal: true);
        }
      }
    }

    final Stopwatch reloadTimer = Stopwatch()..start();
    final Stopwatch devFSTimer = Stopwatch()..start();
    final UpdateFSReport updatedDevFS = await _updateDevFS();
    // Record time it took to synchronize to DevFS.
    bool shouldReportReloadTime = true;
    _addBenchmarkData('hotReloadDevFSSyncMilliseconds', devFSTimer.elapsed.inMilliseconds);
    if (!updatedDevFS.success) {
      return OperationResult(1, 'DevFS synchronization failed');
    }
    String reloadMessage;
    final Stopwatch vmReloadTimer = Stopwatch()..start();
    Map<String, dynamic> firstReloadDetails;
    try {
      final String entryPath = globals.fs.path.relative(
        getReloadPath(fullRestart: false),
        from: projectRootPath,
      );
      final List<Future<DeviceReloadReport>> allReportsFutures = <Future<DeviceReloadReport>>[];
      for (final FlutterDevice device in flutterDevices) {
        if (_shouldResetAssetDirectory) {
          // Asset directory has to be set only once when we switch from
          // running from bundle to uploaded files.
          await device.resetAssetDirectory();
          _shouldResetAssetDirectory = false;
        }
        final List<Future<vm_service.ReloadReport>> reportFutures = await device.reloadSources(
          entryPath, pause: pause,
        );
        allReportsFutures.add(Future.wait(reportFutures).then(
          (List<vm_service.ReloadReport> reports) async {
            // TODO(aam): Investigate why we are validating only first reload report,
            // which seems to be current behavior
            final vm_service.ReloadReport firstReport = reports.first;
            // Don't print errors because they will be printed further down when
            // `validateReloadReport` is called again.
            await device.updateReloadStatus(
              validateReloadReport(firstReport.json, printErrors: false),
            );
            return DeviceReloadReport(device, reports);
          },
        ));
      }
      final List<DeviceReloadReport> reports = await Future.wait(allReportsFutures);
      for (final DeviceReloadReport report in reports) {
        final vm_service.ReloadReport reloadReport = report.reports[0];
        if (!validateReloadReport(reloadReport.json)) {
          // Reload failed.
          HotEvent('reload-reject',
            targetPlatform: targetPlatform,
            sdkName: sdkName,
            emulator: emulator,
            fullRestart: false,
            reason: reason,
          ).send();
          return OperationResult(1, 'Reload rejected');
        }
        // Collect stats only from the first device. If/when run -d all is
        // refactored, we'll probably need to send one hot reload/restart event
        // per device to analytics.
        firstReloadDetails ??= castStringKeyedMap(reloadReport.json['details']);
        final int loadedLibraryCount = reloadReport.json['details']['loadedLibraryCount'] as int;
        final int finalLibraryCount = reloadReport.json['details']['finalLibraryCount'] as int;
        globals.printTrace('reloaded $loadedLibraryCount of $finalLibraryCount libraries');
        reloadMessage = 'Reloaded $loadedLibraryCount of $finalLibraryCount libraries';
      }
    } on Map<String, dynamic> catch (error, stackTrace) {
      globals.printTrace('Hot reload failed: $error\n$stackTrace');
      final int errorCode = error['code'] as int;
      String errorMessage = error['message'] as String;
      if (errorCode == kIsolateReloadBarred) {
        errorMessage = 'Unable to hot reload application due to an unrecoverable error in '
                       'the source code. Please address the error and then use "R" to '
                       'restart the app.\n'
                       '$errorMessage (error code: $errorCode)';
        HotEvent('reload-barred',
          targetPlatform: targetPlatform,
          sdkName: sdkName,
          emulator: emulator,
          fullRestart: false,
          reason: reason,
        ).send();
        return OperationResult(errorCode, errorMessage);
      }
      return OperationResult(errorCode, '$errorMessage (error code: $errorCode)');
    } on Exception catch (error, stackTrace) {
      globals.printTrace('Hot reload failed: $error\n$stackTrace');
      return OperationResult(1, '$error');
    }
    // Record time it took for the VM to reload the sources.
    _addBenchmarkData('hotReloadVMReloadMilliseconds', vmReloadTimer.elapsed.inMilliseconds);
    final Stopwatch reassembleTimer = Stopwatch()..start();
    await _evictDirtyAssets();

    // Check if any isolates are paused and reassemble those
    // that aren't.
    final Map<FlutterView, vm_service.VmService> reassembleViews = <FlutterView, vm_service.VmService>{};
    final List<Future<void>> reassembleFutures = <Future<void>>[];
    String serviceEventKind;
    int pausedIsolatesFound = 0;
    bool failedReassemble = false;
    for (final FlutterDevice device in flutterDevices) {
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      for (final FlutterView view in views) {
        // Check if the isolate is paused, and if so, don't reassemble. Ignore the
        // PostPauseEvent event - the client requesting the pause will resume the app.
        final vm_service.Isolate isolate = await device.vmService
          .getIsolateOrNull(view.uiIsolate.id);
        final vm_service.Event pauseEvent = isolate?.pauseEvent;
        if (pauseEvent != null
          && isPauseEvent(pauseEvent.kind)
          && pauseEvent.kind != vm_service.EventKind.kPausePostRequest) {
          pausedIsolatesFound += 1;
          if (serviceEventKind == null) {
            serviceEventKind = pauseEvent.kind;
          } else if (serviceEventKind != pauseEvent.kind) {
            serviceEventKind = ''; // many kinds
          }
        } else {
          reassembleViews[view] = device.vmService;
          reassembleFutures.add(device.vmService.flutterReassemble(
            isolateId: view.uiIsolate.id,
          ).catchError((dynamic error) {
            failedReassemble = true;
            globals.printError('Reassembling ${view.uiIsolate.name} failed: $error');
          }, test: (dynamic error) => error is Exception));
        }
      }
    }
    if (pausedIsolatesFound > 0) {
      if (onSlow != null) {
        onSlow('${_describePausedIsolates(pausedIsolatesFound, serviceEventKind)}; interface might not update.');
      }
      if (reassembleViews.isEmpty) {
        globals.printTrace('Skipping reassemble because all isolates are paused.');
        return OperationResult(OperationResult.ok.code, reloadMessage);
      }
    }
    assert(reassembleViews.isNotEmpty);

    globals.printTrace('Reassembling application');

    final Future<void> reassembleFuture = Future.wait<void>(reassembleFutures);
    await reassembleFuture.timeout(
      const Duration(seconds: 2),
      onTimeout: () async {
        if (pausedIsolatesFound > 0) {
          shouldReportReloadTime = false;
          return; // probably no point waiting, they're probably deadlocked and we've already warned.
        }
        // Check if any isolate is newly paused.
        globals.printTrace('This is taking a long time; will now check for paused isolates.');
        int postReloadPausedIsolatesFound = 0;
        String serviceEventKind;
        for (final FlutterView view in reassembleViews.keys) {
          final vm_service.Isolate isolate = await reassembleViews[view]
            .getIsolateOrNull(view.uiIsolate.id);
          if (isolate == null) {
            continue;
          }
          if (isolate.pauseEvent != null && isPauseEvent(isolate.pauseEvent.kind)) {
            postReloadPausedIsolatesFound += 1;
            if (serviceEventKind == null) {
              serviceEventKind = isolate.pauseEvent.kind;
            } else if (serviceEventKind != isolate.pauseEvent.kind) {
              serviceEventKind = ''; // many kinds
            }
          }
        }
        globals.printTrace('Found $postReloadPausedIsolatesFound newly paused isolate(s).');
        if (postReloadPausedIsolatesFound == 0) {
          await reassembleFuture; // must just be taking a long time... keep waiting!
          return;
        }
        shouldReportReloadTime = false;
        if (onSlow != null) {
          onSlow('${_describePausedIsolates(postReloadPausedIsolatesFound, serviceEventKind)}.');
        }
      },
    );
    // Record time it took for Flutter to reassemble the application.
    _addBenchmarkData('hotReloadFlutterReassembleMilliseconds', reassembleTimer.elapsed.inMilliseconds);

    reloadTimer.stop();
    final Duration reloadDuration = reloadTimer.elapsed;
    final int reloadInMs = reloadDuration.inMilliseconds;

    // Collect stats that help understand scale of update for this hot reload request.
    // For example, [syncedLibraryCount]/[finalLibraryCount] indicates how
    // many libraries were affected by the hot reload request.
    // Relation of [invalidatedSourcesCount] to [syncedLibraryCount] should help
    // understand sync/transfer "overhead" of updating this number of source files.
    HotEvent('reload',
      targetPlatform: targetPlatform,
      sdkName: sdkName,
      emulator: emulator,
      fullRestart: false,
      reason: reason,
      overallTimeInMs: reloadInMs,
      finalLibraryCount: firstReloadDetails['finalLibraryCount'] as int,
      syncedLibraryCount: firstReloadDetails['receivedLibraryCount'] as int,
      syncedClassesCount: firstReloadDetails['receivedClassesCount'] as int,
      syncedProceduresCount: firstReloadDetails['receivedProceduresCount'] as int,
      syncedBytes: updatedDevFS.syncedBytes,
      invalidatedSourcesCount: updatedDevFS.invalidatedSourcesCount,
      transferTimeInMs: devFSTimer.elapsed.inMilliseconds,
    ).send();

    if (shouldReportReloadTime) {
      globals.printTrace('Hot reload performed in ${getElapsedAsMilliseconds(reloadDuration)}.');
      // Record complete time it took for the reload.
      _addBenchmarkData('hotReloadMillisecondsToFrame', reloadInMs);
    }
    // Only report timings if we reloaded a single view without any errors.
    if ((reassembleViews.length == 1) && !failedReassemble && shouldReportReloadTime) {
      globals.flutterUsage.sendTiming('hot', 'reload', reloadDuration);
    }
    return OperationResult(
      failedReassemble ? 1 : OperationResult.ok.code,
      reloadMessage,
    );
  }

  String _describePausedIsolates(int pausedIsolatesFound, String serviceEventKind) {
    assert(pausedIsolatesFound > 0);
    final StringBuffer message = StringBuffer();
    bool plural;
    if (pausedIsolatesFound == 1) {
      message.write('The application is ');
      plural = false;
    } else {
      message.write('$pausedIsolatesFound isolates are ');
      plural = true;
    }
    assert(serviceEventKind != null);
    switch (serviceEventKind) {
      case vm_service.EventKind.kPauseStart:
        message.write('paused (probably due to --start-paused)');
        break;
      case vm_service.EventKind.kPauseExit:
        message.write('paused because ${ plural ? 'they have' : 'it has' } terminated');
        break;
      case vm_service.EventKind.kPauseBreakpoint:
        message.write('paused in the debugger on a breakpoint');
        break;
      case vm_service.EventKind.kPauseInterrupted:
        message.write('paused due in the debugger');
        break;
      case vm_service.EventKind.kPauseException:
        message.write('paused in the debugger after an exception was thrown');
        break;
      case vm_service.EventKind.kPausePostRequest:
        message.write('paused');
        break;
      case '':
        message.write('paused for various reasons');
        break;
      default:
        message.write('paused');
    }
    return message.toString();
  }


  @override
  void printHelp({ @required bool details }) {
    globals.printStatus('Flutter run key commands.');
    commandHelp.r.print();
    if (canHotRestart) {
      commandHelp.R.print();
    }
    commandHelp.h.print();
    if (_didAttach) {
      commandHelp.d.print();
    }
    commandHelp.c.print();
    commandHelp.q.print();
    if (details) {
      printHelpDetails();
    }
    for (final FlutterDevice device in flutterDevices) {
      final String dname = device.device.name;
      // Caution: This log line is parsed by device lab tests.
      globals.printStatus(
        'An Observatory debugger and profiler on $dname is available at: '
        '${device.vmService.httpAddress}',
      );
    }
  }

  Future<void> _evictDirtyAssets() async {
    final List<Future<Map<String, dynamic>>> futures = <Future<Map<String, dynamic>>>[];
    for (final FlutterDevice device in flutterDevices) {
      if (device.devFS.assetPathsToEvict.isEmpty) {
        continue;
      }
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      if (views.first.uiIsolate == null) {
        globals.printError('Application isolate not found for $device');
        continue;
      }
      for (final String assetPath in device.devFS.assetPathsToEvict) {
        futures.add(
          device.vmService
            .flutterEvictAsset(
              assetPath,
              isolateId: views.first.uiIsolate.id,
            )
        );
      }
      device.devFS.assetPathsToEvict.clear();
    }
    return Future.wait<Map<String, dynamic>>(futures);
  }

  @override
  Future<void> cleanupAfterSignal() async {
    await stopEchoingDeviceLog();
    await hotRunnerConfig.runPreShutdownOperations();
    if (_didAttach) {
      appFinished();
    } else {
      await exitApp();
    }
  }

  @override
  Future<void> preExit() async {
    await _cleanupDevFS();
    await hotRunnerConfig.runPreShutdownOperations();
    await super.preExit();
  }

  @override
  Future<void> cleanupAtFinish() async {
    for (final FlutterDevice flutterDevice in flutterDevices) {
      await flutterDevice.device.dispose();
    }
    await _cleanupDevFS();
    await stopEchoingDeviceLog();
  }
}

/// The result of an invalidation check from [ProjectFileInvalidator].
class InvalidationResult {
  const InvalidationResult({
    this.uris,
    this.packageConfig,
  });

  final List<Uri> uris;
  final PackageConfig packageConfig;
}

/// The [ProjectFileInvalidator] track the dependencies for a running
/// application to determine when they are dirty.
class ProjectFileInvalidator {
  ProjectFileInvalidator({
    @required FileSystem fileSystem,
    @required Platform platform,
    @required Logger logger,
  }): _fileSystem = fileSystem,
      _platform = platform,
      _logger = logger;

  final FileSystem _fileSystem;
  final Platform _platform;
  final Logger _logger;

  static const String _pubCachePathLinuxAndMac = '.pub-cache';
  static const String _pubCachePathWindows = 'Pub/Cache';

  // As of writing, Dart supports up to 32 asynchronous I/O threads per
  // isolate. We also want to avoid hitting platform limits on open file
  // handles/descriptors.
  //
  // This value was chosen based on empirical tests scanning a set of
  // ~2000 files.
  static const int _kMaxPendingStats = 8;

  Future<InvalidationResult> findInvalidated({
    @required DateTime lastCompiled,
    @required List<Uri> urisToMonitor,
    @required String packagesPath,
    @required PackageConfig packageConfig,
    bool asyncScanning = false,
  }) async {
    assert(urisToMonitor != null);
    assert(packagesPath != null);

    if (lastCompiled == null) {
      // Initial load.
      assert(urisToMonitor.isEmpty);
      return InvalidationResult(
        packageConfig: await _createPackageConfig(packagesPath),
        uris: <Uri>[]
      );
    }

    final Stopwatch stopwatch = Stopwatch()..start();
    final List<Uri> urisToScan = <Uri>[
      // Don't watch pub cache directories to speed things up a little.
      for (final Uri uri in urisToMonitor)
        if (_isNotInPubCache(uri)) uri,
    ];
    final List<Uri> invalidatedFiles = <Uri>[];
    if (asyncScanning) {
      final Pool pool = Pool(_kMaxPendingStats);
      final List<Future<void>> waitList = <Future<void>>[];
      for (final Uri uri in urisToScan) {
        waitList.add(pool.withResource<void>(
          () => _fileSystem
            .stat(uri.toFilePath(windows: _platform.isWindows))
            .then((FileStat stat) {
              final DateTime updatedAt = stat.modified;
              if (updatedAt != null && updatedAt.isAfter(lastCompiled)) {
                invalidatedFiles.add(uri);
              }
            })
        ));
      }
      await Future.wait<void>(waitList);
    } else {
      for (final Uri uri in urisToScan) {
        final DateTime updatedAt = _fileSystem.statSync(
            uri.toFilePath(windows: _platform.isWindows)).modified;
        if (updatedAt != null && updatedAt.isAfter(lastCompiled)) {
          invalidatedFiles.add(uri);
        }
      }
    }
    // We need to check the .packages file too since it is not used in compilation.
    final Uri packageUri = _fileSystem.file(packagesPath).uri;
    final DateTime updatedAt = _fileSystem.statSync(
      packageUri.toFilePath(windows: _platform.isWindows)).modified;
    if (updatedAt != null && updatedAt.isAfter(lastCompiled)) {
      invalidatedFiles.add(packageUri);
      packageConfig = await _createPackageConfig(packagesPath);
      // The frontend_server might be monitoring the package_config.json file,
      // Pub should always produce both files.
      // TODO(jonahwilliams): remove after https://github.com/flutter/flutter/issues/55249
      if (_fileSystem.path.basename(packagesPath) == '.packages') {
        final File packageConfigFile = _fileSystem.file(packagesPath)
          .parent.childDirectory('.dart_tool')
          .childFile('package_config.json');
        if (packageConfigFile.existsSync()) {
          invalidatedFiles.add(packageConfigFile.uri);
        }
      }
    }

    _logger.printTrace(
      'Scanned through ${urisToScan.length} files in '
      '${stopwatch.elapsedMilliseconds}ms'
      '${asyncScanning ? " (async)" : ""}',
    );
    return InvalidationResult(
      packageConfig: packageConfig,
      uris: invalidatedFiles,
    );
  }

  bool _isNotInPubCache(Uri uri) {
    return !(_platform.isWindows && uri.path.contains(_pubCachePathWindows))
        && !uri.path.contains(_pubCachePathLinuxAndMac);
  }

  Future<PackageConfig> _createPackageConfig(String packagesPath) {
    return loadPackageConfigWithLogging(
      _fileSystem.file(globalPackagesPath),
      logger: _logger,
    );
  }
}
