Reduce and centralize databinding context instances.
Due to some of the vagaries of skylark and multiple entry points, the databinding context is currently updated by the parse action.

RELNOTES: None
PiperOrigin-RevId: 207333111
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
index a7a980c..d021892 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
@@ -104,7 +104,12 @@
       boolean neverlink = JavaCommon.isNeverLink(ruleContext);
       ValidatedAndroidResources validatedResources =
           AndroidResources.forAarImport(resources)
-              .process(ruleContext, dataContext, manifest, neverlink);
+              .process(
+                  ruleContext,
+                  dataContext,
+                  manifest,
+                  DataBinding.contextFrom(ruleContext),
+                  neverlink);
       MergedAndroidAssets mergedAssets =
           AndroidAssets.forAarImport(assets)
               .process(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index a413f0c..959ffe8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -239,7 +239,8 @@
                       ? ruleContext
                           .getPrerequisite("feature_after", Mode.TARGET, ApkInfo.PROVIDER)
                           .getApk()
-                      : null)
+                      : null,
+                  DataBinding.contextFrom(ruleContext))
               .generateRClass(dataContext, aaptVersion);
     } else {
       applicationManifest =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
index 1a7e53b..58ef404 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
@@ -174,7 +174,12 @@
 
         ValidatedAndroidResources resources =
             AndroidResources.from(ruleContext, "resource_files")
-                .process(ruleContext, dataContext, manifest, isNeverLink);
+                .process(
+                    ruleContext,
+                    dataContext,
+                    manifest,
+                    DataBinding.contextFrom(ruleContext),
+                    isNeverLink);
 
         MergedAndroidAssets assets =
             AndroidAssets.from(ruleContext)
@@ -212,6 +217,7 @@
       resourceApk =
           ResourceApk.processFromTransitiveLibraryData(
               dataContext,
+              DataBinding.contextFrom(ruleContext),
               resourceDeps,
               assetDeps,
               StampedAndroidManifest.createEmpty(ruleContext, /* exported = */ false));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
index f32ea9c..6d02827 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -37,6 +37,7 @@
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment;
 import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder;
 import com.google.devtools.build.lib.rules.java.JavaCommon;
@@ -100,6 +101,7 @@
           buildResourceApk(
               dataContext,
               androidSemantics,
+              DataBinding.contextFrom(ruleContext),
               AndroidManifest.fromAttributes(ruleContext, dataContext),
               AndroidResources.from(ruleContext, "resource_files"),
               AndroidAssets.from(ruleContext),
@@ -557,6 +559,7 @@
   static ResourceApk buildResourceApk(
       AndroidDataContext dataContext,
       AndroidSemantics androidSemantics,
+      DataBindingContext dataBindingContext,
       AndroidManifest manifest,
       AndroidResources resources,
       AndroidAssets assets,
@@ -576,6 +579,7 @@
 
     return ProcessedAndroidData.processLocalTestDataFrom(
             dataContext,
+            dataBindingContext,
             stamped,
             manifestValues,
             aaptVersion,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java
index aff8128..e5fe55a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Streams;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import javax.annotation.Nullable;
 
@@ -118,7 +119,8 @@
   public ParsedAndroidResources build(
       AndroidDataContext dataContext,
       AndroidResources androidResources,
-      StampedAndroidManifest manifest) {
+      StampedAndroidManifest manifest,
+      DataBindingContext dataBindingContext) {
     if (dataBindingInfoZip != null) {
       // Manifest information is needed for data binding
       setManifest(manifest.getManifest());
@@ -129,7 +131,12 @@
     build(dataContext);
 
     return ParsedAndroidResources.of(
-        androidResources, output, compiledSymbols, dataContext.getLabel(), manifest);
+        androidResources,
+        output,
+        compiledSymbols,
+        dataContext.getLabel(),
+        manifest,
+        dataBindingContext);
   }
 
   public ParsedAndroidAssets build(AndroidDataContext dataContext, AndroidAssets assets) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java
index ebe36bc..c78533e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java
@@ -16,6 +16,7 @@
 import com.android.resources.ResourceFolderType;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -136,32 +137,24 @@
     return from(
         ruleContext,
         ruleContext.getPrerequisites(resourcesAttr, Mode.TARGET, FileProvider.class),
-        resourcesAttr,
-        DataBinding.contextFrom(ruleContext));
+        resourcesAttr);
   }
 
   public static AndroidResources from(
       RuleErrorConsumer errorConsumer,
       Iterable<FileProvider> resourcesTargets,
-      String resourcesAttr,
-      DataBindingContext dataBindingContext)
+      String resourcesAttr)
       throws RuleErrorException {
-    return forResources(
-        errorConsumer, getResources(resourcesTargets), resourcesAttr, dataBindingContext);
+    return forResources(errorConsumer, getResources(resourcesTargets), resourcesAttr);
   }
 
   /** Returns an {@link AndroidResources} for a list of resource artifacts. */
   @VisibleForTesting
   public static AndroidResources forResources(
-      RuleErrorConsumer ruleErrorConsumer,
-      ImmutableList<Artifact> resources,
-      String resourcesAttr,
-      DataBindingContext dataBindingContext)
+      RuleErrorConsumer ruleErrorConsumer, ImmutableList<Artifact> resources, String resourcesAttr)
       throws RuleErrorException {
     return new AndroidResources(
-        resources,
-        getResourceRoots(ruleErrorConsumer, resources, resourcesAttr),
-        dataBindingContext);
+        resources, getResourceRoots(ruleErrorConsumer, resources, resourcesAttr));
   }
 
   /**
@@ -174,8 +167,7 @@
   }
 
   static AndroidResources empty() {
-    return new AndroidResources(
-        ImmutableList.of(), ImmutableList.of(), DataBinding.asDisabledDataBindingContext());
+    return new AndroidResources(ImmutableList.of(), ImmutableList.of());
   }
 
   /**
@@ -192,8 +184,7 @@
     Preconditions.checkArgument(resourcesDir.isTreeArtifact());
     return new AndroidResources(
         ImmutableList.of(resourcesDir),
-        ImmutableList.of(resourcesDir.getExecPath().getChild("res")),
-        DataBinding.asDisabledDataBindingContext());
+        ImmutableList.of(resourcesDir.getExecPath().getChild("res")));
   }
 
   /**
@@ -316,20 +307,16 @@
 
   private final ImmutableList<Artifact> resources;
   private final ImmutableList<PathFragment> resourceRoots;
-  private final DataBindingContext dataBindingContext;
 
   AndroidResources(AndroidResources other) {
-    this(other.resources, other.resourceRoots, other.dataBindingContext);
+    this(other.resources, other.resourceRoots);
   }
 
   @VisibleForTesting
   public AndroidResources(
-      ImmutableList<Artifact> resources,
-      ImmutableList<PathFragment> resourceRoots,
-      DataBindingContext dataBindingContext) {
+      ImmutableList<Artifact> resources, ImmutableList<PathFragment> resourceRoots) {
     this.resources = resources;
     this.resourceRoots = resourceRoots;
-    this.dataBindingContext = dataBindingContext;
   }
 
   private static ImmutableList<Artifact> getResources(Iterable<FileProvider> targets) {
@@ -411,19 +398,18 @@
     return Optional.of(
         new AndroidResources(
             filtered.get(),
-            getResourceRoots(errorConsumer, filtered.get(), DEFAULT_RESOURCES_ATTR),
-            dataBindingContext));
+            getResourceRoots(errorConsumer, filtered.get(), DEFAULT_RESOURCES_ATTR)));
   }
 
   /** Parses these resources. */
   public ParsedAndroidResources parse(
       AndroidDataContext dataContext,
       StampedAndroidManifest manifest,
-      boolean enableDataBinding,
-      AndroidAaptVersion aaptVersion)
+      AndroidAaptVersion aaptVersion,
+      DataBindingContext dataBindingContext)
       throws InterruptedException {
     return ParsedAndroidResources.parseFrom(
-        dataContext, this, manifest, enableDataBinding, aaptVersion);
+        dataContext, this, manifest, aaptVersion, dataBindingContext);
   }
 
   /**
@@ -434,13 +420,14 @@
       RuleContext ruleContext,
       AndroidDataContext dataContext,
       StampedAndroidManifest manifest,
+      DataBindingContext dataBindingContext,
       boolean neverlink)
       throws RuleErrorException, InterruptedException {
     return process(
         dataContext,
         manifest,
         ResourceDependencies.fromRuleDeps(ruleContext, neverlink),
-        DataBinding.isEnabled(ruleContext),
+        dataBindingContext,
         AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
   }
 
@@ -448,11 +435,11 @@
       AndroidDataContext dataContext,
       StampedAndroidManifest manifest,
       ResourceDependencies resourceDeps,
-      boolean enableDataBinding,
+      DataBindingContext dataBindingContext,
       AndroidAaptVersion aaptVersion)
       throws InterruptedException {
-    return parse(dataContext, manifest, enableDataBinding, aaptVersion)
-        .merge(dataContext, resourceDeps, enableDataBinding, aaptVersion)
+    return parse(dataContext, manifest, aaptVersion, dataBindingContext)
+        .merge(dataContext, resourceDeps, aaptVersion)
         .validate(dataContext, aaptVersion);
   }
 
@@ -470,4 +457,12 @@
   public int hashCode() {
     return Objects.hash(resources, resourceRoots);
   }
+
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+        .add("resources", resources)
+        .add("resourceRoots", resourceRoots)
+        .toString();
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java
index e289c7e..e1567f0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
 import com.google.devtools.build.lib.rules.android.AndroidDataConverter.JoinerType;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
 import java.util.Collections;
@@ -230,9 +231,12 @@
    *     information.
    */
   public ResourceApk buildWithoutLocalResources(
-      AndroidDataContext dataContext, StampedAndroidManifest manifest) {
+      AndroidDataContext dataContext,
+      StampedAndroidManifest manifest,
+      DataBindingContext androidDataContext) {
 
-    build(dataContext, AndroidResources.empty(), AndroidAssets.empty(), manifest);
+    build(
+        dataContext, AndroidResources.empty(), AndroidAssets.empty(), manifest, androidDataContext);
 
     return ResourceApk.fromTransitiveResources(
         resourceDependencies,
@@ -241,12 +245,16 @@
         rTxtOut);
   }
 
-  public ResourceContainer build(AndroidDataContext dataContext, ResourceContainer primary) {
+  public ResourceContainer build(
+      AndroidDataContext dataContext,
+      ResourceContainer primary,
+      DataBindingContext dataBindingContext) {
     build(
         dataContext,
         primary.getAndroidResources(),
         primary.getAndroidAssets(),
-        ProcessedAndroidManifest.from(primary));
+        ProcessedAndroidManifest.from(primary),
+        dataBindingContext);
 
     ResourceContainer.Builder builder =
         primary.toBuilder().setJavaSourceJar(sourceJarOut).setRTxt(rTxtOut).setSymbols(symbols);
@@ -272,7 +280,8 @@
       AndroidDataContext dataContext,
       AndroidResources primaryResources,
       AndroidAssets primaryAssets,
-      StampedAndroidManifest primaryManifest) {
+      StampedAndroidManifest primaryManifest,
+      DataBindingContext dataBindingContext) {
 
     if (aaptVersion == AndroidAaptVersion.AAPT2) {
       createAapt2ApkAction(dataContext, primaryResources, primaryAssets, primaryManifest);
@@ -294,7 +303,8 @@
             symbols,
             /* compiledSymbols = */ null,
             dataContext.getLabel(),
-            processedManifest);
+            processedManifest,
+            dataBindingContext);
 
     // Wrap the parsed and merged assets
     ParsedAndroidAssets parsedAssets =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
index 58fb920..565fd50 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
@@ -88,6 +88,7 @@
       }
       return ResourceApk.processFromTransitiveLibraryData(
               ctx,
+              DataBinding.asDisabledDataBindingContext(),
               ResourceDependencies.fromProviders(deps, /* neverlink = */ neverlink),
               AssetDependencies.empty(),
               StampedAndroidManifest.createEmpty(
@@ -169,19 +170,12 @@
       AndroidAaptVersion aaptVersion = ctx.getAndroidConfig().getAndroidAaptVersion();
 
       ValidatedAndroidResources validated =
-          AndroidResources.from(
-                  errorReporter,
-                  getFileProviders(resources),
-                  "resources",
-                  enableDataBinding
-                      ? DataBinding.asEnabledDataBindingContextFrom(
-                          ctx.getActionConstructionContext())
-                      : DataBinding.asDisabledDataBindingContext())
+          AndroidResources.from(errorReporter, getFileProviders(resources), "resources")
               .process(
                   ctx,
                   manifest.asStampedManifest(),
                   ResourceDependencies.fromProviders(deps, neverlink),
-                  enableDataBinding,
+                  DataBinding.contextFrom(enableDataBinding, ctx.getActionConstructionContext()),
                   aaptVersion);
 
       JavaInfo javaInfo = getJavaInfoForRClassJar(validated.getClassJar());
@@ -383,7 +377,7 @@
                 AndroidManifest.forAarImport(androidManifestArtifact),
                 ResourceDependencies.fromProviders(
                     getProviders(deps, AndroidResourcesInfo.PROVIDER), /* neverlink = */ false),
-                /* enableDataBinding = */ false,
+                DataBinding.asDisabledDataBindingContext(),
                 aaptVersion);
 
     MergedAndroidAssets mergedAssets =
@@ -428,12 +422,9 @@
           AndroidLocalTestBase.buildResourceApk(
               ctx,
               getAndroidSemantics(),
+              DataBinding.asDisabledDataBindingContext(),
               rawManifest,
-              AndroidResources.from(
-                  errorReporter,
-                  getFileProviders(resources),
-                  "resource_files",
-                  DataBinding.asDisabledDataBindingContext()),
+              AndroidResources.from(errorReporter, getFileProviders(resources), "resource_files"),
               AndroidAssets.from(
                   errorReporter,
                   listFromNoneable(assets, ConfiguredTarget.class),
@@ -575,13 +566,7 @@
                   manifestValues,
                   settings.aaptVersion,
                   AndroidResources.from(
-                      errorReporter,
-                      getFileProviders(resources),
-                      "resource_files",
-                      dataBindingEnabled
-                          ? DataBinding.asEnabledDataBindingContextFrom(
-                              ctx.getActionConstructionContext())
-                          : DataBinding.asDisabledDataBindingContext()),
+                      errorReporter, getFileProviders(resources), "resource_files"),
                   AndroidAssets.from(
                       errorReporter,
                       listFromNoneable(assets, ConfiguredTarget.class),
@@ -596,7 +581,8 @@
                   crunchPng,
                   dataBindingEnabled,
                   /* featureOf = */ null,
-                  /* featureAfter = */ null)
+                  /* featureAfter = */ null,
+                  DataBinding.contextFrom(dataBindingEnabled, ctx.getActionConstructionContext()))
               .generateRClass(ctx, settings.aaptVersion);
 
       return AndroidBinaryDataInfo.of(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
index d93b8a2..c9e3dae 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
@@ -418,7 +418,8 @@
           .setSymbols(resourceContainer.getSymbols())
           .setSourceJarOut(resourceContainer.getJavaSourceJar());
     }
-    ResourceContainer processed = builder.build(dataContext, resourceContainer);
+    ResourceContainer processed =
+        builder.build(dataContext, resourceContainer, DataBinding.contextFrom(ruleContext));
 
     ResourceContainer finalContainer =
         new RClassGeneratorActionBuilder()
@@ -547,7 +548,7 @@
                     .getFragment(AndroidConfiguration.class)
                     .throwOnResourceConflict())
             .setPackageUnderTest(null)
-            .build(dataContext, resourceContainer);
+            .build(dataContext, resourceContainer, DataBinding.contextFrom(ruleContext));
 
     // Intentionally skip building an R class JAR - incremental binaries handle this separately.
 
@@ -630,7 +631,7 @@
             .setRTxtOut(resourceContainer.getRTxt())
             .setSymbols(resourceContainer.getSymbols())
             .setSourceJarOut(resourceContainer.getJavaSourceJar())
-            .build(dataContext, resourceContainer);
+            .build(dataContext, resourceContainer, DataBinding.contextFrom(ruleContext));
 
     ResourceContainer finalContainer =
         new RClassGeneratorActionBuilder()
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java b/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java
index 86cd131..9f295ba 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java
@@ -32,6 +32,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Consumer;
 
 /**
@@ -62,6 +63,8 @@
   public static final String DATABINDING_ANNOTATION_PROCESSOR_ATTR =
       "$databinding_annotation_processor";
 
+  public static final String ENABLE_DATA_BINDING_ATTR = "enable_data_binding";
+
   /** Contains Android Databinding configuration and resource generation information. */
   public interface DataBindingContext {
     void supplyLayoutInfo(Consumer<Artifact> consumer);
@@ -79,6 +82,23 @@
     public void supplyLayoutInfo(Consumer<Artifact> consumer) {
       consumer.accept(getLayoutInfoFile(actionConstructionContext));
     }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      EnabledDataBindingContext that = (EnabledDataBindingContext) o;
+      return Objects.equals(actionConstructionContext, that.actionConstructionContext);
+    }
+
+    @Override
+    public int hashCode() {
+      return actionConstructionContext.hashCode();
+    }
   }
 
   private static final class DisabledDataBindingContext implements DataBindingContext {
@@ -97,6 +117,14 @@
     return asDisabledDataBindingContext();
   }
 
+  /** Supplies a databinding context from a rulecontext. */
+  public static DataBindingContext contextFrom(boolean enabled, ActionConstructionContext context) {
+    if (enabled) {
+      return asEnabledDataBindingContextFrom(context);
+    }
+    return asDisabledDataBindingContext();
+  }
+
   /** Supplies an enabled DataBindingContext from the action context. */
   public static DataBindingContext asEnabledDataBindingContextFrom(
       ActionConstructionContext actionContext) {
@@ -129,8 +157,8 @@
    * binding expressions appear in their layout resources.
    */
   public static boolean isEnabled(RuleContext ruleContext) {
-    return ruleContext.attributes().has("enable_data_binding", Type.BOOLEAN)
-        && ruleContext.attributes().get("enable_data_binding", Type.BOOLEAN);
+    return ruleContext.attributes().has(ENABLE_DATA_BINDING_ATTR, Type.BOOLEAN)
+        && ruleContext.attributes().get(ENABLE_DATA_BINDING_ATTR, Type.BOOLEAN);
   }
 
   /** Returns this rule's data binding base output dir (as an execroot-relative path). */
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java
index ce3bc20..f139a2b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java
@@ -40,7 +40,6 @@
       AndroidDataContext dataContext,
       ParsedAndroidResources parsed,
       ResourceDependencies resourceDeps,
-      boolean enableDataBinding,
       AndroidAaptVersion aaptVersion)
       throws InterruptedException {
 
@@ -60,10 +59,7 @@
             .setThrowOnResourceConflict(androidConfiguration.throwOnResourceConflict())
             .setUseCompiledMerge(useCompiledMerge);
 
-    if (enableDataBinding) {
-      builder.setDataBindingInfoZip(
-          DataBinding.getLayoutInfoFile(dataContext.getActionConstructionContext()));
-    }
+    parsed.asDataBindingContext().supplyLayoutInfo(builder::setDataBindingInfoZip);
 
     return builder
         .setManifestOut(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java
index e1b2d4c..240dce0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java
@@ -13,11 +13,15 @@
 // limitations under the License.
 package com.google.devtools.build.lib.rules.android;
 
+import com.android.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import java.util.Objects;
 import java.util.Optional;
 import javax.annotation.Nullable;
@@ -29,25 +33,28 @@
   @Nullable private final Artifact compiledSymbols;
   private final Label label;
   private final StampedAndroidManifest manifest;
+  private final DataBindingContext dataBindingContext;
 
   public static ParsedAndroidResources parseFrom(
       AndroidDataContext dataContext,
       AndroidResources resources,
       StampedAndroidManifest manifest,
-      boolean enableDataBinding,
-      AndroidAaptVersion aaptVersion)
+      AndroidAaptVersion aaptVersion,
+      DataBindingContext dataBindingContext)
       throws InterruptedException {
 
     boolean isAapt2 = aaptVersion == AndroidAaptVersion.AAPT2;
 
     AndroidResourceParsingActionBuilder builder = new AndroidResourceParsingActionBuilder();
 
-    if (enableDataBinding && isAapt2) {
+    if (isAapt2) {
       // TODO(corysmith): Centralize the data binding processing and zipping into a single
       // action. Data binding processing needs to be triggered here as well as the merger to
       // avoid aapt2 from throwing an error during compilation.
-      builder.setDataBindingInfoZip(
-          DataBinding.getSuffixedInfoFile(dataContext.getActionConstructionContext(), "_unused"));
+      dataBindingContext.supplyLayoutInfo(
+          layoutInfo ->
+              builder.setDataBindingInfoZip(
+                  getDummyDataBindingArtifact(dataContext.getActionConstructionContext())));
     }
 
     return builder
@@ -56,7 +63,12 @@
             isAapt2
                 ? dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_COMPILED_SYMBOLS)
                 : null)
-        .build(dataContext, resources, manifest);
+        .build(dataContext, resources, manifest, dataBindingContext);
+  }
+
+  @VisibleForTesting
+  static Artifact getDummyDataBindingArtifact(ActionConstructionContext dataContext) {
+    return dataContext.getUniqueDirectoryArtifact("dummydatabinding", "unused.zip");
   }
 
   public static ParsedAndroidResources of(
@@ -64,12 +76,20 @@
       Artifact symbols,
       @Nullable Artifact compiledSymbols,
       Label label,
-      StampedAndroidManifest manifest) {
-    return new ParsedAndroidResources(resources, symbols, compiledSymbols, label, manifest);
+      StampedAndroidManifest manifest,
+      DataBindingContext dataBindingContext) {
+    return new ParsedAndroidResources(
+        resources, symbols, compiledSymbols, label, manifest, dataBindingContext);
   }
 
   ParsedAndroidResources(ParsedAndroidResources other, StampedAndroidManifest manifest) {
-    this(other, other.symbols, other.compiledSymbols, other.label, manifest);
+    this(
+        other,
+        other.symbols,
+        other.compiledSymbols,
+        other.label,
+        manifest,
+        other.dataBindingContext);
   }
 
   protected ParsedAndroidResources(
@@ -77,12 +97,14 @@
       Artifact symbols,
       @Nullable Artifact compiledSymbols,
       Label label,
-      StampedAndroidManifest manifest) {
+      StampedAndroidManifest manifest,
+      DataBindingContext dataBindingContext) {
     super(resources);
     this.symbols = symbols;
     this.compiledSymbols = compiledSymbols;
     this.label = label;
     this.manifest = manifest;
+    this.dataBindingContext = dataBindingContext;
   }
 
   @Override
@@ -128,11 +150,9 @@
   MergedAndroidResources merge(
       AndroidDataContext dataContext,
       ResourceDependencies resourceDeps,
-      boolean enableDataBinding,
       AndroidAaptVersion aaptVersion)
       throws InterruptedException {
-    return MergedAndroidResources.mergeFrom(
-        dataContext, this, resourceDeps, enableDataBinding, aaptVersion);
+    return MergedAndroidResources.mergeFrom(dataContext, this, resourceDeps, aaptVersion);
   }
 
   @Override
@@ -142,7 +162,8 @@
     return super.maybeFilter(errorConsumer, resourceFilter, isDependency)
         .map(
             resources ->
-                ParsedAndroidResources.of(resources, symbols, compiledSymbols, label, manifest));
+                ParsedAndroidResources.of(
+                    resources, symbols, compiledSymbols, label, manifest, dataBindingContext));
   }
 
   @Override
@@ -162,4 +183,18 @@
   public int hashCode() {
     return Objects.hash(super.hashCode(), symbols, compiledSymbols, label, manifest);
   }
+
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+        .add("symbols", symbols)
+        .add("compiledSymbols", compiledSymbols)
+        .add("label", label)
+        .add("manifest", manifest)
+        .toString();
+  }
+
+  public DataBindingContext asDataBindingContext() {
+    return dataBindingContext;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
index 484d296..f69128a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import com.google.devtools.build.lib.rules.java.ProguardHelper;
 import com.google.devtools.build.lib.syntax.Type;
 import java.util.List;
@@ -68,7 +69,8 @@
       boolean crunchPng,
       boolean dataBindingEnabled,
       @Nullable Artifact featureOf,
-      @Nullable Artifact featureAfter)
+      @Nullable Artifact featureAfter,
+      DataBindingContext dataBindingContext)
       throws RuleErrorException, InterruptedException {
     if (conditionalKeepRules && aaptVersion != AndroidAaptVersion.AAPT2) {
       throw errorConsumer.throwWithRuleError(
@@ -96,6 +98,7 @@
             .setFeatureAfter(featureAfter);
     return buildActionForBinary(
         dataContext,
+        dataBindingContext,
         errorConsumer,
         builder,
         manifest,
@@ -125,6 +128,7 @@
 
     return buildActionForBinary(
         dataContext,
+        DataBinding.contextFrom(ruleContext),
         ruleContext,
         builder,
         manifest,
@@ -139,6 +143,7 @@
 
   private static ProcessedAndroidData buildActionForBinary(
       AndroidDataContext dataContext,
+      DataBindingContext dataBindingContext,
       RuleErrorConsumer errorConsumer,
       AndroidResourcesProcessorBuilder builder,
       StampedAndroidManifest manifest,
@@ -164,12 +169,13 @@
         .setCrunchPng(crunchPng)
         .withResourceDependencies(resourceDeps)
         .withAssetDependencies(assetDeps)
-        .build(dataContext, resources, assets, manifest);
+        .build(dataContext, resources, assets, manifest, dataBindingContext);
   }
 
   /** Processes Android data (assets, resources, and manifest) for android_local_test targets. */
   public static ProcessedAndroidData processLocalTestDataFrom(
       AndroidDataContext dataContext,
+      DataBindingContext dataBindingContext,
       StampedAndroidManifest manifest,
       Map<String, String> manifestValues,
       AndroidAaptVersion aaptVersion,
@@ -191,12 +197,13 @@
         .setCrunchPng(false)
         .withResourceDependencies(resourceDeps)
         .withAssetDependencies(assetDeps)
-        .build(dataContext, resources, assets, manifest);
+        .build(dataContext, resources, assets, manifest, dataBindingContext);
   }
 
   /** Processes Android data (assets, resources, and manifest) for android_test targets. */
   public static ProcessedAndroidData processTestDataFrom(
       AndroidDataContext dataContext,
+      DataBindingContext dataBindingContext,
       StampedAndroidManifest manifest,
       String packageUnderTest,
       boolean hasLocalResourceFiles,
@@ -220,7 +227,7 @@
             .withResourceDependencies(resourceDeps)
             .withAssetDependencies(assetDeps);
 
-    return builder.build(dataContext, resources, assets, manifest);
+    return builder.build(dataContext, resources, assets, manifest, dataBindingContext);
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java
index bda6e31..2ab400c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import java.util.Optional;
 import javax.annotation.Nullable;
 
@@ -286,6 +287,7 @@
    */
   public static ResourceApk processFromTransitiveLibraryData(
       AndroidDataContext dataContext,
+      DataBindingContext dataBindingContext,
       ResourceDependencies resourceDeps,
       AssetDependencies assetDeps,
       StampedAndroidManifest manifest)
@@ -303,6 +305,6 @@
         .withAssetDependencies(assetDeps)
         .setDebug(dataContext.useDebug())
         .setThrowOnResourceConflict(dataContext.getAndroidConfig().throwOnResourceConflict())
-        .buildWithoutLocalResources(dataContext, manifest);
+        .buildWithoutLocalResources(dataContext, manifest, dataBindingContext);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java
index de1d6f4..c70239b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java
@@ -195,11 +195,12 @@
         new MergedAndroidResources(
             new ParsedAndroidResources(
                 // Null out databinding to avoid accidentally propagating ActionCreationContext
-                new AndroidResources(getResources(), getResourceRoots(), null),
+                new AndroidResources(getResources(), getResourceRoots()),
                 getSymbols(),
                 getCompiledSymbols(),
                 getLabel(),
-                getStampedManifest()),
+                getStampedManifest(),
+                null),
             getMergedResources(),
             getClassJar(),
             getDataBindingInfoZip(),
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java
index 368303d..f2169b5 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java
@@ -25,6 +25,7 @@
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.Optional;
 import org.junit.Before;
@@ -145,14 +146,12 @@
       throws Exception {
     RuleContext ruleContext = getRuleContext();
     ValidatedAndroidResources unfiltered =
-        new AndroidResources(
-                unfilteredResources,
-                getResourceRoots(unfilteredResources),
-                DataBinding.asDisabledDataBindingContext())
+        new AndroidResources(unfilteredResources, getResourceRoots(unfilteredResources))
             .process(
                 ruleContext,
                 AndroidDataContext.forNative(ruleContext),
                 getManifest(),
+                DataBinding.contextFrom(ruleContext),
                 /* neverlink = */ false);
     Optional<? extends AndroidResources> maybeFiltered =
         assertFilter(unfiltered, filteredResources, /* isDependency = */ true);
@@ -180,10 +179,7 @@
       boolean isDependency)
       throws Exception {
     AndroidResources unfiltered =
-        new AndroidResources(
-            unfilteredResources,
-            getResourceRoots(unfilteredResources),
-            DataBinding.asDisabledDataBindingContext());
+        new AndroidResources(unfilteredResources, getResourceRoots(unfilteredResources));
     assertFilter(unfiltered, filteredResources, isDependency);
   }
 
@@ -230,7 +226,8 @@
     useConfiguration("--android_aapt=aapt");
 
     RuleContext ruleContext = getRuleContext();
-    ParsedAndroidResources parsed = assertParse(ruleContext, /* enableDataBinding = */ true);
+    ParsedAndroidResources parsed =
+        assertParse(ruleContext, DataBinding.asEnabledDataBindingContextFrom(ruleContext));
 
     // Since we are not using aapt2, there should be no compiled symbols
     assertThat(parsed.getCompiledSymbols()).isNull();
@@ -271,9 +268,9 @@
     mockAndroidSdkWithAapt2();
     useConfiguration("--android_sdk=//sdk:sdk", "--android_aapt=aapt2");
 
-    RuleContext ruleContext = getRuleContext();
+    RuleContext ruleContext = getRuleContextWithDataBinding();
 
-    ParsedAndroidResources parsed = assertParse(ruleContext, /* enableDataBinding = */ true);
+    ParsedAndroidResources parsed = assertParse(ruleContext);
 
     // The parse action should take resources and busybox artifacts in and output symbols
     assertActionArtifacts(
@@ -290,20 +287,20 @@
             .add(parsed.getManifest())
             .build(),
         /* outputs = */ ImmutableList.of(
-            parsed.getCompiledSymbols(), DataBinding.getSuffixedInfoFile(ruleContext, "_unused")));
+            parsed.getCompiledSymbols(),
+            ParsedAndroidResources.getDummyDataBindingArtifact(ruleContext)));
   }
 
   @Test
   public void testMergeDataBinding() throws Exception {
     useConfiguration("--android_aapt=aapt");
 
-    RuleContext ruleContext = getRuleContext();
+    RuleContext ruleContext = getRuleContextWithDataBinding();
     ParsedAndroidResources parsed = assertParse(ruleContext);
     MergedAndroidResources merged =
         parsed.merge(
             AndroidDataContext.forNative(ruleContext),
             ResourceDependencies.empty(),
-            /* enableDataBinding = */ true,
             AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
 
     // Besides processed manifest, inherited values should be equal
@@ -340,7 +337,6 @@
         parsed.merge(
             AndroidDataContext.forNative(ruleContext),
             ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
-            DataBinding.isEnabled(ruleContext),
             AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
 
     // Besides processed manifest, inherited values should be equal
@@ -502,7 +498,8 @@
                 false,
                 false,
                 null,
-                null)
+                null,
+                DataBinding.contextFrom(ruleContext))
             .generateRClass(dataContext, AndroidAaptVersion.AUTO);
 
     assertThat(resourceApk.getResourceProguardConfig()).isNotNull();
@@ -514,26 +511,23 @@
    * for further validation.
    */
   private ParsedAndroidResources assertParse(RuleContext ruleContext) throws Exception {
-    return assertParse(ruleContext, /* enableDataBinding = */ false);
+    return assertParse(ruleContext, DataBinding.contextFrom(ruleContext));
   }
 
-  private ParsedAndroidResources assertParse(RuleContext ruleContext, boolean enableDataBinding)
-      throws Exception {
-
+  private ParsedAndroidResources assertParse(
+      RuleContext ruleContext, DataBindingContext dataBindingContext) throws Exception {
     ImmutableList<Artifact> resources = getResources("values-en/foo.xml", "drawable-hdpi/bar.png");
     AndroidResources raw =
         new AndroidResources(
-            resources,
-            AndroidResources.getResourceRoots(ruleContext, resources, "resource_files"),
-            DataBinding.asDisabledDataBindingContext());
+            resources, AndroidResources.getResourceRoots(ruleContext, resources, "resource_files"));
     StampedAndroidManifest manifest = getManifest();
 
     ParsedAndroidResources parsed =
         raw.parse(
             AndroidDataContext.forNative(ruleContext),
             manifest,
-            enableDataBinding,
-            AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
+            AndroidAaptVersion.chooseTargetAaptVersion(ruleContext),
+            dataBindingContext);
 
     // Inherited values should be equal
     assertThat(raw).isEqualTo(new AndroidResources(parsed));
@@ -550,30 +544,19 @@
         .merge(
             AndroidDataContext.forNative(ruleContext),
             ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
-            DataBinding.isEnabled(ruleContext),
             AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
   }
 
   private ParsedAndroidResources makeParsedResources(RuleContext ruleContext)
       throws RuleErrorException, InterruptedException {
-    return makeParsedResources(ruleContext, /* enableDataBinding = */ false);
-  }
-
-  private ParsedAndroidResources makeParsedResources(
-      RuleContext ruleContext, boolean enableDataBinding)
-      throws RuleErrorException, InterruptedException {
     ImmutableList<Artifact> resources = getResources("values-en/foo.xml", "drawable-hdpi/bar.png");
     return new AndroidResources(
-            resources,
-            AndroidResources.getResourceRoots(ruleContext, resources, "resource_files"),
-            enableDataBinding
-                ? DataBinding.asEnabledDataBindingContextFrom(ruleContext)
-                : DataBinding.asDisabledDataBindingContext())
+            resources, AndroidResources.getResourceRoots(ruleContext, resources, "resource_files"))
         .parse(
             AndroidDataContext.forNative(ruleContext),
             getManifest(),
-            enableDataBinding,
-            AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
+            AndroidAaptVersion.chooseTargetAaptVersion(ruleContext),
+            DataBinding.contextFrom(ruleContext));
   }
 
   private ProcessedAndroidManifest getManifest() {
@@ -586,6 +569,10 @@
     return getRuleContext("android_library");
   }
 
+  private RuleContext getRuleContextWithDataBinding() throws Exception {
+    return getRuleContext("android_library", "enable_data_binding = 1");
+  }
+
   /** Gets a dummy rule context object by creating a dummy target. */
   private RuleContext getRuleContext(String kind, String... additionalLines) throws Exception {
     ConfiguredTarget target =
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java
index f569191..1793e42 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java
@@ -62,11 +62,7 @@
 
     return ResourceContainer.builder()
         .setAndroidResources(
-            AndroidResources.forResources(
-                errorConsumer,
-                resources,
-                "resource_files",
-                DataBinding.asDisabledDataBindingContext()))
+            AndroidResources.forResources(errorConsumer, resources, "resource_files"))
         .setLabel(label)
         .setManifestExported(false)
         .setManifest(manifest)
@@ -362,8 +358,7 @@
         AndroidResources.forResources(
             errorConsumer,
             ImmutableList.of(localResourceToKeep, localResourceToDiscard),
-            "resource_files",
-            DataBinding.asDisabledDataBindingContext());
+            "resource_files");
 
     ResourceDependencies resourceDependencies =
         ResourceDependencies.empty()
@@ -501,8 +496,7 @@
       ResourceFilterFactory resourceFilterFactory, ImmutableList<Artifact> artifacts)
       throws RuleErrorException {
     AndroidResources localResources =
-        AndroidResources.forResources(
-            errorConsumer, artifacts, "resource_files", DataBinding.asDisabledDataBindingContext());
+        AndroidResources.forResources(errorConsumer, artifacts, "resource_files");
 
     ResourceDependencies resourceDeps = ResourceDependencies.empty();