// 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.

// @dart = 2.8

import 'dart:async';

import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:pool/pool.dart';
import 'package:vm_service/vm_service.dart' as vm_service;

import 'base/common.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 'features.dart';
import 'globals.dart' as globals;
import 'project.dart';
import 'reporting/reporting.dart';
import 'resident_devtools_handler.dart';
import 'resident_runner.dart';
import 'vmservice.dart';

ProjectFileInvalidator get projectFileInvalidator => context.get<ProjectFileInvalidator>() ?? 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 initialization prior
  /// to a hot reload. Should return true if the hot restart should continue.
  Future<bool> setupHotReload() async {
    return true;
  }

  /// A hook for implementations to perform any necessary cleanup after the
  /// devfs sync is complete. At this point the flutter_tools no longer needs to
  /// access the source files and assets.
  void updateDevFSComplete() {}

  /// 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.
}

class HotRunner extends ResidentRunner {
  HotRunner(
    List<FlutterDevice> devices, {
    @required String target,
    @required DebuggingOptions debuggingOptions,
    this.benchmarkMode = false,
    this.applicationBinary,
    this.hostIsIde = false,
    String projectRootPath,
    String dillOutputPath,
    bool stayResident = true,
    bool ipv6 = false,
    bool machine = false,
    this.multidexEnabled = false,
    ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler,
    StopwatchFactory stopwatchFactory = const StopwatchFactory(),
    ReloadSourcesHelper reloadSourcesHelper = _defaultReloadSourcesHelper,
    ReassembleHelper reassembleHelper = _defaultReassembleHelper,
  }) : _stopwatchFactory = stopwatchFactory,
       _reloadSourcesHelper = reloadSourcesHelper,
       _reassembleHelper = reassembleHelper,
       super(
          devices,
          target: target,
          debuggingOptions: debuggingOptions,
          projectRootPath: projectRootPath,
          stayResident: stayResident,
          hotMode: true,
          dillOutputPath: dillOutputPath,
          ipv6: ipv6,
          machine: machine,
          devtoolsHandler: devtoolsHandler,
        );

  final StopwatchFactory _stopwatchFactory;
  final ReloadSourcesHelper _reloadSourcesHelper;
  final ReassembleHelper _reassembleHelper;

  final bool benchmarkMode;
  final File applicationBinary;
  final bool hostIsIde;
  final bool multidexEnabled;

  /// When performing a hot restart, the tool needs to upload a new main.dart.dill to
  /// each attached device's devfs. Replacing the existing file is not safe and does
  /// not work at all on the windows embedder, because the old dill file will still be
  /// memory-mapped by the embedder. To work around this issue, the tool will alternate
  /// names for the uploaded dill, sometimes inserting `.swap`. Since the active dill will
  /// never be replaced, there is no risk of writing the file while the embedder is attempting
  /// to read from it. This also avoids filling up the devfs, if a incrementing counter was
  /// used instead.
  ///
  /// This is only used for hot restart, incremental dills uploaded as part of the hot
  /// reload process do not have this issue.
  bool _swap = false;

  /// Whether the resident runner has correctly attached to the running application.
  bool _didAttach = false;

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

  DateTime firstBuildTime;

  String _targetPlatform;
  String _sdkName;
  bool _emulator;

  Future<void> _calculateTargetPlatform() async {
    if (_targetPlatform != null) {
      return;
    }

    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;
    }
  }

  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 {
    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.expressionData != null) {
          return base64.encode(compilerOutput.expressionData);
        }
      }
    }
    throw Exception('Failed to compile $expression');
  }

  // Returns the exit code of the flutter tool process, like [run].
  @override
  Future<int> attach({
    Completer<DebugConnectionInfo> connectionInfoCompleter,
    Completer<void> appStartedCompleter,
    bool allowExistingDdsInstance = false,
    bool enableDevTools = false,
  }) async {
    _didAttach = true;
    try {
      await connectToServiceProtocol(
        reloadSources: _reloadSourcesService,
        restart: _restartService,
        compileExpression: _compileExpressionService,
        getSkSLMethod: writeSkSL,
        allowExistingDdsInstance: allowExistingDdsInstance,
      );
    // 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');
      return 2;
    }

    if (enableDevTools) {
      // The method below is guaranteed never to return a failing future.
      unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools(
        devToolsServerAddress: debuggingOptions.devToolsServerAddress,
        flutterDevices: flutterDevices,
      ));
    }

    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 DevFSException 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,
        reason: 'restart',
        silent: true,
      );
    }

    appStartedCompleter?.complete();

    if (benchmarkMode) {
      // Wait multiple seconds for the isolate to have fully started.
      await Future<void>.delayed(const Duration(seconds: 10));
      // 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);
      // Wait multiple seconds to stabilize benchmark on slower device lab hardware.
      // Hot restart finishes when the new isolate is started, not when the new isolate
      // is ready. This process can actually take multiple seconds.
      await Future<void>.delayed(const Duration(seconds: 10));

      globals.printStatus('Benchmarking hot reload');
      // Measure time to perform a hot reload.
      await restart();
      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,
    bool enableDevTools = false,
    String route,
  }) async {
    await _calculateTargetPlatform();

    final Stopwatch appStartedTimer = Stopwatch()..start();
    final File mainFile = globals.fs.file(mainPath);
    firstBuildTime = DateTime.now();

    Duration totalCompileTime = Duration.zero;
    Duration totalLaunchAppTime = Duration.zero;

    final List<Future<bool>> startupTasks = <Future<bool>>[];
    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) {
        final Stopwatch compileTimer = Stopwatch()..start();
        startupTasks.add(
          device.generator.recompile(
            mainFile.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,
            checkDartPluginRegistry: true,
            outputPath: dillOutputPath ??
              getDefaultApplicationKernelPath(
                trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation,
              ),
            packageConfig: debuggingOptions.buildInfo.packageConfig,
            projectRootPath: FlutterProject.current().directory.absolute.path,
            fs: globals.fs,
          ).then((CompilerOutput output) {
            compileTimer.stop();
            totalCompileTime += compileTimer.elapsed;
            return output?.errorCount == 0;
          })
        );
      }

      final Stopwatch launchAppTimer = Stopwatch()..start();
      startupTasks.add(device.runHot(
        hotRunner: this,
        route: route,
      ).then((int result) {
        totalLaunchAppTime += launchAppTimer.elapsed;
        return result == 0;
      }));
    }

    unawaited(appStartedCompleter?.future?.then((_) => HotEvent('reload-ready',
      targetPlatform: _targetPlatform,
      sdkName: _sdkName,
      emulator: _emulator,
      fullRestart: false,
      fastReassemble: false,
      overallTimeInMs: appStartedTimer.elapsed.inMilliseconds,
      compileTimeInMs: totalCompileTime.inMilliseconds,
      transferTimeInMs: totalLaunchAppTime.inMilliseconds,
    )?.send()));

    try {
      final List<bool> results = await Future.wait(startupTasks);
      if (!results.every((bool passed) => passed)) {
        appFailedToStart();
        return 1;
      }
      cacheInitialDillCompilation();
    } on Exception catch (err) {
      globals.printError(err.toString());
      appFailedToStart();
      return 1;
    }

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

  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),
        ),
    ];
  }

  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(packagesPath: '.packages');
      if (result != 0) {
        return UpdateFSReport();
      }
    }

    final Stopwatch findInvalidationTimer = _stopwatchFactory.createStopwatch('updateDevFS')..start();
    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
          ?? debuggingOptions.buildInfo.packageConfig,
    );
    findInvalidationTimer.stop();
    final File entrypointFile = globals.fs.file(mainPath);
    if (!entrypointFile.existsSync()) {
      globals.printError(
        'The entrypoint file (i.e. the file with main()) ${entrypointFile.path} '
        'cannot be found. Moving or renaming this file will prevent changes to '
        'its contents from being discovered during hot reload/restart until '
        'flutter is restarted or the file is restored.'
      );
    }
    final UpdateFSReport results = UpdateFSReport(
      success: true,
      scannedSourcesCount: flutterDevices[0].devFS.sources.length,
      findInvalidatedDuration: findInvalidationTimer.elapsed,
    );
    for (final FlutterDevice device in flutterDevices) {
      results.incorporateResults(await device.updateDevFS(
        mainUri: entrypointFile.absolute.uri,
        target: target,
        bundle: assetBundle,
        firstBuildTime: firstBuildTime,
        bundleFirstUpload: isFirstUpload,
        bundleDirty: !isFirstUpload && rebuildBundle,
        fullRestart: fullRestart,
        projectRootPath: projectRootPath,
        pathToReload: getReloadPath(fullRestart: fullRestart, swap: _swap),
        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() async {
    final List<Future<void>> futures = <Future<void>>[];
    for (final FlutterDevice device in flutterDevices) {
      final Uri deviceEntryUri = device.devFS.baseUri.resolve(_swap ? 'main.dart.swap.dill' : 'main.dart.dill');
      final Uri deviceAssetsDirectoryUri = device.devFS.baseUri.resolveUri(
        globals.fs.path.toUri(getAssetBuildDirectory()));
      futures.add(_launchInView(device,
                          deviceEntryUri,
                          deviceAssetsDirectoryUri));
    }
    await Future.wait(futures);
  }

  Future<OperationResult> _restartFromSources({
    String reason,
  }) async {
    final Stopwatch restartTimer = Stopwatch()..start();
    UpdateFSReport updatedDevFS;
    try {
      updatedDevFS = await _updateDevFS(fullRestart: true);
    } finally {
      hotRunnerConfig.updateDevFSComplete();
    }
    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)) {
            // The embedder requires that the isolate is unpaused, because the
            // runInView method requires interaction with dart engine APIs that
            // are not thread-safe, and thus must be run on the same thread that
            // would be blocked by the pause. Simply un-pausing is not sufficient,
            // because this does not prevent the isolate from immediately hitting
            // a breakpoint (for example if the breakpoint was placed in a loop
            // or in a frequently called method) or an exception. Instead, all
            // breakpoints are first disabled and exception pause mode set to
            // None, and then the isolate resumed.
            // These settings to not need restoring as Hot Restart results in
            // new isolates, which will be configured by the editor as they are
            // started.
            final List<Future<void>> breakpointAndExceptionRemoval = <Future<void>>[
              device.vmService.service.setIsolatePauseMode(isolate.id,
                exceptionPauseMode: vm_service.ExceptionPauseMode.kNone),
              for (final vm_service.Breakpoint breakpoint in isolate.breakpoints)
                device.vmService.service.removeBreakpoint(isolate.id, breakpoint.id)
            ];
            await Future.wait(breakpointAndExceptionRemoval);
            await device.vmService.service.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 restarted, and so they must be manually killed.
      final vm_service.VM vm = await device.vmService.service.getVM();
      for (final vm_service.IsolateRef isolateRef in vm.isolates) {
        if (uiIsolatesIds.contains(isolateRef.id)) {
          continue;
        }
        operations.add(device.vmService.service.kill(isolateRef.id)
          .catchError((dynamic error, StackTrace stackTrace) {
            // Do nothing on a SentinelException since it means the isolate
            // has already been killed.
            // Error code 105 indicates the isolate is not yet runnable, and might
            // be triggered if the tool is attempting to kill the asset parsing
            // isolate before it has finished starting up.
          }, test: (dynamic error) => error is vm_service.SentinelException
            || (error is vm_service.RPCError && error.code == 105)));
      }
    }
    await Future.wait(operations);

    await _launchFromDevFS();
    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);

    // Toggle the main dill name after successfully uploading.
    _swap =! _swap;

    return OperationResult(
      OperationResult.ok.code,
      OperationResult.ok.message,
      updateFSReport: updatedDevFS,
    );
  }

  /// Returns [true] if the reload was successful.
  /// Prints errors if [printErrors] is [true].
  static bool validateReloadReport(
    vm_service.ReloadReport reloadReport, {
    bool printErrors = true,
  }) {
    if (reloadReport == null) {
      if (printErrors) {
        globals.printError('Hot reload did not receive reload report.');
      }
      return false;
    }
    final ReloadReportContents contents = ReloadReportContents.fromReloadReport(reloadReport);
    if (!reloadReport.success) {
      if (printErrors) {
        globals.printError('Hot reload was rejected:');
        for (final ReasonForCancelling reason in contents.notices) {
          globals.printError(reason.toString());
        }
      }
      return false;
    }
    return true;
  }

  @override
  Future<OperationResult> restart({
    bool fullRestart = false,
    String reason,
    bool silent = false,
    bool pause = false,
  }) async {
    if (flutterDevices.any((FlutterDevice device) => device.devFS == null)) {
      return OperationResult(1, 'Device initialization has not completed.');
    }
    await _calculateTargetPlatform();
    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,
        silent: silent,
      );
      if (!silent) {
        globals.printStatus('Restarted application in ${getElapsedAsMilliseconds(timer.elapsed)}.');
      }
      unawaited(residentDevtoolsHandler.hotRestart(flutterDevices));
      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 silent,
  }) async {
    if (!supportsRestart) {
      return OperationResult(1, 'hotRestart not supported');
    }
    Status status;
    if (!silent) {
      status = globals.logger.startProgress(
        'Performing hot restart...',
        progressId: 'hot.restart',
      );
    }
    OperationResult result;
    String restartEvent;
    try {
      final Stopwatch restartTimer = _stopwatchFactory.createStopwatch('fullRestartHelper')..start();
      if (!(await hotRunnerConfig.setupHotRestart())) {
        return OperationResult(1, 'setupHotRestart failed');
      }
      result = await _restartFromSources(reason: reason);
      restartTimer.stop();
      if (!result.isOk) {
        restartEvent = 'restart-failed';
      } else {
        HotEvent('restart',
          targetPlatform: targetPlatform,
          sdkName: sdkName,
          emulator: emulator,
          fullRestart: true,
          reason: reason,
          fastReassemble: false,
          overallTimeInMs: restartTimer.elapsed.inMilliseconds,
          syncedBytes: result.updateFSReport?.syncedBytes,
          invalidatedSourcesCount: result.updateFSReport?.invalidatedSourcesCount,
          transferTimeInMs: result.updateFSReport?.transferDuration?.inMilliseconds,
          compileTimeInMs: result.updateFSReport?.compileDuration?.inMilliseconds,
          findInvalidatedTimeInMs: result.updateFSReport?.findInvalidatedDuration?.inMilliseconds,
          scannedSourcesCount: result.updateFSReport?.scannedSourcesCount,
        ).send();
      }
    } 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 {
      // The `restartEvent` variable will be null if restart succeeded. We will
      // only handle the case when it failed here.
      if (restartEvent != null) {
        HotEvent(restartEvent,
          targetPlatform: targetPlatform,
          sdkName: sdkName,
          emulator: emulator,
          fullRestart: true,
          reason: reason,
          fastReassemble: false,
        ).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...',
      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,
            progressId: 'hot.reload',
          );
        },
      );
    } on vm_service.RPCError catch (error) {
      String errorMessage = 'hot reload failed to complete';
      int errorCode = 1;
      if (error.code == kIsolateReloadBarred) {
        errorCode = error.code;
        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'
                      '${error.message} (error code: ${error.code})';
        HotEvent('reload-barred',
          targetPlatform: targetPlatform,
          sdkName: sdkName,
          emulator: emulator,
          fullRestart: false,
          reason: reason,
          fastReassemble: false,
        ).send();
      } else {
        HotEvent('exception',
          targetPlatform: targetPlatform,
          sdkName: sdkName,
          emulator: emulator,
          fullRestart: false,
          reason: reason,
          fastReassemble: false,
        ).send();
      }
      return OperationResult(errorCode, errorMessage, 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 {
    final Map<FlutterDevice, List<FlutterView>> viewCache = <FlutterDevice, List<FlutterView>>{};
    for (final FlutterDevice device in flutterDevices) {
      final List<FlutterView> views = await device.vmService.getFlutterViews();
      viewCache[device] = views;
      for (final FlutterView view in views) {
        if (view.uiIsolate == null) {
          return OperationResult(2, 'Application isolate not found', fatal: true);
        }
      }
    }

    final Stopwatch reloadTimer = _stopwatchFactory.createStopwatch('reloadSources:reload')..start();
    if (!(await hotRunnerConfig.setupHotReload())) {
      return OperationResult(1, 'setupHotReload failed');
    }
    final Stopwatch devFSTimer = Stopwatch()..start();
    UpdateFSReport updatedDevFS;
    try {
      updatedDevFS= await _updateDevFS();
    } finally {
      hotRunnerConfig.updateDevFSComplete();
    }
    // 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 = 'Reloaded 0 libraries';
    final Stopwatch reloadVMTimer = _stopwatchFactory.createStopwatch('reloadSources:vm')..start();
    final Map<String, Object> firstReloadDetails = <String, Object>{};
    if (updatedDevFS.invalidatedSourcesCount > 0) {
      final OperationResult result = await _reloadSourcesHelper(
        this,
        flutterDevices,
        pause,
        firstReloadDetails,
        targetPlatform,
        sdkName,
        emulator,
        reason,
      );
      if (result.code != 0) {
        return result;
      }
      reloadMessage = result.message;
    } else {
      _addBenchmarkData('hotReloadVMReloadMilliseconds', 0);
    }
    reloadVMTimer.stop();

    await evictDirtyAssets();

    final Stopwatch reassembleTimer = _stopwatchFactory.createStopwatch('reloadSources:reassemble')..start();

    final ReassembleResult reassembleResult = await _reassembleHelper(
      flutterDevices,
      viewCache,
      onSlow,
      reloadMessage,
      updatedDevFS.fastReassembleClassName,
    );
    shouldReportReloadTime = reassembleResult.shouldReportReloadTime;
    if (reassembleResult.reassembleViews.isEmpty) {
      return OperationResult(OperationResult.ok.code, reloadMessage);
    }
    // Record time it took for Flutter to reassemble the application.
    reassembleTimer.stop();
    _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 ?? 0,
      syncedLibraryCount: firstReloadDetails['receivedLibraryCount'] as int ?? 0,
      syncedClassesCount: firstReloadDetails['receivedClassesCount'] as int ?? 0,
      syncedProceduresCount: firstReloadDetails['receivedProceduresCount'] as int ?? 0,
      syncedBytes: updatedDevFS.syncedBytes,
      invalidatedSourcesCount: updatedDevFS.invalidatedSourcesCount,
      transferTimeInMs: updatedDevFS.transferDuration.inMilliseconds,
      fastReassemble: featureFlags.isSingleWidgetReloadEnabled
        ? updatedDevFS.fastReassembleClassName != null
        : null,
      compileTimeInMs: updatedDevFS.compileDuration.inMilliseconds,
      findInvalidatedTimeInMs: updatedDevFS.findInvalidatedDuration.inMilliseconds,
      scannedSourcesCount: updatedDevFS.scannedSourcesCount,
      reassembleTimeInMs: reassembleTimer.elapsed.inMilliseconds,
      reloadVMTimeInMs: reloadVMTimer.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 ((reassembleResult.reassembleViews.length == 1) && !reassembleResult.failedReassemble && shouldReportReloadTime) {
      globals.flutterUsage.sendTiming('hot', 'reload', reloadDuration);
    }
    return OperationResult(
      reassembleResult.failedReassemble ? 1 : OperationResult.ok.code,
      reloadMessage,
    );
  }

  @override
  void printHelp({ @required bool details }) {
    globals.printStatus('Flutter run key commands.');
    commandHelp.r.print();
    if (supportsRestart) {
      commandHelp.R.print();
    }
    if (details) {
      printHelpDetails();
      commandHelp.hWithDetails.print();
    } else {
      commandHelp.hWithoutDetails.print();
    }
    if (_didAttach) {
      commandHelp.d.print();
    }
    commandHelp.c.print();
    commandHelp.q.print();
    globals.printStatus('');
    if (debuggingOptions.buildInfo.nullSafetyMode ==  NullSafetyMode.sound) {
      globals.printStatus('💪 Running with sound null safety 💪', emphasis: true);
    } else {
      globals.printStatus(
        'Running with unsound null safety',
        emphasis: true,
      );
      globals.printStatus(
        'For more information see https://dart.dev/null-safety/unsound-null-safety',
      );
    }
    globals.printStatus('');
    printDebuggerList();
  }

  @visibleForTesting
  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 this is the first time we update the assets, make sure to call the setAssetDirectory
      if (!device.devFS.hasSetAssetDirectory) {
        final Uri deviceAssetsDirectoryUri = device.devFS.baseUri.resolveUri(globals.fs.path.toUri(getAssetBuildDirectory()));
        await Future.wait<void>(views.map<Future<void>>(
          (FlutterView view) => device.vmService.setAssetDirectory(
            assetsDirectory: deviceAssetsDirectoryUri,
            uiIsolateId: view.uiIsolate.id,
            viewId: view.id,
          )
        ));
        for (final FlutterView view in views) {
          globals.printTrace('Set asset directory in $view.');
        }
        device.devFS.hasSetAssetDirectory = true;
      }

      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 residentDevtoolsHandler.shutdown();
    await stopEchoingDeviceLog();
  }
}

typedef ReloadSourcesHelper = Future<OperationResult> Function(
  HotRunner hotRunner,
  List<FlutterDevice> flutterDevices,
  bool pause,
  Map<String, dynamic> firstReloadDetails,
  String targetPlatform,
  String sdkName,
  bool emulator,
  String reason,
);

Future<OperationResult> _defaultReloadSourcesHelper(
  HotRunner hotRunner,
  List<FlutterDevice> flutterDevices,
  bool pause,
  Map<String, dynamic> firstReloadDetails,
  String targetPlatform,
  String sdkName,
  bool emulator,
  String reason,
) async {
  final Stopwatch vmReloadTimer = Stopwatch()..start();
  const String entryPath = 'main.dart.incremental.dill';
  final List<Future<DeviceReloadReport>> allReportsFutures = <Future<DeviceReloadReport>>[];

  for (final FlutterDevice device in flutterDevices) {
    final List<Future<vm_service.ReloadReport>> reportFutures = await _reloadDeviceSources(
      device,
      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(
          HotRunner.validateReloadReport(firstReport, printErrors: false),
        );
        return DeviceReloadReport(device, reports);
      },
    ));
  }
  final List<DeviceReloadReport> reports = await Future.wait(allReportsFutures);
  final vm_service.ReloadReport reloadReport = reports.first.reports[0];
  if (!HotRunner.validateReloadReport(reloadReport)) {
    // Reload failed.
    HotEvent('reload-reject',
      targetPlatform: targetPlatform,
      sdkName: sdkName,
      emulator: emulator,
      fullRestart: false,
      reason: reason,
      fastReassemble: false,
    ).send();
    // Reset devFS lastCompileTime to ensure the file will still be marked
    // as dirty on subsequent reloads.
    _resetDevFSCompileTime(flutterDevices);
    final ReloadReportContents contents = ReloadReportContents.fromReloadReport(reloadReport);
    return OperationResult(1, 'Reload rejected: ${contents.notices.join("\n")}');
  }
  // 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.addAll(castStringKeyedMap(reloadReport.json['details']));
  final Map<String, dynamic> details = reloadReport.json['details'] as Map<String, dynamic>;
  final int loadedLibraryCount = details['loadedLibraryCount'] as int;
  final int finalLibraryCount = details['finalLibraryCount'] as int;
  globals.printTrace('reloaded $loadedLibraryCount of $finalLibraryCount libraries');
  // reloadMessage = 'Reloaded $loadedLibraryCount of $finalLibraryCount libraries';
  // Record time it took for the VM to reload the sources.
  hotRunner._addBenchmarkData('hotReloadVMReloadMilliseconds', vmReloadTimer.elapsed.inMilliseconds);
  return OperationResult(0, 'Reloaded $loadedLibraryCount of $finalLibraryCount libraries');
}

Future<List<Future<vm_service.ReloadReport>>> _reloadDeviceSources(
  FlutterDevice device,
  String entryPath, {
  bool pause = false,
}) async {
  final String deviceEntryUri = device.devFS.baseUri
    .resolve(entryPath).toString();
  final vm_service.VM vm = await device.vmService.service.getVM();
  return <Future<vm_service.ReloadReport>>[
    for (final vm_service.IsolateRef isolateRef in vm.isolates)
      device.vmService.service.reloadSources(
        isolateRef.id,
        pause: pause,
        rootLibUri: deviceEntryUri,
      )
  ];
}

void _resetDevFSCompileTime(List<FlutterDevice> flutterDevices) {
  for (final FlutterDevice device in flutterDevices) {
    device.devFS.resetLastCompiled();
  }
}

@visibleForTesting
class ReassembleResult {
  ReassembleResult(this.reassembleViews, this.failedReassemble, this.shouldReportReloadTime);
  final Map<FlutterView, FlutterVmService> reassembleViews;
  final bool failedReassemble;
  final bool shouldReportReloadTime;
}

typedef ReassembleHelper = Future<ReassembleResult> Function(
  List<FlutterDevice> flutterDevices,
  Map<FlutterDevice, List<FlutterView>> viewCache,
  void Function(String message) onSlow,
  String reloadMessage,
  String fastReassembleClassName,
);

Future<ReassembleResult> _defaultReassembleHelper(
  List<FlutterDevice> flutterDevices,
  Map<FlutterDevice, List<FlutterView>> viewCache,
  void Function(String message) onSlow,
  String reloadMessage,
  String fastReassembleClassName,
) async {
  // Check if any isolates are paused and reassemble those that aren't.
  final Map<FlutterView, FlutterVmService> reassembleViews = <FlutterView, FlutterVmService>{};
  final List<Future<void>> reassembleFutures = <Future<void>>[];
  String serviceEventKind;
  int pausedIsolatesFound = 0;
  bool failedReassemble = false;
  bool shouldReportReloadTime = true;
  for (final FlutterDevice device in flutterDevices) {
    final List<FlutterView> views = viewCache[device];
    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;
        // If the tool identified a change in a single widget, do a fast instead
        // of a full reassemble.
        Future<void> reassembleWork;
        if (fastReassembleClassName != null) {
          reassembleWork = device.vmService.flutterFastReassemble(
            isolateId: view.uiIsolate.id,
            className: fastReassembleClassName,
          );
        } else {
          reassembleWork = device.vmService.flutterReassemble(
            isolateId: view.uiIsolate.id,
          );
        }
        reassembleFutures.add(reassembleWork.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 ReassembleResult(reassembleViews, failedReassemble, shouldReportReloadTime);
    }
  }
  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)}.');
      }
    },
  );
  return ReassembleResult(reassembleViews, failedReassemble, shouldReportReloadTime);
}

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();
}

/// 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: packageConfig,
        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>(
          // Calling fs.stat() is more performant than fs.file().stat(), but
          // uri.toFilePath() does not work with MultiRootFileSystem.
          () => (uri.hasScheme && uri.scheme != 'file'
            ? _fileSystem.file(uri).stat()
            :  _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) {
        // Calling fs.statSync() is more performant than fs.file().statSync(), but
        // uri.toFilePath() does not work with MultiRootFileSystem.
        final DateTime updatedAt = uri.hasScheme && uri.scheme != 'file'
          ? _fileSystem.file(uri).statSync().modified
          : _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 File packageFile = _fileSystem.file(packagesPath);
    final Uri packageUri = packageFile.uri;
    final DateTime updatedAt = packageFile.statSync().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(zanderso): 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(packagesPath),
      logger: _logger,
    );
  }
}

/// Additional serialization logic for a hot reload response.
class ReloadReportContents {
  factory ReloadReportContents.fromReloadReport(vm_service.ReloadReport report) {
    final List<ReasonForCancelling> reasons = <ReasonForCancelling>[];
    final Object notices = report.json['notices'];
    if (notices is! List<dynamic>) {
      return ReloadReportContents._(report.success, reasons, report);
    }
    for (final Object obj in notices as List<dynamic>) {
      if (obj is! Map<String, dynamic>) {
        continue;
      }
      final Map<String, dynamic> notice = obj as Map<String, dynamic>;
      reasons.add(ReasonForCancelling(
        message: notice['message'] is String
          ? notice['message'] as String
          : 'Unknown Error',
      ));
    }

    return ReloadReportContents._(report.success, reasons, report);
  }

  ReloadReportContents._(
    this.success,
    this.notices,
    this.report,
  );

  final bool success;
  final List<ReasonForCancelling> notices;
  final vm_service.ReloadReport report;
}

/// A serialization class for hot reload rejection reasons.
///
/// Injects an additional error message that a hot restart will
/// resolve the issue.
class ReasonForCancelling {
  ReasonForCancelling({
    this.message,
  });

  final String message;

  @override
  String toString() {
    return '$message.\nTry performing a hot restart instead.';
  }
}
