// 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_null_migrated.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 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,
    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;

  /// 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 '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(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,
    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,
            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: null,
      fastReassemble: null,
      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(success: false);
      }
    }

    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();
    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)) {
            // 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. Instead, all breakpoints are first
            // disabled and then the isolate resumed.
            final List<Future<void>> breakpointRemoval = <Future<void>>[
              for (final vm_service.Breakpoint breakpoint in isolate.breakpoints)
                device.vmService.service.removeBreakpoint(isolate.id, breakpoint.id)
            ];
            await Future.wait(breakpointRemoval);
            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: null,
          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: null,
        ).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: null,
        ).send();
      } else {
        HotEvent('exception',
          targetPlatform: targetPlatform,
          sdkName: sdkName,
          emulator: emulator,
          fullRestart: false,
          reason: reason,
          fastReassemble: null,
        ).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();
    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 = '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: null,
    ).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(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(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.';
  }
}
