Support caching host filesystem symlink targets to speedup DevFS updates (#6798)

diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart
index bdcfc30..54e0c81 100644
--- a/packages/flutter_tools/lib/executable.dart
+++ b/packages/flutter_tools/lib/executable.dart
@@ -35,6 +35,7 @@
 import 'src/commands/trace.dart';
 import 'src/commands/update_packages.dart';
 import 'src/commands/upgrade.dart';
+import 'src/devfs.dart';
 import 'src/device.dart';
 import 'src/doctor.dart';
 import 'src/globals.dart';
@@ -83,6 +84,7 @@
     // Initialize globals.
     context[Logger] = new StdoutLogger();
     context[DeviceManager] = new DeviceManager();
+    context[DevFSConfig] = new DevFSConfig();
     Doctor.initGlobal();
 
     dynamic result = await runner.run(args);
diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart
index 1001232..0249075 100644
--- a/packages/flutter_tools/lib/src/devfs.dart
+++ b/packages/flutter_tools/lib/src/devfs.dart
@@ -8,6 +8,7 @@
 
 import 'package:path/path.dart' as path;
 
+import 'base/context.dart';
 import 'build_info.dart';
 import 'dart/package_map.dart';
 import 'asset.dart';
@@ -16,6 +17,13 @@
 
 typedef void DevFSProgressReporter(int progress, int max);
 
+class DevFSConfig {
+  /// Should DevFS assume that symlink targets are stable?
+  bool cacheSymlinks = false;
+}
+
+DevFSConfig get devFSConfig => context[DevFSConfig];
+
 // A file that has been added to a DevFS.
 class DevFSEntry {
   DevFSEntry(this.devicePath, this.file)
@@ -30,10 +38,13 @@
   String get assetPath => bundleEntry.archivePath;
 
   final FileSystemEntity file;
+  FileSystemEntity _linkTarget;
   FileStat _fileStat;
   // When we scanned for files, did this still exist?
   bool _exists = false;
   DateTime get lastModified => _fileStat?.modified;
+  bool get _isSourceEntry => file == null;
+  bool get _isAssetEntry => bundleEntry != null;
   bool get stillExists {
     if (_isSourceEntry)
       return true;
@@ -67,19 +78,28 @@
   void _stat() {
     if (_isSourceEntry)
       return;
+    if (_linkTarget != null) {
+      // Stat the cached symlink target.
+      _fileStat = _linkTarget.statSync();
+      return;
+    }
     _fileStat = file.statSync();
     if (_fileStat.type == FileSystemEntityType.LINK) {
-      // Stat the link target.
+      // Resolve, stat, and maybe cache the symlink target.
       String resolved = file.resolveSymbolicLinksSync();
-      _fileStat = FileStat.statSync(resolved);
+      FileSystemEntity linkTarget = new File(resolved);
+      // Stat the link target.
+      _fileStat = linkTarget.statSync();
+      if (devFSConfig.cacheSymlinks) {
+        _linkTarget = linkTarget;
+      }
     }
   }
 
-  bool get _isSourceEntry => file == null;
-
-  bool get _isAssetEntry => bundleEntry != null;
-
   File _getFile() {
+    if (_linkTarget != null) {
+      return _linkTarget;
+    }
     if (file is Link) {
       // The link target.
       return new File(file.resolveSymbolicLinksSync());