Move TimestampGranularityMonitor to CommandEnvironment.

This is one of the last pieces of state in BlazeRuntime that isn't safe to
share across command invocations.

--
MOS_MIGRATED_REVID=117910631
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index 76b182a..422e289 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -209,16 +209,10 @@
    */
   int exec(List<String> args, OutErr outErr, long firstContactTime)
       throws ShutdownBlazeServerException {
-    // Record the start time for the profiler and the timestamp granularity monitor. Do not put
-    // anything before this!
+    // Record the start time for the profiler. Do not put anything before this!
     long execStartTimeNanos = runtime.getClock().nanoTime();
 
-    // Record the command's starting time again, for use by
-    // TimestampGranularityMonitor.waitForTimestampGranularity().
-    // This should be done as close as possible to the start of
-    // the command's execution - that's why we do this separately,
-    // rather than in runtime.beforeCommand().
-    runtime.getTimestampGranularityMonitor().setCommandStartTime();
+    // The initCommand call also records the start time for the timestamp granularity monitor.
     CommandEnvironment env = runtime.initCommand();
     // Record the command's starting time for use by the commands themselves.
     env.recordCommandStartTime(firstContactTime);
@@ -400,7 +394,7 @@
         reporter.removeHandler(ansiAllowingHandler);
         releaseHandler(ansiAllowingHandler);
       }
-      runtime.getTimestampGranularityMonitor().waitForTimestampGranularity(outErr);
+      env.getTimestampGranularityMonitor().waitForTimestampGranularity(outErr);
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index e1e82f8..c28b697 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -92,7 +92,6 @@
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.ThreadUtils;
 import com.google.devtools.build.lib.util.io.OutErr;
-import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.JavaIoFileSystem;
@@ -159,7 +158,6 @@
   private final PackageFactory packageFactory;
   private final ConfigurationFactory configurationFactory;
   private final ConfiguredRuleClassProvider ruleClassProvider;
-  private final TimestampGranularityMonitor timestampGranularityMonitor;
 
   private final AtomicInteger storedExitCode = new AtomicInteger();
 
@@ -190,7 +188,6 @@
       PackageFactory pkgFactory, ConfiguredRuleClassProvider ruleClassProvider,
       ConfigurationFactory configurationFactory, Clock clock,
       OptionsProvider startupOptionsProvider, Iterable<BlazeModule> blazeModules,
-      TimestampGranularityMonitor timestampGranularityMonitor,
       SubscriberExceptionHandler eventBusExceptionHandler,
       BinTools binTools, ProjectFile.Provider projectFileProvider,
       InvocationPolicy invocationPolicy, Iterable<BlazeCommand> commands) {
@@ -207,7 +204,6 @@
     this.ruleClassProvider = ruleClassProvider;
     this.configurationFactory = configurationFactory;
     this.clock = clock;
-    this.timestampGranularityMonitor = Preconditions.checkNotNull(timestampGranularityMonitor);
     this.startupOptionsProvider = startupOptionsProvider;
     this.eventBusExceptionHandler = eventBusExceptionHandler;
     this.queryEnvironmentFactory = queryEnvironmentFactory;
@@ -578,15 +574,6 @@
   }
 
   /**
-   * Returns the TimestampGranularityMonitor. The same monitor object is used
-   * across multiple Blaze commands, but it doesn't hold any persistent state
-   * across different commands.
-   */
-  public TimestampGranularityMonitor getTimestampGranularityMonitor() {
-    return timestampGranularityMonitor;
-  }
-
-  /**
    * Returns path to the cache directory. Path must be inside output base to
    * ensure that users can run concurrent instances of blaze in different
    * clients without attempting to concurrently write to the same action cache
@@ -1342,7 +1329,6 @@
       UUID instanceId =  (this.instanceId == null) ? UUID.randomUUID() : this.instanceId;
 
       Preconditions.checkNotNull(clock);
-      TimestampGranularityMonitor timestampMonitor = new TimestampGranularityMonitor(clock);
 
       Preprocessor.Factory.Supplier preprocessorFactorySupplier = null;
       SkyframeExecutorFactory skyframeExecutorFactory = null;
@@ -1466,7 +1452,6 @@
       SkyframeExecutor skyframeExecutor =
           skyframeExecutorFactory.create(
               pkgFactory,
-              timestampMonitor,
               directories,
               binTools,
               workspaceStatusActionFactory,
@@ -1499,8 +1484,7 @@
       return new BlazeRuntime(directories, workspaceStatusActionFactory, skyframeExecutor,
           queryEnvironmentFactory, pkgFactory, ruleClassProvider, configurationFactory,
           clock, startupOptionsProvider, ImmutableList.copyOf(blazeModules),
-          timestampMonitor, eventBusExceptionHandler, binTools, projectFileProvider,
-          invocationPolicy, commands);
+          eventBusExceptionHandler, binTools, projectFileProvider, invocationPolicy, commands);
     }
 
     public Builder setBinTools(BinTools binTools) {
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
index 952b71e..f0dc73c 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
@@ -46,6 +46,7 @@
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.util.Preconditions;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -77,6 +78,7 @@
   private final EventBus eventBus;
   private final BlazeModule.ModuleEnvironment blazeModuleEnvironment;
   private final Map<String, String> clientEnv = new HashMap<>();
+  private final TimestampGranularityMonitor timestampGranularityMonitor;
 
   private final BuildView view;
 
@@ -110,6 +112,12 @@
     this.reporter = new Reporter();
     this.eventBus = eventBus;
     this.blazeModuleEnvironment = new BlazeModuleEnvironment();
+    this.timestampGranularityMonitor = new TimestampGranularityMonitor(runtime.getClock());
+    // Record the command's starting time again, for use by
+    // TimestampGranularityMonitor.waitForTimestampGranularity().
+    // This should be done as close as possible to the start of
+    // the command's execution.
+    timestampGranularityMonitor.setCommandStartTime();
 
     this.view = new BuildView(runtime.getDirectories(), runtime.getRuleClassProvider(),
         runtime.getSkyframeExecutor(), runtime.getCoverageReportActionFactory());
@@ -161,6 +169,10 @@
     }
   }
 
+  public TimestampGranularityMonitor getTimestampGranularityMonitor() {
+    return timestampGranularityMonitor;
+  }
+
   public PackageManager getPackageManager() {
     return runtime.getPackageManager();
   }
@@ -297,7 +309,8 @@
       skyframeExecutor.resetEvaluator();
     }
     skyframeExecutor.sync(reporter, packageCacheOptions, runtime.getOutputBase(),
-        getWorkingDirectory(), defaultsPackageContents, commandId);
+        getWorkingDirectory(), defaultsPackageContents, commandId,
+        timestampGranularityMonitor);
   }
 
   public void recordLastExecutionTime() {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
index ba4c70a..963fe1d 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
@@ -59,6 +59,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Level;
 
 import javax.annotation.Nullable;
@@ -78,11 +79,11 @@
  */
 public class ActionExecutionFunction implements SkyFunction, CompletionReceiver {
   private final SkyframeActionExecutor skyframeActionExecutor;
-  private final TimestampGranularityMonitor tsgm;
+  private final AtomicReference<TimestampGranularityMonitor> tsgm;
   private ConcurrentMap<Action, ContinuationState> stateMap;
 
   public ActionExecutionFunction(SkyframeActionExecutor skyframeActionExecutor,
-      TimestampGranularityMonitor tsgm) {
+      AtomicReference<TimestampGranularityMonitor> tsgm) {
     this.skyframeActionExecutor = skyframeActionExecutor;
     this.tsgm = tsgm;
     stateMap = Maps.newConcurrentMap();
@@ -334,7 +335,7 @@
     }
     // This may be recreated if we discover inputs.
     ActionMetadataHandler metadataHandler = new ActionMetadataHandler(state.inputArtifactData,
-        action.getOutputs(), tsgm);
+        action.getOutputs(), tsgm.get());
     long actionStartTime = System.nanoTime();
     // We only need to check the action cache if we haven't done it on a previous run.
     if (!state.hasCheckedActionCache()) {
@@ -376,7 +377,7 @@
           state.inputArtifactData = inputArtifactData;
           perActionFileCache = new PerActionFileCache(state.inputArtifactData);
           metadataHandler =
-              new ActionMetadataHandler(state.inputArtifactData, action.getOutputs(), tsgm);
+              new ActionMetadataHandler(state.inputArtifactData, action.getOutputs(), tsgm.get());
         }
       }
       actionExecutionContext =
@@ -414,7 +415,7 @@
           inputArtifactData.putAll(metadataFoundDuringActionExecution);
           state.inputArtifactData = inputArtifactData;
           metadataHandler =
-              new ActionMetadataHandler(state.inputArtifactData, action.getOutputs(), tsgm);
+              new ActionMetadataHandler(state.inputArtifactData, action.getOutputs(), tsgm.get());
         }
       } else if (!metadataFoundDuringActionExecution.isEmpty()) {
         // The action has run and discovered more inputs. This is a bug, probably the result of
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java
index 0f2fb63..cf8f668 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionMetadataHandler.java
@@ -568,7 +568,7 @@
 
   @VisibleForTesting
   static FileValue fileValueFromArtifactFile(ArtifactFile file,
-      @Nullable FileStatusWithDigest statNoFollow, TimestampGranularityMonitor tsgm)
+      @Nullable FileStatusWithDigest statNoFollow, @Nullable TimestampGranularityMonitor tsgm)
       throws IOException {
     Path path = file.getPath();
     RootedPath rootedPath =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java
index 3e10330..d77f7e3 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateFunction.java
@@ -21,6 +21,7 @@
 import com.google.devtools.build.skyframe.SkyValue;
 
 import java.io.IOException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * A {@link SkyFunction} for {@link FileStateValue}s.
@@ -30,10 +31,10 @@
  */
 public class FileStateFunction implements SkyFunction {
 
-  private final TimestampGranularityMonitor tsgm;
+  private final AtomicReference<TimestampGranularityMonitor> tsgm;
   private final ExternalFilesHelper externalFilesHelper;
 
-  public FileStateFunction(TimestampGranularityMonitor tsgm,
+  public FileStateFunction(AtomicReference<TimestampGranularityMonitor> tsgm,
       ExternalFilesHelper externalFilesHelper) {
     this.tsgm = tsgm;
     this.externalFilesHelper = externalFilesHelper;
@@ -48,7 +49,7 @@
       if (env.valuesMissing()) {
         return null;
       }
-      return FileStateValue.create(rootedPath, tsgm);
+      return FileStateValue.create(rootedPath, tsgm.get());
     } catch (FileOutsidePackageRootsException e) {
       throw new FileStateFunctionException(e);
     } catch (IOException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java b/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
index 833306d..63a3800 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
@@ -371,8 +371,7 @@
       FileValue lastKnownData = entry.getValue();
       if (shouldCheckFile(knownModifiedOutputFiles, file)) {
         try {
-          FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(file, null,
-              tsgm);
+          FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(file, null, tsgm);
           if (!fileValue.equals(lastKnownData)) {
             updateIntraBuildModifiedCounter(fileValue.exists()
                 ? fileValue.realRootedPath().asPath().getLastModifiedTime()
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index 3b393a9b..0a612f8 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -100,7 +100,6 @@
   private SequencedSkyframeExecutor(
       EvaluatorSupplier evaluatorSupplier,
       PackageFactory pkgFactory,
-      TimestampGranularityMonitor tsgm,
       BlazeDirectories directories,
       BinTools binTools,
       Factory workspaceStatusActionFactory,
@@ -114,7 +113,6 @@
     super(
         evaluatorSupplier,
         pkgFactory,
-        tsgm,
         directories,
         binTools,
         workspaceStatusActionFactory,
@@ -130,7 +128,6 @@
 
   public static SequencedSkyframeExecutor create(
       PackageFactory pkgFactory,
-      TimestampGranularityMonitor tsgm,
       BlazeDirectories directories,
       BinTools binTools,
       Factory workspaceStatusActionFactory,
@@ -145,7 +142,6 @@
         new SequencedSkyframeExecutor(
             InMemoryMemoizingEvaluator.SUPPLIER,
             pkgFactory,
-            tsgm,
             directories,
             binTools,
             workspaceStatusActionFactory,
@@ -162,13 +158,12 @@
 
   @VisibleForTesting
   public static SequencedSkyframeExecutor create(PackageFactory pkgFactory,
-      TimestampGranularityMonitor tsgm, BlazeDirectories directories, BinTools binTools,
+      BlazeDirectories directories, BinTools binTools,
       WorkspaceStatusAction.Factory workspaceStatusActionFactory,
       ImmutableList<BuildInfoFactory> buildInfoFactories,
       Iterable<? extends DiffAwareness.Factory> diffAwarenessFactories) {
     return create(
         pkgFactory,
-        tsgm,
         directories,
         binTools,
         workspaceStatusActionFactory,
@@ -217,11 +212,12 @@
 
   @Override
   public void sync(EventHandler eventHandler, PackageCacheOptions packageCacheOptions,
-      Path outputBase, Path workingDirectory, String defaultsPackageContents, UUID commandId)
+      Path outputBase, Path workingDirectory, String defaultsPackageContents, UUID commandId,
+      TimestampGranularityMonitor tsgm)
           throws InterruptedException, AbruptExitException {
     this.valueCacheEvictionLimit = packageCacheOptions.minLoadedPkgCountForCtNodeEviction;
     super.sync(eventHandler, packageCacheOptions, outputBase, workingDirectory,
-        defaultsPackageContents, commandId);
+        defaultsPackageContents, commandId, tsgm);
     handleDiffs(eventHandler);
   }
 
@@ -283,6 +279,7 @@
       dropConfiguredTargetsNow(eventHandler);
       lastAnalysisDiscarded = false;
     }
+    TimestampGranularityMonitor tsgm = this.tsgm.get();
     modifiedFiles = 0;
     Map<Path, DiffAwarenessManager.ProcessableModifiedFileSet> modifiedFilesByPathEntry =
         Maps.newHashMap();
@@ -297,8 +294,8 @@
         modifiedFilesByPathEntry.put(pathEntry, modifiedFileSet);
       }
     }
-    handleDiffsWithCompleteDiffInformation(modifiedFilesByPathEntry);
-    handleDiffsWithMissingDiffInformation(eventHandler, pathEntriesWithoutDiffInformation);
+    handleDiffsWithCompleteDiffInformation(tsgm, modifiedFilesByPathEntry);
+    handleDiffsWithMissingDiffInformation(eventHandler, tsgm, pathEntriesWithoutDiffInformation);
   }
 
   /**
@@ -306,7 +303,7 @@
    * diff. Removes entries from the given map as they are processed. All of the files need to be
    * invalidated, so the map should be empty upon completion of this function.
    */
-  private void handleDiffsWithCompleteDiffInformation(
+  private void handleDiffsWithCompleteDiffInformation(TimestampGranularityMonitor tsgm,
       Map<Path, DiffAwarenessManager.ProcessableModifiedFileSet> modifiedFilesByPathEntry)
           throws InterruptedException {
     for (Path pathEntry : ImmutableSet.copyOf(modifiedFilesByPathEntry.keySet())) {
@@ -315,7 +312,7 @@
       ModifiedFileSet modifiedFileSet = processableModifiedFileSet.getModifiedFileSet();
       Preconditions.checkState(!modifiedFileSet.treatEverythingAsModified(), pathEntry);
       handleChangedFiles(ImmutableList.of(pathEntry),
-          getDiff(modifiedFileSet.modifiedSourceFiles(), pathEntry));
+          getDiff(tsgm, modifiedFileSet.modifiedSourceFiles(), pathEntry));
       processableModifiedFileSet.markProcessed();
     }
   }
@@ -325,6 +322,7 @@
    * {@link DiffAwareness} said all files may have been modified.
    */
   private void handleDiffsWithMissingDiffInformation(EventHandler eventHandler,
+      TimestampGranularityMonitor tsgm,
       Set<Pair<Path, DiffAwarenessManager.ProcessableModifiedFileSet>>
           pathEntriesWithoutDiffInformation) throws InterruptedException {
     if (pathEntriesWithoutDiffInformation.isEmpty()
@@ -447,12 +445,13 @@
       dropConfiguredTargetsNow(eventHandler);
       lastAnalysisDiscarded = false;
     }
+    TimestampGranularityMonitor tsgm = this.tsgm.get();
     Differencer.Diff diff;
     if (modifiedFileSet.treatEverythingAsModified()) {
       diff = new FilesystemValueChecker(tsgm, null).getDirtyKeys(memoizingEvaluator.getValues(),
           new BasicFilesystemDirtinessChecker());
     } else {
-      diff = getDiff(modifiedFileSet.modifiedSourceFiles(), pathEntry);
+      diff = getDiff(tsgm, modifiedFileSet.modifiedSourceFiles(), pathEntry);
     }
     syscalls.set(newPerBuildSyscallCache(/*concurrencyLevel=*/42));
     recordingDiffer.invalidate(diff.changedKeysWithoutNewValues());
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
index 5b6484d..3dbeb2e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
@@ -22,7 +22,6 @@
 import com.google.devtools.build.lib.analysis.config.BinTools;
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.Preprocessor;
-import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunctionName;
@@ -35,7 +34,6 @@
   @Override
   public SkyframeExecutor create(
       PackageFactory pkgFactory,
-      TimestampGranularityMonitor tsgm,
       BlazeDirectories directories,
       BinTools binTools,
       Factory workspaceStatusActionFactory,
@@ -48,7 +46,6 @@
       Iterable<SkyValueDirtinessChecker> customDirtinessCheckers) {
     return SequencedSkyframeExecutor.create(
         pkgFactory,
-        tsgm,
         directories,
         binTools,
         workspaceStatusActionFactory,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 7bcb2e3..c215411 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -215,6 +215,8 @@
   protected final AtomicReference<ImmutableSet<PackageIdentifier>> deletedPackages =
       new AtomicReference<>(ImmutableSet.<PackageIdentifier>of());
   private final AtomicReference<EventBus> eventBus = new AtomicReference<>();
+  protected final AtomicReference<TimestampGranularityMonitor> tsgm =
+      new AtomicReference<>();
 
   private final ImmutableList<BuildInfoFactory> buildInfoFactories;
   // Under normal circumstances, the artifact factory persists for the life of a Blaze server, but
@@ -233,8 +235,6 @@
   private final Preprocessor.Factory.Supplier preprocessorFactorySupplier;
   private Preprocessor.Factory preprocessorFactory;
 
-  protected final TimestampGranularityMonitor tsgm;
-
   private final ResourceManager resourceManager;
 
   /** Used to lock evaluator on legacy calls to get existing values. */
@@ -270,7 +270,6 @@
   protected SkyframeExecutor(
       EvaluatorSupplier evaluatorSupplier,
       PackageFactory pkgFactory,
-      TimestampGranularityMonitor tsgm,
       BlazeDirectories directories,
       BinTools binTools,
       Factory workspaceStatusActionFactory,
@@ -285,7 +284,6 @@
     this.evaluatorSupplier = evaluatorSupplier;
     this.pkgFactory = pkgFactory;
     this.pkgFactory.setSyscalls(syscalls);
-    this.tsgm = tsgm;
     this.workspaceStatusActionFactory = workspaceStatusActionFactory;
     this.packageManager = new SkyframePackageManager(
         new SkyframePackageLoader(), new SkyframeTransitivePackageLoader(),
@@ -804,8 +802,9 @@
         || (oldType.equals(Dirent.Type.SYMLINK) && newType.equals(FileStateValue.Type.SYMLINK));
   }
 
-  protected Differencer.Diff getDiff(Iterable<PathFragment> modifiedSourceFiles,
-      final Path pathEntry) throws InterruptedException {
+  protected Differencer.Diff getDiff(TimestampGranularityMonitor tsgm,
+      Iterable<PathFragment> modifiedSourceFiles, final Path pathEntry)
+          throws InterruptedException {
     if (Iterables.isEmpty(modifiedSourceFiles)) {
       return new ImmutableDiff(ImmutableList.<SkyKey>of(), ImmutableMap.<SkyKey, SkyValue>of());
     }
@@ -901,10 +900,13 @@
   @VisibleForTesting  // productionVisibility = Visibility.PRIVATE
   public void preparePackageLoading(PathPackageLocator pkgLocator, RuleVisibility defaultVisibility,
                                     boolean showLoadingProgress, int globbingThreads,
-                                    String defaultsPackageContents, UUID commandId) {
+                                    String defaultsPackageContents, UUID commandId,
+                                    TimestampGranularityMonitor tsgm) {
     Preconditions.checkNotNull(pkgLocator);
+    Preconditions.checkNotNull(tsgm);
     setActive(true);
 
+    this.tsgm.set(tsgm);
     maybeInjectPrecomputedValuesForAnalysis();
     setCommandId(commandId);
     setBlacklistedPackagePrefixesFile(getBlacklistedPackagePrefixesFile());
@@ -1358,11 +1360,6 @@
    */
   public abstract void invalidateTransientErrors();
 
-  @VisibleForTesting
-  public TimestampGranularityMonitor getTimestampGranularityMonitorForTesting() {
-    return tsgm;
-  }
-
   /** Configures a given set of configured targets. */
   public EvaluationResult<ActionLookupValue> configureTargets(
       EventHandler eventHandler,
@@ -1592,16 +1589,15 @@
   public abstract void updateLoadedPackageSet(Set<PackageIdentifier> loadedPackages);
 
   public void sync(EventHandler eventHandler, PackageCacheOptions packageCacheOptions,
-      Path outputBase, Path workingDirectory, String defaultsPackageContents, UUID commandId)
-          throws InterruptedException,
-      AbruptExitException{
-
+      Path outputBase, Path workingDirectory, String defaultsPackageContents, UUID commandId,
+      TimestampGranularityMonitor tsgm)
+          throws InterruptedException, AbruptExitException{
     preparePackageLoading(
         createPackageLocator(
             eventHandler, packageCacheOptions, outputBase, directories.getWorkspace(),
             workingDirectory),
         packageCacheOptions.defaultVisibility, packageCacheOptions.showLoadingProgress,
-        packageCacheOptions.globbingThreads, defaultsPackageContents, commandId);
+        packageCacheOptions.globbingThreads, defaultsPackageContents, commandId, tsgm);
     setDeletedPackages(packageCacheOptions.getDeletedPackages());
 
     incrementalBuildMonitor = new SkyframeIncrementalBuildMonitor();
@@ -1643,12 +1639,13 @@
   }
 
   public void prepareExecution(ModifiedFileSet modifiedOutputFiles,
-      @Nullable Range<Long> lastExecutionTimeRange) throws AbruptExitException,
-      InterruptedException {
+      @Nullable Range<Long> lastExecutionTimeRange)
+          throws AbruptExitException, InterruptedException {
     maybeInjectEmbeddedArtifacts();
 
     // Detect external modifications in the output tree.
-    FilesystemValueChecker fsvc = new FilesystemValueChecker(tsgm, lastExecutionTimeRange);
+    FilesystemValueChecker fsvc =
+        new FilesystemValueChecker(Preconditions.checkNotNull(tsgm.get()), lastExecutionTimeRange);
     BatchStat batchStatter = outputService == null ? null : outputService.getBatchStatter();
     invalidateDirtyActions(fsvc.getDirtyActionValues(memoizingEvaluator.getValues(),
         batchStatter, modifiedOutputFiles));
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java
index ddfdd23..8e3cea4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java
@@ -23,7 +23,6 @@
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.Preprocessor;
 import com.google.devtools.build.lib.util.AbruptExitException;
-import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunctionName;
@@ -53,7 +52,6 @@
    */
   SkyframeExecutor create(
       PackageFactory pkgFactory,
-      TimestampGranularityMonitor tsgm,
       BlazeDirectories directories,
       BinTools binTools,
       Factory workspaceStatusActionFactory,
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
index 4d16cec..241f7a6 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
@@ -159,7 +159,6 @@
     skyframeExecutor =
         SequencedSkyframeExecutor.create(
             pkgFactory,
-            new TimestampGranularityMonitor(BlazeClock.instance()),
             directories,
             binTools,
             workspaceStatusActionFactory,
@@ -172,7 +171,8 @@
             ImmutableList.<SkyValueDirtinessChecker>of());
     skyframeExecutor.preparePackageLoading(pkgLocator,
         Options.getDefaults(PackageCacheOptions.class).defaultVisibility, true,
-        3, ruleClassProvider.getDefaultsPackageContent(), UUID.randomUUID());
+        3, ruleClassProvider.getDefaultsPackageContent(), UUID.randomUUID(),
+        new TimestampGranularityMonitor(BlazeClock.instance()));
     packageManager = skyframeExecutor.getPackageManager();
     loadingPhaseRunner = skyframeExecutor.getLoadingPhaseRunner(
         pkgFactory.getRuleClassNames(), defaultFlags().contains(Flag.SKYFRAME_LOADING_PHASE));
@@ -253,7 +253,8 @@
         outputBase, packageCacheOptions.packagePath, reporter, rootDirectory, rootDirectory);
     skyframeExecutor.preparePackageLoading(pathPackageLocator,
         packageCacheOptions.defaultVisibility, true,
-        7, ruleClassProvider.getDefaultsPackageContent(), UUID.randomUUID());
+        7, ruleClassProvider.getDefaultsPackageContent(), UUID.randomUUID(),
+        new TimestampGranularityMonitor(BlazeClock.instance()));
     skyframeExecutor.invalidateFilesUnderPathForTesting(reporter,
         ModifiedFileSet.EVERYTHING_MODIFIED, rootDirectory);
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
index 7ad0832..96c8ffd 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
@@ -170,6 +170,7 @@
 
   private SequencedSkyframeExecutor skyframeExecutor;
 
+  protected TimestampGranularityMonitor tsgm;
   protected BlazeDirectories directories;
   protected BinTools binTools;
 
@@ -203,10 +204,10 @@
     mutableActionGraph = new MapBasedActionGraph();
     ruleClassProvider = getRuleClassProvider();
     pkgFactory = new PackageFactory(ruleClassProvider, getEnvironmentExtensions());
+    tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
     skyframeExecutor =
         SequencedSkyframeExecutor.create(
             pkgFactory,
-            new TimestampGranularityMonitor(BlazeClock.instance()),
             directories,
             binTools,
             workspaceStatusActionFactory,
@@ -220,7 +221,7 @@
     skyframeExecutor.preparePackageLoading(
         new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
         ConstantRuleVisibility.PUBLIC, true, 7, "",
-        UUID.randomUUID());
+        UUID.randomUUID(), tsgm);
     useConfiguration();
     setUpSkyframe();
     // Also initializes ResourceManager.
@@ -311,7 +312,7 @@
     skyframeExecutor.preparePackageLoading(pkgLocator,
         packageCacheOptions.defaultVisibility, true,
         7, ruleClassProvider.getDefaultsPackageContent(optionsParser),
-        UUID.randomUUID());
+        UUID.randomUUID(), tsgm);
     skyframeExecutor.setDeletedPackages(ImmutableSet.copyOf(packageCacheOptions.getDeletedPackages()));
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/ConfigurationTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/ConfigurationTestCase.java
index 654f838..5b86f88 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/ConfigurationTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/ConfigurationTestCase.java
@@ -101,7 +101,6 @@
     skyframeExecutor =
         SequencedSkyframeExecutor.create(
             pkgFactory,
-            new TimestampGranularityMonitor(BlazeClock.instance()),
             directories,
             BinTools.forUnitTesting(directories, TestConstants.EMBEDDED_TOOLS),
             workspaceStatusActionFactory,
@@ -115,7 +114,8 @@
 
     skyframeExecutor.preparePackageLoading(pkgLocator,
         Options.getDefaults(PackageCacheOptions.class).defaultVisibility, true,
-        7, ruleClassProvider.getDefaultsPackageContent(), UUID.randomUUID());
+        7, ruleClassProvider.getDefaultsPackageContent(), UUID.randomUUID(),
+        new TimestampGranularityMonitor(BlazeClock.instance()));
 
     analysisMock.setupMockClient(new MockToolsConfig(rootDirectory));
     analysisMock.setupMockWorkspaceFiles(directories.getEmbeddedBinariesRoot());
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java b/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java
index d97eadb..be3709d 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java
@@ -23,7 +23,6 @@
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
-import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
@@ -85,7 +84,7 @@
       ruleClassProvider = TestRuleClassProvider.getRuleClassProvider();
     }
     skyframeExecutor = createSkyframeExecutor(getEnvironmentExtensions(),
-        Preprocessor.Factory.Supplier.NullSupplier.INSTANCE, ConstantRuleVisibility.PUBLIC, "");
+        getPreprocessorFactorySupplier());
     setUpSkyframe(parsePackageCacheOptions());
   }
 
@@ -94,15 +93,12 @@
     return ImmutableList.of();
   }
 
-  protected SkyframeExecutor createSkyframeExecutor(
+  private SkyframeExecutor createSkyframeExecutor(
       Iterable<EnvironmentExtension> environmentExtensions,
-      Preprocessor.Factory.Supplier preprocessorFactorySupplier,
-      RuleVisibility defaultVisibility,
-      String defaultsPackageContents) {
+      Preprocessor.Factory.Supplier preprocessorFactorySupplier) {
     SkyframeExecutor skyframeExecutor =
         SequencedSkyframeExecutor.create(
             new PackageFactory(ruleClassProvider, environmentExtensions),
-            new TimestampGranularityMonitor(BlazeClock.instance()),
             new BlazeDirectories(outputBase, outputBase, rootDirectory),
             null, /* BinTools */
             null, /* workspaceStatusActionFactory */
@@ -113,10 +109,6 @@
             ImmutableMap.<SkyFunctionName, SkyFunction>of(),
             ImmutableList.<PrecomputedValue.Injected>of(),
             ImmutableList.<SkyValueDirtinessChecker>of());
-    skyframeExecutor.preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        defaultVisibility, true, GLOBBING_THREADS, defaultsPackageContents,
-        UUID.randomUUID());
     return skyframeExecutor;
   }
 
@@ -124,13 +116,24 @@
     return ImmutableList.<EnvironmentExtension>of();
   }
 
+  protected Preprocessor.Factory.Supplier getPreprocessorFactorySupplier() {
+    return Preprocessor.Factory.Supplier.NullSupplier.INSTANCE;
+  }
+
+  protected void setUpSkyframe(RuleVisibility defaultVisibility, String defaultsPackageContents) {
+    skyframeExecutor.preparePackageLoading(
+        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
+        defaultVisibility, true, GLOBBING_THREADS, defaultsPackageContents,
+        UUID.randomUUID(), new TimestampGranularityMonitor(BlazeClock.instance()));
+  }
+
   private void setUpSkyframe(PackageCacheOptions packageCacheOptions) {
     PathPackageLocator pkgLocator = PathPackageLocator.create(
         outputBase, packageCacheOptions.packagePath, reporter, rootDirectory, rootDirectory);
     skyframeExecutor.preparePackageLoading(pkgLocator,
         packageCacheOptions.defaultVisibility, true,
-        7, ruleClassProvider.getDefaultsPackageContent(),
-        UUID.randomUUID());
+        GLOBBING_THREADS, ruleClassProvider.getDefaultsPackageContent(),
+        UUID.randomUUID(), new TimestampGranularityMonitor(BlazeClock.instance()));
     skyframeExecutor.setDeletedPackages(ImmutableSet.copyOf(packageCacheOptions.getDeletedPackages()));
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java
index 766b85b..cf5d36e 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java
@@ -15,7 +15,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
@@ -23,11 +22,8 @@
 import com.google.devtools.build.lib.events.DelegatingEventHandler;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
-import com.google.devtools.build.lib.packages.PackageFactory;
-import com.google.devtools.build.lib.packages.Preprocessor;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
-import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
 import com.google.devtools.build.lib.util.Pair;
 
 import org.junit.Before;
@@ -45,7 +41,6 @@
  * be extracted here if they are needed by other classes.
  */
 public abstract class AbstractTargetPatternEvaluatorTest extends PackageLoadingTestCase {
-  protected SkyframeExecutor skyframeExecutor;
   protected TargetPatternEvaluator parser;
   protected RecordingParsingListener parsingListener;
 
@@ -78,10 +73,7 @@
 
   @Before
   public final void initializeParser() throws Exception {
-    skyframeExecutor =
-        super.createSkyframeExecutor(ImmutableList.<PackageFactory.EnvironmentExtension>of(),
-            Preprocessor.Factory.Supplier.NullSupplier.INSTANCE, ConstantRuleVisibility.PRIVATE,
-            ruleClassProvider.getDefaultsPackageContent());
+    setUpSkyframe(ConstantRuleVisibility.PRIVATE, ruleClassProvider.getDefaultsPackageContent());
     parser = skyframeExecutor.getPackageManager().newTargetPatternEvaluator();
     parsingListener = new RecordingParsingListener(reporter);
   }
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/IOExceptionsTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/IOExceptionsTest.java
index 3aa1935..034d22b 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/IOExceptionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/IOExceptionsTest.java
@@ -18,15 +18,11 @@
 import static org.junit.Assert.assertTrue;
 
 import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
-import com.google.devtools.build.lib.packages.PackageFactory;
-import com.google.devtools.build.lib.packages.Preprocessor;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
-import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
 import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import com.google.devtools.build.lib.vfs.FileSystem;
@@ -65,14 +61,9 @@
 
   private Function<Path, String> crashMessage = NULL_FUNCTION;
 
-  private SkyframeExecutor skyframeExecutor;
-
   @Before
   public final void initializeVisitor() throws Exception {
-    skyframeExecutor =
-        super.createSkyframeExecutor(ImmutableList.<PackageFactory.EnvironmentExtension>of(),
-            Preprocessor.Factory.Supplier.NullSupplier.INSTANCE, ConstantRuleVisibility.PRIVATE,
-            ruleClassProvider.getDefaultsPackageContent());
+    setUpSkyframe(ConstantRuleVisibility.PRIVATE, ruleClassProvider.getDefaultsPackageContent());
     this.visitor = skyframeExecutor.pkgLoader();
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
index 2cebe83..053c5eb 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
@@ -468,7 +468,6 @@
       skyframeExecutor =
           SequencedSkyframeExecutor.create(
               new PackageFactory(TestRuleClassProvider.getRuleClassProvider()),
-              new TimestampGranularityMonitor(BlazeClock.instance()),
               new BlazeDirectories(fs.getPath("/install"), fs.getPath("/output"), workspace),
               null, /* BinTools */
               null, /* workspaceStatusActionFactory */
@@ -482,7 +481,7 @@
       skyframeExecutor.preparePackageLoading(
           new PathPackageLocator(outputBase, ImmutableList.of(workspace)),
           ConstantRuleVisibility.PUBLIC, true, 7, "",
-          UUID.randomUUID());
+          UUID.randomUUID(), new TimestampGranularityMonitor(BlazeClock.instance()));
     }
 
     Path addFile(String fileName, String... content) throws IOException {
@@ -561,7 +560,7 @@
       skyframeExecutor.preparePackageLoading(
           new PathPackageLocator(outputBase, ImmutableList.of(workspace)),
           ConstantRuleVisibility.PUBLIC, true, 7, "",
-          UUID.randomUUID());
+          UUID.randomUUID(), new TimestampGranularityMonitor(BlazeClock.instance()));
       skyframeExecutor.invalidateFilesUnderPathForTesting(
           new Reporter(), modifiedFileSet, workspace);
       ((SequencedSkyframeExecutor) skyframeExecutor).handleDiffs(new Reporter());
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java
index 5e9dcd4..6a6ad4c 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java
@@ -642,7 +642,6 @@
       BlazeDirectories directories =
           new BlazeDirectories(fs.getPath("/install"), fs.getPath("/output"), workspace);
       skyframeExecutor = SequencedSkyframeExecutor.create(pkgFactory,
-          new TimestampGranularityMonitor(clock),
           directories,
           null,  /* binTools -- not used */
           null,  /* workspaceStatusActionFactory -- not used */
@@ -658,7 +657,7 @@
       skyframeExecutor.preparePackageLoading(pkgLocator,
           ConstantRuleVisibility.PRIVATE, true,
           7, TestRuleClassProvider.getRuleClassProvider().getDefaultsPackageContent(),
-          UUID.randomUUID());
+          UUID.randomUUID(), new TimestampGranularityMonitor(clock));
       loadingPhaseRunner = skyframeExecutor.getLoadingPhaseRunner(
           pkgFactory.getRuleClassNames(), useNewImpl);
       this.options = Options.getDefaults(LoadingOptions.class);
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/PackageCacheTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/PackageCacheTest.java
index b5856a1..b8ba7fb 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/PackageCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/PackageCacheTest.java
@@ -32,7 +32,6 @@
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
-import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -78,13 +77,12 @@
   private SkyframeExecutor skyframeExecutor;
 
   @Before
-  public final void initializeSkyframExecutor() throws Exception {
+  public final void initializeSkyframeExecutor() throws Exception {
     ruleClassProvider = TestRuleClassProvider.getRuleClassProvider();
     BlazeDirectories directories = new BlazeDirectories(outputBase, outputBase, rootDirectory);
     skyframeExecutor =
         SequencedSkyframeExecutor.create(
             new PackageFactory(ruleClassProvider),
-            new TimestampGranularityMonitor(BlazeClock.instance()),
             directories,
             null, /* BinTools */
             null, /* workspaceStatusActionFactory */
@@ -95,10 +93,6 @@
             AnalysisMock.get().getSkyFunctions(directories),
             ImmutableList.<PrecomputedValue.Injected>of(),
             ImmutableList.<SkyValueDirtinessChecker>of());
-    skyframeExecutor.preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true, 7, "",
-        UUID.randomUUID());
     setUpSkyframe(parsePackageCacheOptions());
   }
 
@@ -108,7 +102,7 @@
     skyframeExecutor.preparePackageLoading(pkgLocator,
         packageCacheOptions.defaultVisibility, true,
         7, ruleClassProvider.getDefaultsPackageContent(),
-        UUID.randomUUID());
+        UUID.randomUUID(), new TimestampGranularityMonitor(BlazeClock.instance()));
     skyframeExecutor.setDeletedPackages(ImmutableSet.copyOf(packageCacheOptions.getDeletedPackages()));
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
index 2d5a9b3..9f35341 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
@@ -397,7 +397,7 @@
       FileArtifactValue value;
       if (action.getActionType() == MiddlemanType.NORMAL) {
         try {
-          FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(output, null, tsgm);
+          FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(output, null, null);
           artifactData.put(output, fileValue);
           value = FileArtifactValue.create(output, fileValue);
         } catch (IOException e) {
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
index 1a93420..76b2c11 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
@@ -24,7 +24,6 @@
 import com.google.devtools.build.lib.skyframe.ActionLookupValue.ActionLookupKey;
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
 import com.google.devtools.build.lib.testutil.TestUtils;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
@@ -60,8 +59,6 @@
   protected SequentialBuildDriver driver;
   protected MemoizingEvaluator evaluator;
   protected Path root;
-  protected TimestampGranularityMonitor tsgm =
-      new TimestampGranularityMonitor(BlazeClock.instance());
 
   /**
    * The test action execution function. The Skyframe evaluator's action execution function
@@ -79,7 +76,9 @@
     evaluator =
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
-                .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
+                .put(SkyFunctions.FILE_STATE,
+                    new FileStateFunction(
+                        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper))
                 .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
                 .put(SkyFunctions.ARTIFACT,
                     new ArtifactFunction(allowedMissingInputsPredicate))
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java
index 0476e56..aa6dcd9 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupFunctionTest.java
@@ -24,7 +24,6 @@
 import com.google.devtools.build.lib.events.NullEventHandler;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
@@ -61,14 +60,14 @@
         new AtomicReference<>(new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)));
     deletedPackages = new AtomicReference<>(ImmutableSet.<PackageIdentifier>of());
     ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator, false);
-    TimestampGranularityMonitor tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
 
     Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>();
     skyFunctions.put(SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction(deletedPackages));
     skyFunctions.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction());
     skyFunctions.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES,
         new BlacklistedPackagePrefixesFunction());
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
+    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
+        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
     skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
     RecordingDifferencer differencer = new RecordingDifferencer();
     evaluator = new InMemoryMemoizingEvaluator(skyFunctions, differencer);
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
index ed239f3..22afdaa 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
+
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.devtools.build.lib.skyframe.SkyframeExecutor.DEFAULT_THREAD_COUNT;
 import static org.junit.Assert.assertArrayEquals;
@@ -42,7 +43,6 @@
 import com.google.devtools.build.lib.testutil.ManualClock;
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
 import com.google.devtools.build.lib.testutil.TestUtils;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
@@ -96,17 +96,15 @@
   private Path pkgRoot;
   private Path outputBase;
   private PathPackageLocator pkgLocator;
-  private TimestampGranularityMonitor tsgm;
   private boolean fastMd5;
   private ManualClock manualClock;
   private RecordingDifferencer differencer;
 
   @Before
-  public final void createMonitor() throws Exception  {
+  public final void createFsAndRoot() throws Exception  {
     fastMd5 = true;
     manualClock = new ManualClock();
     createFsAndRoot(new CustomInMemoryFs(manualClock));
-    tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
   }
 
   private void createFsAndRoot(CustomInMemoryFs fs) throws IOException {
@@ -129,7 +127,8 @@
     MemoizingEvaluator evaluator =
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
-                .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
+                .put(SkyFunctions.FILE_STATE, new FileStateFunction(
+                    new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper))
                 .put(
                     SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS,
                     new FileSymlinkCycleUniquenessFunction())
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java
index 174709b..da88d1f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FilesetEntryFunctionTest.java
@@ -36,7 +36,6 @@
 import com.google.devtools.build.lib.packages.FilesetEntry.SymlinkBehavior;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.Fingerprint;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
@@ -72,8 +71,6 @@
 /** Tests for {@link FilesetEntryFunction}. */
 @RunWith(JUnit4.class)
 public final class FilesetEntryFunctionTest extends FoundationTestCase {
-
-  private TimestampGranularityMonitor tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
   private MemoizingEvaluator evaluator;
   private SequentialBuildDriver driver;
   private RecordingDifferencer differencer;
@@ -89,7 +86,8 @@
 
     Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>();
 
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
+    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
+        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
     skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
index 5f46eed..e9f4cf8 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
@@ -23,7 +23,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.Runnables;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.Artifact;
@@ -41,7 +40,6 @@
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.BasicFilesystemDirtinessChecker;
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.BatchStat;
@@ -94,7 +92,6 @@
   private SequentialBuildDriver driver;
   private MockFileSystem fs;
   private Path pkgRoot;
-  private TimestampGranularityMonitor tsgm;
 
   @Before
   public final void setUp() throws Exception  {
@@ -105,11 +102,11 @@
     FileSystemUtils.createDirectoryAndParents(pkgRoot);
     FileSystemUtils.createEmptyFile(pkgRoot.getRelative("WORKSPACE"));
 
-    tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
     AtomicReference<PathPackageLocator> pkgLocator = new AtomicReference<>(new PathPackageLocator(
         fs.getPath("/output_base"), ImmutableList.of(pkgRoot)));
     ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator, false);
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
+    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
+        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
     skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(
         SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction());
@@ -137,13 +134,13 @@
 
   @Test
   public void testEmpty() throws Exception {
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
     assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
   }
 
   @Test
   public void testSimple() throws Exception {
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
 
     Path path = fs.getPath("/foo");
     FileSystemUtils.createEmptyFile(path);
@@ -187,7 +184,7 @@
    */
   @Test
   public void testDirtySymlink() throws Exception {
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
 
     Path path = fs.getPath("/foo");
     FileSystemUtils.writeContentAsLatin1(path, "foo contents");
@@ -259,7 +256,7 @@
 
   @Test
   public void testExplicitFiles() throws Exception {
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
 
     Path path1 = fs.getPath("/foo1");
     Path path2 = fs.getPath("/foo2");
@@ -312,7 +309,7 @@
     assertTrue(result.hasError());
 
     fs.readlinkThrowsIoException = false;
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
     Diff diff = getDirtyFilesystemKeys(evaluator, checker);
     assertThat(diff.changedKeysWithoutNewValues()).isEmpty();
     assertThat(diff.changedKeysWithNewValues()).isEmpty();
@@ -336,7 +333,7 @@
             NullEventHandler.INSTANCE);
     assertTrue(result.hasError());
 
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
     Diff diff = getDirtyFilesystemKeys(evaluator, checker);
     assertThat(diff.changedKeysWithoutNewValues()).isEmpty();
     assertThat(diff.changedKeysWithNewValues()).isEmpty();
@@ -363,28 +360,27 @@
         driver
             .evaluate(ImmutableList.<SkyKey>of(), false, 1, NullEventHandler.INSTANCE)
             .hasError());
-    assertThat(new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+    assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
         batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
 
     FileSystemUtils.writeContentAsLatin1(out1.getPath(), "goodbye");
-    assertEquals(
-        ActionExecutionValue.key(action1),
-        Iterables.getOnlyElement(
-            new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
-                batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)));
-    assertEquals(
-        ActionExecutionValue.key(action1),
-        Iterables.getOnlyElement(
-            new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
-                batchStatter,
-                new ModifiedFileSet.Builder().modify(out1.getExecPath()).build())));
     assertThat(
-            new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+        new FilesystemValueChecker(null, null).getDirtyActionValues(
+            evaluator.getValues(), batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED))
+        .containsExactly(ActionExecutionValue.key(action1));
+    assertThat(
+        new FilesystemValueChecker(null, null).getDirtyActionValues(
+            evaluator.getValues(),
+            batchStatter,
+            new ModifiedFileSet.Builder().modify(out1.getExecPath()).build()))
+        .containsExactly(ActionExecutionValue.key(action1));
+    assertThat(
+            new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
                 batchStatter,
                 new ModifiedFileSet.Builder().modify(
                     out1.getExecPath().getParentDirectory()).build())).isEmpty();
     assertThat(
-        new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+        new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
             batchStatter, ModifiedFileSet.NOTHING_MODIFIED)).isEmpty();
   }
 
@@ -439,25 +435,25 @@
         driver
             .evaluate(ImmutableList.<SkyKey>of(), false, 1, NullEventHandler.INSTANCE)
             .hasError());
-    assertThat(new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+    assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
         batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
 
     // Touching the TreeArtifact directory should have no effect
     FileSystemUtils.touchFile(out1.getPath());
     assertThat(
-        new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+        new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
             batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
     // Neither should touching a subdirectory.
     FileSystemUtils.touchFile(out2.getPath().getChild("subdir"));
     assertThat(
-        new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+        new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
             batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
 
     /* **** Tests for directories **** */
 
     // Removing a directory (even if empty) should have an effect
     outEmpty.getPath().delete();
-    assertThat(new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+    assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
         batchStatter,
         new ModifiedFileSet.Builder().modify(outEmpty.getExecPath()).build()))
         .containsExactly(ActionExecutionValue.key(actionEmpty));
@@ -465,7 +461,7 @@
     Path dummyEmptyDir = fs.getPath("/bin").getRelative("symlink");
     FileSystemUtils.createDirectoryAndParents(dummyEmptyDir);
     FileSystemUtils.ensureSymbolicLink(outEmpty.getPath(), dummyEmptyDir);
-    assertThat(new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+    assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
         batchStatter,
         new ModifiedFileSet.Builder().modify(outEmpty.getExecPath()).build()))
         .containsExactly(ActionExecutionValue.key(actionEmpty));
@@ -480,12 +476,12 @@
     // Test that file contents matter. This is covered by existing tests already,
     // so it's just a sanity check.
     FileSystemUtils.writeContentAsLatin1(file11.getPath(), "goodbye");
-    assertEquals(
-        ActionExecutionValue.key(action1),
-        Iterables.getOnlyElement(
-            new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
-                batchStatter,
-                new ModifiedFileSet.Builder().modify(file11.getExecPath()).build())));
+    assertThat(
+        new FilesystemValueChecker(null, null).getDirtyActionValues(
+            evaluator.getValues(),
+            batchStatter,
+            new ModifiedFileSet.Builder().modify(file11.getExecPath()).build()))
+        .containsExactly(ActionExecutionValue.key(action1));
 
     // Test that directory contents (and nested contents) matter
     ArtifactFile out1new = artifactFile(out1, "julius/caesar");
@@ -497,12 +493,12 @@
     // so does removing
     file21.getPath().delete();
     // now, let's test our changes are actually visible
-    assertThat(new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+    assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
             batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED))
         .containsExactly(ActionExecutionValue.key(action1), ActionExecutionValue.key(action2),
             ActionExecutionValue.key(actionEmpty));
     assertThat(
-        new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+        new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
             batchStatter,
             new ModifiedFileSet.Builder()
                 .modify(file21.getExecPath())
@@ -514,7 +510,7 @@
     // We add a test for NOTHING_MODIFIED, because FileSystemValueChecker doesn't
     // pay attention to file sets for TreeArtifact directory listings.
     assertThat(
-        new FilesystemValueChecker(tsgm, null).getDirtyActionValues(evaluator.getValues(),
+        new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
             batchStatter, ModifiedFileSet.NOTHING_MODIFIED)).isEmpty();
   }
 
@@ -628,7 +624,7 @@
         FileStatusWithDigest stat =
             forceDigest ? statWithDigest(path, path.statIfFound(Symlinks.NOFOLLOW)) : null;
         artifactData.put(output,
-            ActionMetadataHandler.fileValueFromArtifactFile(output, stat, tsgm));
+            ActionMetadataHandler.fileValueFromArtifactFile(output, stat, null));
       } catch (IOException e) {
         throw new IllegalStateException(e);
       }
@@ -662,7 +658,7 @@
           dirDatum = new HashMap<>();
           directoryData.put(output.getParent(), dirDatum);
         }
-        FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(output, null, tsgm);
+        FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(output, null, null);
         // Always test with digests. TreeArtifact checking behavior doesn't depend on the
         // presence/absence of digests. FileValue checking w/o digests is already tested.
         byte[] digest = DigestUtils.getDigestOrFail(output.getPath(), 1);
@@ -695,7 +691,7 @@
         ImmutableList.of(FileValue.key(RootedPath.toRootedPath(pkgRoot, new PathFragment("foo"))));
     driver.evaluate(
         values, false, SkyframeExecutor.DEFAULT_THREAD_COUNT, NullEventHandler.INSTANCE);
-    FilesystemValueChecker checker = new FilesystemValueChecker(tsgm, null);
+    FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
 
     assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
index 8829e77..95bf419 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
@@ -31,7 +31,6 @@
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.skyframe.GlobValue.InvalidGlobPatternException;
 import com.google.devtools.build.lib.testutil.ManualClock;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Dirent;
 import com.google.devtools.build.lib.vfs.FileStatus;
@@ -94,7 +93,6 @@
   private Path outputBase;
   private Path pkgPath;
   private AtomicReference<PathPackageLocator> pkgLocator;
-  private TimestampGranularityMonitor tsgm;
 
   private static final PackageIdentifier PKG_ID = PackageIdentifier.createInMainRepo("pkg");
 
@@ -109,7 +107,6 @@
     pkgLocator =
         new AtomicReference<>(
             new PathPackageLocator(outputBase, ImmutableList.of(writableRoot, root)));
-    tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
 
     differencer = new RecordingDifferencer();
     evaluator = new InMemoryMemoizingEvaluator(createFunctionMap(), differencer);
@@ -139,7 +136,7 @@
     skyFunctions.put(
         SkyFunctions.FILE_STATE,
         new FileStateFunction(
-            new TimestampGranularityMonitor(BlazeClock.instance()), externalFilesHelper));
+            new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
     skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
     return skyFunctions;
   }
@@ -562,7 +559,7 @@
     // Our custom filesystem says "pkgPath/BUILD" exists but "pkgPath" does not exist.
     fs.stubStat(pkgPath, null);
     RootedPath pkgRootedPath = RootedPath.toRootedPath(root, pkgPath);
-    FileStateValue pkgDirFileStateValue = FileStateValue.create(pkgRootedPath, tsgm);
+    FileStateValue pkgDirFileStateValue = FileStateValue.create(pkgRootedPath, null);
     FileValue pkgDirValue =
         FileValue.value(pkgRootedPath, pkgDirFileStateValue, pkgRootedPath, pkgDirFileStateValue);
     differencer.inject(ImmutableMap.of(FileValue.key(pkgRootedPath), pkgDirValue));
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
index 9178fd5..0ca5b31 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
@@ -35,6 +35,8 @@
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
 import com.google.devtools.build.lib.testutil.ManualClock;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Dirent;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import com.google.devtools.build.lib.vfs.FileSystem;
@@ -71,6 +73,13 @@
 
   private CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
 
+  private void preparePackageLoading(Path... roots) {
+    getSkyframeExecutor().preparePackageLoading(
+        new PathPackageLocator(outputBase, ImmutableList.copyOf(roots)),
+        ConstantRuleVisibility.PUBLIC, true,
+        7, "", UUID.randomUUID(), new TimestampGranularityMonitor(BlazeClock.instance()));
+  }
+
   @Override
   protected Preprocessor.Factory.Supplier getPreprocessorFactorySupplier() {
     return new SubincludePreprocessor.FactorySupplier(scratch.getFileSystem());
@@ -97,10 +106,7 @@
     scratch.file("pkg/BUILD", "subinclude('//foo:sub')");
     scratch.file("foo/sub");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey pkgLookupKey = PackageLookupValue.key(new PathFragment("foo"));
     EvaluationResult<PackageLookupValue> result = SkyframeExecutorTestUtils.evaluate(
@@ -131,10 +137,7 @@
     scratch.file("/root2/foo/BUILD");
     scratch.file("/root2/foo/sub");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(root1, root2)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(root1, root2);
 
     SkyKey pkgLookupKey = PackageLookupValue.key(PackageIdentifier.parse("@//foo"));
     EvaluationResult<PackageLookupValue> result = SkyframeExecutorTestUtils.evaluate(
@@ -206,8 +209,7 @@
     };
     fs.stubStat(fooDir, inconsistentParentFileStatus);
     RootedPath pkgRootedPath = RootedPath.toRootedPath(pkgRoot, fooDir);
-    SkyValue fooDirValue = FileStateValue.create(pkgRootedPath,
-        getSkyframeExecutor().getTimestampGranularityMonitorForTesting());
+    SkyValue fooDirValue = FileStateValue.create(pkgRootedPath, tsgm);
     differencer.inject(ImmutableMap.of(FileStateValue.key(pkgRootedPath), fooDirValue));
     SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     String expectedMessage = "/workspace/foo/BUILD exists but its parent path /workspace/foo isn't "
@@ -240,8 +242,7 @@
     // has a child directory "baz".
     fs.stubStat(bazDir, null);
     RootedPath barDirRootedPath = RootedPath.toRootedPath(pkgRoot, barDir);
-    FileStateValue barDirFileStateValue = FileStateValue.create(barDirRootedPath,
-        getSkyframeExecutor().getTimestampGranularityMonitorForTesting());
+    FileStateValue barDirFileStateValue = FileStateValue.create(barDirRootedPath, tsgm);
     FileValue barDirFileValue = FileValue.value(barDirRootedPath, barDirFileStateValue,
         barDirRootedPath, barDirFileStateValue);
     DirectoryListingValue barDirListing = DirectoryListingValue.value(barDirRootedPath,
@@ -293,10 +294,7 @@
     scratch.file("bar/a");
     scratch.file("bar/b");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     validPackage(skyKey);
@@ -315,10 +313,7 @@
     scratch.file("baz/b");
     scratch.file("baz/c");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     PackageValue value = validPackage(skyKey);
@@ -345,10 +340,7 @@
         "exports_files(['a'])");
     scratch.file("baz/a");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey fooKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     PackageValue fooValue = validPackage(fooKey);
@@ -376,10 +368,7 @@
     scratch.file("qux/ext.bzl",
         "c = 1");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     PackageValue value = validPackage(skyKey);
@@ -549,10 +538,7 @@
     scratch.file("foo/existing.txt");
     FileSystemUtils.ensureSymbolicLink(packageDirPath.getChild("dangling.txt"), "nope");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     PackageValue value = validPackage(skyKey);
@@ -605,10 +591,7 @@
         "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]");
     scratch.file("foo/bar");
 
-    getSkyframeExecutor().preparePackageLoading(
-        new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)),
-        ConstantRuleVisibility.PUBLIC, true,
-        7, "", UUID.randomUUID());
+    preparePackageLoading(rootDirectory);
 
     SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
     PackageValue value = validPackage(skyKey);
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java
index 3452728..07edc60 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageLookupFunctionTest.java
@@ -32,7 +32,6 @@
 import com.google.devtools.build.lib.skyframe.PackageLookupValue.ErrorReason;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -74,7 +73,6 @@
         new PathPackageLocator(outputBase, ImmutableList.of(emptyPackagePath, rootDirectory)));
     deletedPackages = new AtomicReference<>(ImmutableSet.<PackageIdentifier>of());
     ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator, false);
-    TimestampGranularityMonitor tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
     BlazeDirectories directories = new BlazeDirectories(rootDirectory, outputBase, rootDirectory);
 
     Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>();
@@ -83,7 +81,8 @@
     skyFunctions.put(
         SkyFunctions.PACKAGE,
         new PackageFunction(null, null, null, null, null, null, null));
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
+    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
+        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
     skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES,
         new BlacklistedPackagePrefixesFunction());
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java
index 5e2ebfd..507e93a 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunctionTest.java
@@ -38,7 +38,6 @@
 import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.TraversalRequest;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
-import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Path;
@@ -74,9 +73,6 @@
 /** Tests for {@link RecursiveFilesystemTraversalFunction}. */
 @RunWith(JUnit4.class)
 public final class RecursiveFilesystemTraversalFunctionTest extends FoundationTestCase {
-
-  private final TimestampGranularityMonitor tsgm =
-      new TimestampGranularityMonitor(BlazeClock.instance());
   private RecordingEvaluationProgressReceiver progressReceiver;
   private MemoizingEvaluator evaluator;
   private SequentialBuildDriver driver;
@@ -93,7 +89,8 @@
 
     Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>();
 
-    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper));
+    skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction(
+        new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper));
     skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator));
     skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
     skyFunctions.put(
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTest.java
index d8c63fe..d1e36bea 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTest.java
@@ -24,9 +24,10 @@
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
-import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.util.SubincludePreprocessor;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.ModifiedFileSet;
@@ -43,12 +44,6 @@
 
 @RunWith(JUnit4.class)
 public class SkyframeLabelVisitorTest extends SkyframeLabelVisitorTestCase {
-
-  @Override
-  public PackageFactory.EnvironmentExtension getPackageEnvironmentExtension() {
-    return new PackageFactory.EmptyEnvironmentExtension();
-  }
-
   @Test
   public void testLabelVisitorDetectsMissingPackages() throws Exception {
     reporter.removeHandler(failFastHandler); // expect errors
@@ -414,7 +409,8 @@
             true,
             7,
             ruleClassProvider.getDefaultsPackageContent(),
-            UUID.randomUUID());
+            UUID.randomUUID(),
+            new TimestampGranularityMonitor(BlazeClock.instance()));
     this.visitor = getSkyframeExecutor().pkgLoader();
     scratch.file("pkg/BUILD", "sh_library(name = 'x', deps = ['z'])", "sh_library(name = 'z')");
     assertLabelsVisited(
@@ -457,7 +453,8 @@
             true,
             7,
             ruleClassProvider.getDefaultsPackageContent(),
-            UUID.randomUUID());
+            UUID.randomUUID(),
+            new TimestampGranularityMonitor(BlazeClock.instance()));
     this.visitor = getSkyframeExecutor().pkgLoader();
     scratch.file("a/BUILD", "subinclude('//b:c/d/foo')");
     scratch.file("b/BUILD", "exports_files(['c/d/foo'])");
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTestCase.java
index 1395159..1568cc1 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitorTestCase.java
@@ -20,7 +20,6 @@
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
@@ -33,7 +32,7 @@
 import com.google.devtools.build.lib.events.EventKind;
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
-import com.google.devtools.build.lib.packages.PackageFactory;
+import com.google.devtools.build.lib.packages.Preprocessor;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
 import com.google.devtools.build.lib.packages.util.PreprocessorUtils;
@@ -71,7 +70,10 @@
   protected PreprocessorUtils.MutableFactorySupplier preprocessorFactorySupplier =
       new PreprocessorUtils.MutableFactorySupplier(null);
 
-  abstract public PackageFactory.EnvironmentExtension getPackageEnvironmentExtension();
+  @Override
+  protected Preprocessor.Factory.Supplier getPreprocessorFactorySupplier() {
+    return preprocessorFactorySupplier;
+  }
 
   @Override
   protected FileSystem createFileSystem() {
@@ -279,9 +281,7 @@
 
   @Before
   public final void initializeVisitor() throws Exception {
-    skyframeExecutor = super.createSkyframeExecutor(
-        ImmutableList.of(getPackageEnvironmentExtension()), preprocessorFactorySupplier,
-        ConstantRuleVisibility.PRIVATE, ruleClassProvider.getDefaultsPackageContent());
+    setUpSkyframe(ConstantRuleVisibility.PRIVATE, ruleClassProvider.getDefaultsPackageContent());
     this.visitor = skyframeExecutor.pkgLoader();
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkFileContentHashTests.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkFileContentHashTests.java
index 4cdc8be..089d6a4 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkFileContentHashTests.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkFileContentHashTests.java
@@ -24,6 +24,8 @@
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.skyframe.EvaluationResult;
 import com.google.devtools.build.skyframe.SkyKey;
 
@@ -161,7 +163,8 @@
             true,
             7,
             "",
-            UUID.randomUUID());
+            UUID.randomUUID(),
+            new TimestampGranularityMonitor(BlazeClock.instance()));
     SkyKey pkgLookupKey = PackageValue.key(PackageIdentifier.parse("@//" + pkg));
     EvaluationResult<PackageValue> result =
         SkyframeExecutorTestUtils.evaluate(
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunctionTest.java
index 8689062..838302f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunctionTest.java
@@ -24,6 +24,8 @@
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.skyframe.ErrorInfo;
 import com.google.devtools.build.skyframe.EvaluationResult;
@@ -52,7 +54,8 @@
             true,
             7,
             "",
-            UUID.randomUUID());
+            UUID.randomUUID(),
+            new TimestampGranularityMonitor(BlazeClock.instance()));
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
index 9ddfcb5..e4e15ef 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -138,6 +138,7 @@
       @Nullable EvaluationProgressReceiver evaluationProgressReceiver) {
     AtomicReference<PathPackageLocator> pkgLocator =
         new AtomicReference<>(new PathPackageLocator(outputBase, ImmutableList.of(rootDirectory)));
+    AtomicReference<TimestampGranularityMonitor> tsgmRef = new AtomicReference<>(tsgm);
     ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator, false);
     differencer = new RecordingDifferencer();
 
@@ -153,14 +154,14 @@
     final InMemoryMemoizingEvaluator evaluator =
         new InMemoryMemoizingEvaluator(
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
-                .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
+                .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgmRef, externalFilesHelper))
                 .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
                 .put(
                     SkyFunctions.ARTIFACT,
                     new ArtifactFunction(Predicates.<PathFragment>alwaysFalse()))
                 .put(
                     SkyFunctions.ACTION_EXECUTION,
-                    new ActionExecutionFunction(skyframeActionExecutor, tsgm))
+                    new ActionExecutionFunction(skyframeActionExecutor, tsgmRef))
                 .put(
                     SkyFunctions.PACKAGE,
                     new PackageFunction(null, null, null, null, null, null, null))
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
index a57576c..54a1418 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
@@ -227,7 +227,7 @@
         try {
           ArtifactFile suboutput = ActionInputHelper.artifactFile(output, subpath);
           FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(
-              suboutput, null, tsgm);
+              suboutput, null, null);
           fileData.put(suboutput, fileValue);
           // Ignore FileValue digests--correctness of these digests is not part of this tests.
           byte[] digest = DigestUtils.getDigestOrFail(suboutput.getPath(), 1);