Update Android rules for Databinding V2.

RELNOTES[NEW]: Android Databinding v2 can be enabled with --experimental_android_databinding_v2.

PiperOrigin-RevId: 221710069
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index 113d995..f1306a1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -731,6 +731,11 @@
     return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
   }
 
+  @Override
+  public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
+    return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
+  }
+
   /**
    * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
    * clashes with artifacts created by other rules.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/ActionConstructionContext.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/ActionConstructionContext.java
index 2ce75c5..ce9c327 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/ActionConstructionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/ActionConstructionContext.java
@@ -81,6 +81,30 @@
   Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String relative);
 
   /**
+   * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
+   * clashes with artifacts created by other rules.
+   *
+   * @param uniqueDirectorySuffix suffix of the directory - it will be prepended
+   */
+  Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative);
+
+  /**
+   * Returns a path fragment qualified by the rule name and unique fragment to
+   * disambiguate artifacts produced from the source file appearing in
+   * multiple rules.
+   *
+   * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
+   */
+  public PathFragment getUniqueDirectory(PathFragment fragment);
+
+  /**
+   * Returns the root of either the "bin" or "genfiles" tree, based on this target and the current
+   * configuration. The choice of which tree to use is based on the rule with which this target
+   * (which must be an OutputFile or a Rule) is associated.
+   */
+  public ArtifactRoot getBinOrGenfilesDirectory();
+
+  /**
    * Returns the root-relative path fragment under which output artifacts of this rule should go.
    *
    * <p>Note that:
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
index 0ac3bfa..5a97842 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
@@ -878,10 +878,17 @@
       JavaSemantics semantics,
       DataBindingContext dataBindingContext,
       boolean isLibrary) {
-    ImmutableList<Artifact> srcs =
-        dataBindingContext.addAnnotationFileToSrcs(
-            ruleContext.getPrerequisiteArtifacts("srcs", RuleConfiguredTarget.Mode.TARGET).list(),
-            ruleContext);
+
+    ImmutableList<Artifact> ruleSources =
+        ruleContext.getPrerequisiteArtifacts("srcs", RuleConfiguredTarget.Mode.TARGET).list();
+
+    ImmutableList<Artifact> dataBindingSources =
+        dataBindingContext.getAnnotationSourceFiles(ruleContext);
+
+    ImmutableList<Artifact> srcs = ImmutableList.<Artifact>builder()
+        .addAll(ruleSources)
+        .addAll(dataBindingSources)
+        .build();
 
     ImmutableList<TransitiveInfoCollection> compileDeps;
     ImmutableList<TransitiveInfoCollection> runtimeDeps;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataBindingProcessorBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataBindingProcessorBuilder.java
new file mode 100644
index 0000000..af31cf9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataBindingProcessorBuilder.java
@@ -0,0 +1,98 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.rules.android;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/** Builder for creating databinding processing action. */
+public class AndroidDataBindingProcessorBuilder {
+
+  /**
+   * Creates and registers an action to strip databinding from layout xml and generate the layout
+   * info file.
+   *
+   * @param dataContext The android data context.
+   * @param androidResources The resources to process.
+   * @param appId The app id (the app's java package).
+   * @param dataBindingLayoutInfoOut The output layout info file to write.
+   * @return The new AndroidResources that has been processed by databinding.
+   */
+  public static AndroidResources create(
+      AndroidDataContext dataContext,
+      AndroidResources androidResources,
+      String appId,
+      Artifact dataBindingLayoutInfoOut) {
+
+    ImmutableList.Builder<Artifact> databindingProcessedResourcesBuilder = ImmutableList.builder();
+    for (Artifact resource : androidResources.getResources()) {
+
+      // Create resources that will be processed by databinding under paths that look like:
+      //
+      // <bazel-pkg>/databinding-processed-resources/<rule-name>/<bazal-pkg>/<resource-dir>
+
+      Artifact databindingProcessedResource =
+          dataContext.getUniqueDirectoryArtifact("databinding-processed-resources",
+              resource.getRootRelativePath());
+
+      databindingProcessedResourcesBuilder.add(databindingProcessedResource);
+    }
+    ImmutableList<Artifact> databindingProcessedResources =
+        databindingProcessedResourcesBuilder.build();
+
+    BusyBoxActionBuilder builder = BusyBoxActionBuilder.create(dataContext, "PROCESS_DATABINDING");
+
+    // Create output resource roots that correspond to the paths of the resources created above:
+    //
+    //   <bazel-pkg>/databinding-processed-resources/<rule-name>/<resource-root>
+    //
+    // AndroidDataBindingProcessingAction will append each value of --resource_root to its
+    // corresponding --output_resource_root, so the only part that needs to be constructed here is
+    //
+    //   <bazel-pkg>/databinding-processed-resources/<rule-name>
+    ArtifactRoot binOrGenfiles = dataContext.getBinOrGenfilesDirectory();
+    PathFragment uniqueDir =
+        dataContext.getUniqueDirectory(PathFragment.create("databinding-processed-resources"));
+    PathFragment outputResourceRoot = binOrGenfiles.getExecPath().getRelative(uniqueDir);
+
+    ImmutableList.Builder<PathFragment> outputResourceRootsBuilder = ImmutableList.builder();
+    for (PathFragment resourceRoot : androidResources.getResourceRoots()) {
+
+      outputResourceRootsBuilder.add(outputResourceRoot);
+
+      // The order of these matter, the input root and the output root have to be matched up
+      // because the resource processor will iterate over them in pairs.
+      builder.addFlag("--resource_root", resourceRoot.toString());
+      builder.addFlag("--output_resource_root", outputResourceRoot.toString());
+    }
+
+    // Even though the databinding processor really only cares about layout files, we send
+    // all the resources so that the new resource root that is created for databinding processing
+    // can be used for later processing (e.g. aapt). It would be nice to send only the layout
+    // files, but then we'd have to mix roots and rely on sandboxing to "hide" the
+    // old unprocessed files, which might not work if, for example, the actions run locally.
+    builder.addInputs(androidResources.getResources());
+
+    builder.addOutputs(databindingProcessedResources);
+
+    builder.addOutput("--dataBindingInfoOut", dataBindingLayoutInfoOut);
+    builder.addFlag("--appId", appId);
+
+    builder.buildAndRegister("Processing data binding", "ProcessDatabinding");
+
+    return new AndroidResources(databindingProcessedResources, outputResourceRootsBuilder.build());
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java
index 45463ac..aa65bc2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java
@@ -15,6 +15,7 @@
 
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
@@ -24,6 +25,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
 import com.google.devtools.build.lib.skylarkbuildapi.android.AndroidDataContextApi;
+import com.google.devtools.build.lib.vfs.PathFragment;
 
 /**
  * Wraps common tools and settings used for working with Android assets, resources, and manifests.
@@ -37,26 +39,30 @@
  * are used in BusyBox actions.
  */
 public class AndroidDataContext implements AndroidDataContextApi {
+
   private final Label label;
   private final ActionConstructionContext actionConstructionContext;
   private final FilesToRunProvider busybox;
   private final AndroidSdkProvider sdk;
   private final boolean persistentBusyboxToolsEnabled;
+  private final boolean useDataBindingV2;
 
   public static AndroidDataContext forNative(RuleContext ruleContext) {
     return makeContext(ruleContext);
   }
 
   public static AndroidDataContext makeContext(RuleContext ruleContext) {
+    AndroidConfiguration androidConfig = ruleContext
+        .getConfiguration()
+        .getFragment(AndroidConfiguration.class);
+
     return new AndroidDataContext(
         ruleContext.getLabel(),
         ruleContext,
         ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST),
-        ruleContext
-            .getConfiguration()
-            .getFragment(AndroidConfiguration.class)
-            .persistentBusyboxTools(),
-        AndroidSdkProvider.fromRuleContext(ruleContext));
+        androidConfig.persistentBusyboxTools(),
+        AndroidSdkProvider.fromRuleContext(ruleContext),
+        androidConfig.useDataBindingV2());
   }
 
   protected AndroidDataContext(
@@ -64,12 +70,14 @@
       ActionConstructionContext actionConstructionContext,
       FilesToRunProvider busybox,
       boolean persistentBusyboxToolsEnabled,
-      AndroidSdkProvider sdk) {
+      AndroidSdkProvider sdk,
+      boolean useDataBindingV2) {
     this.label = label;
     this.persistentBusyboxToolsEnabled = persistentBusyboxToolsEnabled;
     this.actionConstructionContext = actionConstructionContext;
     this.busybox = busybox;
     this.sdk = sdk;
+    this.useDataBindingV2 = useDataBindingV2;
   }
 
   public Label getLabel() {
@@ -111,6 +119,22 @@
     return actionConstructionContext.getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative);
   }
 
+  public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
+    return actionConstructionContext.getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative);
+  }
+
+  public PathFragment getUniqueDirectory(PathFragment fragment) {
+    return actionConstructionContext.getUniqueDirectory(fragment);
+  }
+
+  public ArtifactRoot getBinOrGenfilesDirectory() {
+    return actionConstructionContext.getBinOrGenfilesDirectory();
+  }
+
+  public PathFragment getPackageDirectory() {
+    return actionConstructionContext.getPackageDirectory();
+  }
+
   public AndroidConfiguration getAndroidConfig() {
     return actionConstructionContext.getConfiguration().getFragment(AndroidConfiguration.class);
   }
@@ -124,4 +148,8 @@
   public boolean isPersistentBusyboxToolsEnabled() {
     return persistentBusyboxToolsEnabled;
   }
+
+  public boolean useDataBindingV2() {
+    return useDataBindingV2;
+  }
 }
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 724f989..f781d05 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
@@ -214,12 +214,6 @@
       StampedAndroidManifest primaryManifest,
       DataBindingContext dataBindingContext) {
 
-    if (aaptVersion == AndroidAaptVersion.AAPT2) {
-      createAapt2ApkAction(dataContext, primaryResources, primaryAssets, primaryManifest);
-    } else {
-      createAaptAction(dataContext, primaryResources, primaryAssets, primaryManifest);
-    }
-
     // Wrap the new manifest, if any
     ProcessedAndroidManifest processedManifest =
         new ProcessedAndroidManifest(
@@ -227,10 +221,28 @@
             primaryManifest.getPackage(),
             primaryManifest.isExported());
 
+    // In databinding v2, this strips out the databinding and generates the layout info file.
+    AndroidResources databindingProcessedResources = dataBindingContext.processResources(
+        dataContext, primaryResources, processedManifest.getPackage());
+
+    if (aaptVersion == AndroidAaptVersion.AAPT2) {
+      createAapt2ApkAction(
+          dataContext,
+          databindingProcessedResources,
+          primaryAssets,
+          primaryManifest);
+    } else {
+      createAaptAction(
+          dataContext,
+          databindingProcessedResources,
+          primaryAssets,
+          primaryManifest);
+    }
+
     // Wrap the parsed resources
     ParsedAndroidResources parsedResources =
         ParsedAndroidResources.of(
-            primaryResources,
+            databindingProcessedResources,
             symbols,
             /* compiledSymbols = */ null,
             dataContext.getLabel(),
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 407f737..df9fb65 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -442,6 +442,11 @@
               attr(DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, LABEL)
                   .cfg(HostTransition.INSTANCE)
                   .value(env.getToolsLabel("//tools/android:databinding_annotation_processor")))
+          .add(
+              attr(DataBinding.DATABINDING_EXEC_PROCESSOR_ATTR, LABEL)
+                  .cfg(HostTransition.INSTANCE)
+                  .exec()
+                  .value(env.getToolsLabel("//tools/android:databinding_exec")))
           .advertiseSkylarkProvider(
               SkylarkProviderIdentifier.forKey(AndroidResourcesInfo.PROVIDER.getKey()))
           .advertiseSkylarkProvider(
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 d816107..f07d87e 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
@@ -93,7 +93,7 @@
       }
       return ResourceApk.processFromTransitiveLibraryData(
               ctx,
-              DataBinding.asDisabledDataBindingContext(),
+              DataBinding.getDisabledDataBindingContext(ctx),
               ResourceDependencies.fromProviders(deps, /* neverlink = */ neverlink),
               AssetDependencies.empty(),
               StampedAndroidManifest.createEmpty(
@@ -374,7 +374,7 @@
                 AndroidManifest.forAarImport(androidManifestArtifact),
                 ResourceDependencies.fromProviders(
                     getProviders(deps, AndroidResourcesInfo.PROVIDER), /* neverlink = */ false),
-                DataBinding.asDisabledDataBindingContext(),
+                DataBinding.getDisabledDataBindingContext(ctx),
                 aaptVersion);
 
     MergedAndroidAssets mergedAssets =
@@ -420,7 +420,7 @@
               ctx,
               getAndroidSemantics(),
               errorReporter,
-              DataBinding.asDisabledDataBindingContext(),
+              DataBinding.getDisabledDataBindingContext(ctx),
               rawManifest,
               AndroidResources.from(errorReporter, getFileProviders(resources), "resource_files"),
               AndroidAssets.from(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
index c1cd19f..eb61855 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
@@ -98,6 +98,12 @@
     return this;
   }
 
+  /** Adds the given input artifacts without any command line options. */
+  public BusyBoxActionBuilder addInputs(Iterable<Artifact> inputs) {
+    this.inputs.addAll(inputs);
+    return this;
+  }
+
   /** Adds an input artifact if it is non-null */
   public BusyBoxActionBuilder maybeAddInput(
       @CompileTimeConstant String arg, @Nullable Artifact value) {
@@ -150,6 +156,12 @@
     return this;
   }
 
+  /** Adds the given output artifacts without adding any command line options. */
+  public BusyBoxActionBuilder addOutputs(Iterable<Artifact> outputs) {
+    this.outputs.addAll(outputs);
+    return this;
+  }
+
   /** Adds an output artifact if it is non-null */
   public BusyBoxActionBuilder maybeAddOutput(
       @CompileTimeConstant String arg, @Nullable Artifact value) {
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 256d6f3..9dcf277 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
@@ -56,6 +56,10 @@
                   getDummyDataBindingArtifact(dataContext.getActionConstructionContext())));
     }
 
+    // In databinding v2, this strips out the databinding and generates the layout info file.
+    AndroidResources databindingProcessedResources =
+        dataBindingContext.processResources(dataContext, resources, manifest.getPackage());
+
     return builder
         .setOutput(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS))
         .setCompiledSymbolsOutput(
@@ -64,7 +68,7 @@
                 : null)
         .build(
             dataContext,
-            dataBindingContext.processResources(resources),
+            databindingProcessedResources,
             manifest,
             dataBindingContext);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBinding.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBinding.java
index 6285a1a..d21e344 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBinding.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBinding.java
@@ -13,21 +13,26 @@
 // limitations under the License.
 package com.google.devtools.build.lib.rules.android.databinding;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
+import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
 import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.rules.android.AndroidCommon;
 import com.google.devtools.build.lib.rules.android.AndroidConfiguration;
+import com.google.devtools.build.lib.rules.android.AndroidDataContext;
 import com.google.devtools.build.lib.rules.android.AndroidResources;
 import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.ResourceFileLoader;
 import com.google.devtools.build.lib.vfs.PathFragment;
+import java.io.IOException;
 import java.util.List;
+import javax.annotation.Nullable;
 
 /**
  * Support logic for Bazel's <a
@@ -53,67 +58,53 @@
  * via the implicit dependencies specified inside this class.
  */
 public final class DataBinding {
+
   /** The rule attribute supplying data binding's annotation processor. */
   public static final String DATABINDING_ANNOTATION_PROCESSOR_ATTR =
       "$databinding_annotation_processor";
 
+  /** The rule attribute supplying data binding's build helper (exec). */
+  public static final String DATABINDING_EXEC_PROCESSOR_ATTR = "$databinding_exec";
+
   private static final String ENABLE_DATA_BINDING_ATTR = "enable_data_binding";
 
-  private static final DataBindingContext DISABLED_CONTEXT = new DisabledDataBindingV1Context();
+  /** The directory where the annotation processor looks for dep metadata. */
+  private static final String DEP_METADATA_INPUT_DIR = "dependent-lib-artifacts";
+
+  /** The directory where the annotation processor writes metadata output for the current rule. */
+  private static final String METADATA_OUTPUT_DIR = "bin-files";
+
+  @VisibleForTesting
+  public static final DataBindingContext DISABLED_V1_CONTEXT = new DisabledDataBindingV1Context();
+
+  private static final DataBindingContext DISABLED_V2_CONTEXT = new DisabledDataBindingV2Context();
 
   /** Supplies a databinding context from a rulecontext. */
   public static DataBindingContext contextFrom(
       RuleContext ruleContext, AndroidConfiguration androidConfig) {
-    if (isEnabled(ruleContext)) {
-      if (androidConfig.useDataBindingV2()) {
-        return asEnabledDataBindingV2ContextFrom(ruleContext);
-      }
-      return asEnabledDataBindingV1ContextFrom(ruleContext);
-    }
-    return asDisabledDataBindingContext();
+
+    return contextFrom(isEnabled(ruleContext), ruleContext, androidConfig);
   }
 
   /** Supplies a databinding context from an action context. */
   public static DataBindingContext contextFrom(
       boolean enabled, ActionConstructionContext context, AndroidConfiguration androidConfig) {
+
     if (enabled) {
       if (androidConfig.useDataBindingV2()) {
-        return asEnabledDataBindingV2ContextFrom(context);
+        return new DataBindingV2Context(context);
+      } else {
+        return new DataBindingV1Context(context);
       }
-      return asEnabledDataBindingV1ContextFrom(context);
+    } else {
+      if (androidConfig.useDataBindingV2()) {
+        return DISABLED_V2_CONTEXT;
+      } else {
+        return DISABLED_V1_CONTEXT;
+      }
     }
-    return asDisabledDataBindingContext();
   }
 
-  /** Supplies an enabled DataBindingContext from the action context. */
-  private static DataBindingContext asEnabledDataBindingV1ContextFrom(
-      ActionConstructionContext actionContext) {
-    return new DataBindingV1Context(actionContext);
-  }
-
-  private static DataBindingContext asEnabledDataBindingV2ContextFrom(
-      ActionConstructionContext actionContext) {
-    return new DataBindingV2Context(actionContext);
-  }
-
-  /** Supplies a disabled (no-op) DataBindingContext. */
-  public static DataBindingContext asDisabledDataBindingContext() {
-    return DISABLED_CONTEXT;
-  }
-
-  /**
-   * Annotation processing creates the following metadata files that describe how data binding is
-   * applied. The full file paths include prefixes as implemented in {@link #getMetadataOutputs}.
-   */
-  private static final ImmutableList<String> METADATA_OUTPUT_SUFFIXES =
-      ImmutableList.of("setter_store.bin", "layoutinfo.bin", "br.bin");
-
-  /** The directory where the annotation processor looks for dep metadata. */
-  private static final String DEP_METADATA_INPUT_DIR = "dependent-lib-artifacts";
-
-  /** The directory where the annotation processor write metadata output for the current rule. */
-  private static final String METADATA_OUTPUT_DIR = "bin-files";
-
   /**
    * Should data binding support be enabled for this rule?
    *
@@ -127,6 +118,15 @@
             ruleContext.attributes().get(ENABLE_DATA_BINDING_ATTR, Type.BOOLEAN));
   }
 
+  /** Supplies a disabled (no-op) DataBindingContext. */
+  public static DataBindingContext getDisabledDataBindingContext(AndroidDataContext ctx) {
+    if (ctx.useDataBindingV2()) {
+      return DISABLED_V2_CONTEXT;
+    } else {
+      return DISABLED_V1_CONTEXT;
+    }
+  }
+
   /** Returns this rule's data binding base output dir (as an execroot-relative path). */
   static PathFragment getDataBindingExecPath(RuleContext ruleContext) {
     return ruleContext
@@ -135,6 +135,10 @@
         .getRelative(ruleContext.getUniqueDirectory("databinding"));
   }
 
+  static Artifact getLayoutInfoFile(ActionConstructionContext actionConstructionContext) {
+    return actionConstructionContext.getUniqueDirectoryArtifact("databinding", "layout-info.zip");
+  }
+
   /** Returns an artifact for the specified output under a standardized data binding base dir. */
   static Artifact getDataBindingArtifact(RuleContext ruleContext, String relativePath) {
     PathFragment binRelativeBasePath =
@@ -149,26 +153,31 @@
     return String.format("-Aandroid.databinding.%s=%s", flag, value);
   }
 
-  /**
-   * Adds the appropriate {@link UsesDataBindingProvider} for a rule if it should expose one.
-   *
-   * <p>A rule exposes {@link UsesDataBindingProvider} if either it or its deps set {@code
-   * enable_data_binding = 1}.
-   */
-  static void maybeAddProvider(
-      List<Artifact> dataBindingMetadataOutputs,
-      RuleConfiguredTargetBuilder builder,
-      RuleContext ruleContext) {
-    // Expose the data binding provider if there are outputs.
-    dataBindingMetadataOutputs.addAll(getTransitiveMetadata(ruleContext, "exports"));
-    if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) {
-      // If this rule doesn't declare direct resources, no resource processing is run so no data
-      // binding outputs are produced. In that case, we need to explicitly propagate data binding
-      // outputs from the deps to make sure they continue up the build graph.
-      dataBindingMetadataOutputs.addAll(getTransitiveMetadata(ruleContext, "deps"));
-    }
-    if (!dataBindingMetadataOutputs.isEmpty()) {
-      builder.addNativeDeclaredProvider(new UsesDataBindingProvider(dataBindingMetadataOutputs));
+  /** Turns a key/value pair into a javac annotation processor flag received by data binding. */
+  static String createProcessorFlag(String flag, Artifact value) {
+    return createProcessorFlag(flag, value.getExecPathString());
+  }
+
+  static ImmutableList<Artifact> getAnnotationFile(RuleContext ruleContext) {
+    // Add this rule's annotation processor input. If the rule doesn't have direct resources,
+    // there's no direct data binding info, so there's strictly no need for annotation processing.
+    // But it's still important to process the deps' .bin files so any Java class references get
+    // re-referenced so they don't get filtered out of the compilation classpath by JavaBuilder
+    // (which filters out classpath .jars that "aren't used": see --reduce_classpath). If data
+    // binding didn't reprocess a library's data binding expressions redundantly up the dependency
+    // chain (meaning each depender processes them again as if they were its own), this problem
+    // wouldn't happen.
+    try {
+      String contents =
+          ResourceFileLoader.loadResource(
+              DataBinding.class, "databinding_annotation_template.txt");
+      Artifact annotationFile = getDataBindingArtifact(ruleContext, "DataBindingInfo.java");
+      ruleContext.registerAction(
+          FileWriteAction.create(ruleContext, annotationFile, contents, false));
+      return ImmutableList.of(annotationFile);
+    } catch (IOException e) {
+      ruleContext.ruleError("Cannot load annotation processor template: " + e.getMessage());
+      return ImmutableList.of();
     }
   }
 
@@ -196,7 +205,10 @@
    * would be a class redefinition conflict. But by feeding the library's metadata outputs into the
    * binary's compilation, enough information is available to only use the first version.
    */
-  static List<Artifact> getMetadataOutputs(RuleContext ruleContext) {
+  static ImmutableList<Artifact> getMetadataOutputs(
+      RuleContext ruleContext,
+      List<String> metadataOutputSuffixes) {
+
     if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) {
       // If this rule doesn't define local resources, no resource processing was done, so it
       // doesn't produce data binding output.
@@ -204,7 +216,7 @@
     }
     ImmutableList.Builder<Artifact> outputs = ImmutableList.<Artifact>builder();
     String javaPackage = AndroidCommon.getJavaPackage(ruleContext);
-    for (String suffix : METADATA_OUTPUT_SUFFIXES) {
+    for (String suffix : metadataOutputSuffixes) {
       // The annotation processor automatically creates files with this naming pattern under the
       // {@code -Aandroid.databinding.generationalFileOutDir} base directory.
       outputs.add(
@@ -215,28 +227,50 @@
     return outputs.build();
   }
 
+  @Nullable
+  static Artifact getMetadataOutput(
+      RuleContext ruleContext,
+      String metadataOutputSuffix) {
+
+    if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      // If this rule doesn't define local resources, no resource processing was done, so it
+      // doesn't produce data binding output.
+      return null;
+    }
+    String javaPackage = AndroidCommon.getJavaPackage(ruleContext);
+
+    // The annotation processor automatically creates files with this naming pattern under the
+    // {@code -Aandroid.databinding.generationalFileOutDir} base directory.
+    return getDataBindingArtifact(
+            ruleContext,
+            String.format("%s/%s-%s-%s",
+                METADATA_OUTPUT_DIR, javaPackage, javaPackage, metadataOutputSuffix));
+  }
+
   /**
    * Data binding's annotation processor reads the transitive metadata outputs of the target's deps
-   * (see {@link #getMetadataOutputs(RuleContext)}) in the directory specified by the processor flag
-   * {@code -Aandroid.databinding.bindingBuildFolder}. Since dependencies don't generate their
-   * outputs under a common directory, we symlink them into a common place here.
+   * (see {@link #getMetadataOutputs(RuleContext, List<String>)}) in the directory specified by the
+   * processor flag {@code -Aandroid.databinding.bindingBuildFolder}. Since dependencies don't
+   * generate their outputs under a common directory, we symlink them into a common place here.
    *
    * @return the symlink paths of the transitive dep metadata outputs for this rule
    */
-  static Artifact symlinkDepsMetadataIntoOutputTree(
-      RuleContext ruleContext, Artifact depMetadata) {
+  static Artifact symlinkDepsMetadataIntoOutputTree(RuleContext ruleContext, Artifact depMetadata) {
+
     Label ruleLabel = ruleContext.getRule().getLabel();
     Artifact symlink =
         getDataBindingArtifact(
             ruleContext,
             String.format(
                 "%s/%s", DEP_METADATA_INPUT_DIR, depMetadata.getRootRelativePathString()));
-    ruleContext.registerAction(SymlinkAction.toArtifact(
-        ruleContext.getActionOwner(),
-        depMetadata,
-        symlink,
-        String.format(
-            "Symlinking dep metadata output %s for %s", depMetadata.getFilename(), ruleLabel)));
+    ruleContext.registerAction(
+        SymlinkAction.toArtifact(
+            ruleContext.getActionOwner(),
+            depMetadata,
+            symlink,
+            String.format(
+                "Symlinking dep metadata output %s for %s", depMetadata.getFilename(), ruleLabel)));
     return symlink;
   }
+
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingContext.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingContext.java
index 95802c2..726a163 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingContext.java
@@ -17,6 +17,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.rules.android.AndroidDataContext;
 import com.google.devtools.build.lib.rules.android.AndroidResources;
 import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider;
 import java.util.function.BiConsumer;
@@ -55,16 +56,22 @@
 
   /** The javac flags that are needed to configure data binding's annotation processor. */
   void supplyJavaCoptsUsing(
-      RuleContext ruleContext, boolean isBinary, Consumer<Iterable<String>> consumer);
+      RuleContext ruleContext,
+      boolean isBinary,
+      Consumer<Iterable<String>> consumer);
 
   /**
    * Adds data binding's annotation processor as a plugin to the given Java compilation context.
    *
    * <p>This extends the Java compilation to translate data binding .xml into corresponding
    * classes.
+   *
+   * The BiConsumer accepts as its first argument the JavaPluginInfoProvider, and the list of
+   * outputs of the processor as the second argument.
    */
   void supplyAnnotationProcessor(
-      RuleContext ruleContext, BiConsumer<JavaPluginInfoProvider, Iterable<Artifact>> consumer);
+      RuleContext ruleContext,
+      BiConsumer<JavaPluginInfoProvider, Iterable<Artifact>> consumer);
 
   /**
    * Processes deps that also apply data binding.
@@ -83,8 +90,7 @@
    * <p>This triggers the annotation processor. Annotation processor settings are configured
    * separately in {@link #supplyJavaCoptsUsing(RuleContext, boolean, Consumer)}.
    */
-  ImmutableList<Artifact> addAnnotationFileToSrcs(
-      ImmutableList<Artifact> srcs, RuleContext ruleContext);
+  ImmutableList<Artifact> getAnnotationSourceFiles(RuleContext ruleContext);
 
   /**
    * Adds the appropriate {@link UsesDataBindingProvider} for a rule if it should expose one.
@@ -94,5 +100,12 @@
    */
   void addProvider(RuleConfiguredTargetBuilder builder, RuleContext ruleContext);
 
-  AndroidResources processResources(AndroidResources resources);
+  /**
+   * Process the given Android Resources for databinding. In databinding v2, this strips out the
+   * databinding and generates the layout info file.
+   */
+  AndroidResources processResources(
+      AndroidDataContext dataContext,
+      AndroidResources resources,
+      String appId);
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV1Context.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV1Context.java
index bea5df8..f136ec9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV1Context.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV1Context.java
@@ -14,7 +14,6 @@
 package com.google.devtools.build.lib.rules.android.databinding;
 
 import static com.google.devtools.build.lib.rules.android.databinding.DataBinding.createProcessorFlag;
-import static com.google.devtools.build.lib.rules.android.databinding.DataBinding.getDataBindingExecPath;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -22,21 +21,25 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
-import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.rules.android.AndroidCommon;
+import com.google.devtools.build.lib.rules.android.AndroidDataContext;
 import com.google.devtools.build.lib.rules.android.AndroidResources;
 import com.google.devtools.build.lib.rules.java.JavaInfo;
 import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider;
-import com.google.devtools.build.lib.util.ResourceFileLoader;
-import java.io.IOException;
 import java.util.List;
-import java.util.Objects;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 final class DataBindingV1Context implements DataBindingContext {
 
+  /**
+   * Annotation processing creates the following metadata files that describe how data binding is
+   * applied. The full file paths include prefixes as implemented in {@link #getMetadataOutputs}.
+   */
+  private static final ImmutableList<String> METADATA_OUTPUT_SUFFIXES_V1 =
+      ImmutableList.of("setter_store.bin", "layoutinfo.bin", "br.bin");
+
   private final ActionConstructionContext actionConstructionContext;
 
   DataBindingV1Context(ActionConstructionContext actionConstructionContext) {
@@ -45,18 +48,15 @@
 
   @Override
   public void supplyLayoutInfo(Consumer<Artifact> consumer) {
-    consumer.accept(layoutInfoFile());
-  }
-
-  Artifact layoutInfoFile() {
-    return actionConstructionContext.getUniqueDirectoryArtifact("databinding", "layout-info.zip");
+    consumer.accept(DataBinding.getLayoutInfoFile(actionConstructionContext));
   }
 
   @Override
   public void supplyJavaCoptsUsing(
       RuleContext ruleContext, boolean isBinary, Consumer<Iterable<String>> consumer) {
+
     ImmutableList.Builder<String> flags = ImmutableList.builder();
-    String metadataOutputDir = getDataBindingExecPath(ruleContext).getPathString();
+    String metadataOutputDir = DataBinding.getDataBindingExecPath(ruleContext).getPathString();
 
     // Directory where the annotation processor looks for deps metadata output. The annotation
     // processor automatically appends {@link DEP_METADATA_INPUT_DIR} to this path. Individual
@@ -75,7 +75,7 @@
 
     // The path where data binding's resource processor wrote its output (the data binding XML
     // expressions). The annotation processor reads this file to translate that XML into Java.
-    flags.add(createProcessorFlag("xmlOutDir", getDataBindingExecPath(ruleContext).toString()));
+    flags.add(createProcessorFlag("xmlOutDir", metadataOutputDir));
 
     // Unused.
     flags.add(createProcessorFlag("exportClassListTo", "/tmp/exported_classes"));
@@ -84,7 +84,9 @@
     flags.add(createProcessorFlag("modulePackage", AndroidCommon.getJavaPackage(ruleContext)));
 
     // The minimum Android SDK compatible with this rule.
-    flags.add(createProcessorFlag("minApi", "14")); // TODO(gregce): update this
+    // TODO(bazel-team): This probably should be based on the actual min-sdk from the manifest,
+    // or an appropriate rule attribute.
+    flags.add(createProcessorFlag("minApi", "14"));
 
     // If enabled, produces cleaner output for Android Studio.
     flags.add(createProcessorFlag("printEncodedErrors", "0"));
@@ -94,80 +96,64 @@
 
   @Override
   public void supplyAnnotationProcessor(
-      RuleContext ruleContext, BiConsumer<JavaPluginInfoProvider, Iterable<Artifact>> consumer) {
-    consumer.accept(
-        JavaInfo.getProvider(
-            JavaPluginInfoProvider.class,
-            ruleContext.getPrerequisite(
-                DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, RuleConfiguredTarget.Mode.HOST)),
-        DataBinding.getMetadataOutputs(ruleContext));
+      RuleContext ruleContext,
+      BiConsumer<JavaPluginInfoProvider, Iterable<Artifact>> consumer) {
+
+    JavaPluginInfoProvider javaPluginInfoProvider = JavaInfo.getProvider(
+        JavaPluginInfoProvider.class,
+        ruleContext.getPrerequisite(
+            DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, RuleConfiguredTarget.Mode.HOST));
+
+    ImmutableList<Artifact> annotationProcessorOutputs =
+        DataBinding.getMetadataOutputs(ruleContext, METADATA_OUTPUT_SUFFIXES_V1);
+
+    consumer.accept(javaPluginInfoProvider, annotationProcessorOutputs);
   }
 
   @Override
   public ImmutableList<Artifact> processDeps(RuleContext ruleContext) {
+
     ImmutableList.Builder<Artifact> dataBindingJavaInputs = ImmutableList.builder();
     if (AndroidResources.definesAndroidResources(ruleContext.attributes())) {
-      dataBindingJavaInputs.add(layoutInfoFile());
+      dataBindingJavaInputs.add(DataBinding.getLayoutInfoFile(actionConstructionContext));
     }
+
     for (Artifact dataBindingDepMetadata : DataBinding.getTransitiveMetadata(ruleContext, "deps")) {
       dataBindingJavaInputs.add(
           DataBinding.symlinkDepsMetadataIntoOutputTree(ruleContext, dataBindingDepMetadata));
     }
+
     return dataBindingJavaInputs.build();
   }
 
   @Override
-  public ImmutableList<Artifact> addAnnotationFileToSrcs(
-      ImmutableList<Artifact> srcs, RuleContext ruleContext) {
-    // Add this rule's annotation processor input. If the rule doesn't have direct resources,
-    // there's no direct data binding info, so there's strictly no need for annotation processing.
-    // But it's still important to process the deps' .bin files so any Java class references get
-    // re-referenced so they don't get filtered out of the compilation classpath by JavaBuilder
-    // (which filters out classpath .jars that "aren't used": see --reduce_classpath). If data
-    // binding didn't reprocess a library's data binding expressions redundantly up the dependency
-    // chain (meaning each depender processes them again as if they were its own), this problem
-    // wouldn't happen.
-    try {
-      String contents =
-          ResourceFileLoader.loadResource(
-              DataBinding.class, "databinding_annotation_template.txt");
-      Artifact annotationFile = DataBinding
-          .getDataBindingArtifact(ruleContext, "DataBindingInfo.java");
-      ruleContext.registerAction(
-          FileWriteAction.create(ruleContext, annotationFile, contents, false));
-      return ImmutableList.<Artifact>builder().addAll(srcs).add(annotationFile).build();
-    } catch (IOException e) {
-      ruleContext.ruleError("Cannot load annotation processor template: " + e.getMessage());
-      return ImmutableList.of();
-    }
+  public ImmutableList<Artifact> getAnnotationSourceFiles(RuleContext ruleContext) {
+    return DataBinding.getAnnotationFile(ruleContext);
   }
 
   @Override
   public void addProvider(RuleConfiguredTargetBuilder builder, RuleContext ruleContext) {
-    List<Artifact> dataBindingMetadataOutputs =
-        Lists.newArrayList(DataBinding.getMetadataOutputs(ruleContext));
-    DataBinding.maybeAddProvider(dataBindingMetadataOutputs, builder, ruleContext);
-  }
 
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
+    List<Artifact> dataBindingMetadataOutputs = Lists.newArrayList(
+        DataBinding.getMetadataOutputs(ruleContext, METADATA_OUTPUT_SUFFIXES_V1));
+
+    // Expose the data binding provider if there are outputs.
+    dataBindingMetadataOutputs.addAll(DataBinding.getTransitiveMetadata(ruleContext, "exports"));
+    if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      // If this rule doesn't declare direct resources, no resource processing is run so no data
+      // binding outputs are produced. In that case, we need to explicitly propagate data binding
+      // outputs from the deps to make sure they continue up the build graph.
+      dataBindingMetadataOutputs.addAll(DataBinding.getTransitiveMetadata(ruleContext, "deps"));
     }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
+    if (!dataBindingMetadataOutputs.isEmpty()) {
+      builder.addNativeDeclaredProvider(
+          new UsesDataBindingProvider(dataBindingMetadataOutputs));
     }
-    DataBindingV1Context that = (DataBindingV1Context) o;
-    return Objects.equals(actionConstructionContext, that.actionConstructionContext);
   }
 
   @Override
-  public int hashCode() {
-    return actionConstructionContext.hashCode();
-  }
-
-  @Override
-  public AndroidResources processResources(AndroidResources resources) {
+  public AndroidResources processResources(
+      AndroidDataContext dataContext, AndroidResources resources, String appId) {
     return resources;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java
index 28661d5..642a8f8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java
@@ -13,63 +13,303 @@
 // limitations under the License.
 package com.google.devtools.build.lib.rules.android.databinding;
 
+import static com.google.devtools.build.lib.rules.android.databinding.DataBinding.createProcessorFlag;
+
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+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.AndroidCommon;
+import com.google.devtools.build.lib.rules.android.AndroidDataBindingProcessorBuilder;
+import com.google.devtools.build.lib.rules.android.AndroidDataContext;
 import com.google.devtools.build.lib.rules.android.AndroidResources;
+import com.google.devtools.build.lib.rules.java.JavaInfo;
 import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider;
+import java.util.List;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 class DataBindingV2Context implements DataBindingContext {
 
-  // TODO(b/112038432): Enable databinding v2.
-  @SuppressWarnings("unused")
+  /**
+   * Annotation processing creates the following metadata files that describe how data binding is
+   * applied. The full file paths include prefixes as implemented in {@link #getMetadataOutputs}.
+   */
+  private static final ImmutableList<String> METADATA_OUTPUT_SUFFIXES_V2 =
+      ImmutableList.of("setter_store.bin", "br.bin");
+
   private final ActionConstructionContext actionContext;
 
   DataBindingV2Context(ActionConstructionContext actionContext) {
     this.actionContext = actionContext;
-    // TODO(b/112038432): Enable databinding v2.
-    throw new UnsupportedOperationException("V2 not implemented yet.");
   }
 
   @Override
   public void supplyLayoutInfo(Consumer<Artifact> consumer) {
-
+    // In v2, The layout info file is generated in processResources below.
   }
 
   @Override
   public void supplyJavaCoptsUsing(RuleContext ruleContext, boolean isBinary,
       Consumer<Iterable<String>> consumer) {
 
+    ImmutableList.Builder<String> flags = ImmutableList.builder();
+    String metadataOutputDir = DataBinding.getDataBindingExecPath(ruleContext).getPathString();
+
+    // Directory where the annotation processor looks for deps metadata output. The annotation
+    // processor automatically appends {@link DEP_METADATA_INPUT_DIR} to this path. Individual
+    // files can be anywhere under this directory, recursively.
+    flags.add(createProcessorFlag("bindingBuildFolder", metadataOutputDir));
+
+    // Directory where the annotation processor should write this rule's metadata output. The
+    // annotation processor automatically appends {@link METADATA_OUTPUT_DIR} to this path.
+    flags.add(createProcessorFlag("generationalFileOutDir", metadataOutputDir));
+
+    // Path to the Android SDK installation (if available).
+    flags.add(createProcessorFlag("sdkDir", "/not/used"));
+
+    // Whether the current rule is a library or binary.
+    flags.add(createProcessorFlag("artifactType", isBinary ? "APPLICATION" : "LIBRARY"));
+
+    // Unused.
+    flags.add(createProcessorFlag("exportClassListTo", "/tmp/exported_classes"));
+
+    // The Java package for the current rule.
+    flags.add(createProcessorFlag("modulePackage", AndroidCommon.getJavaPackage(ruleContext)));
+
+    // The minimum Android SDK compatible with this rule.
+    // TODO(bazel-team): This probably should be based on the actual min-sdk from the manifest,
+    // or an appropriate rule attribute.
+    flags.add(createProcessorFlag("minApi", "14"));
+
+    // If enabled, produces cleaner output for Android Studio.
+    flags.add(createProcessorFlag("printEncodedErrors", "0"));
+
+    // V2 flags
+    flags.add(createProcessorFlag("enableV2", "1"));
+
+    if (AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      flags.add(createProcessorFlag("classLogDir", getClassInfoFile(ruleContext)));
+      // The path where data binding's resource processor wrote its output (the data binding XML
+      // expressions). The annotation processor reads this file to translate that XML into Java.
+      flags.add(createProcessorFlag("xmlOutDir", DataBinding.getLayoutInfoFile(ruleContext)));
+    } else {
+      // send dummy files
+      flags.add(createProcessorFlag("classLogDir", "/tmp/no_resources"));
+      flags.add(createProcessorFlag("xmlOutDir", "/tmp/no_resources"));
+    }
+
+    consumer.accept(flags.build());
   }
 
   @Override
-  public void supplyAnnotationProcessor(RuleContext ruleContext,
+  public void supplyAnnotationProcessor(
+      RuleContext ruleContext,
       BiConsumer<JavaPluginInfoProvider, Iterable<Artifact>> consumer) {
 
+    JavaPluginInfoProvider javaPluginInfoProvider = JavaInfo.getProvider(
+        JavaPluginInfoProvider.class,
+        ruleContext.getPrerequisite(
+            DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, RuleConfiguredTarget.Mode.HOST));
+
+    ImmutableList<Artifact> annotationProcessorOutputs =
+        DataBinding.getMetadataOutputs(ruleContext, METADATA_OUTPUT_SUFFIXES_V2);
+
+    consumer.accept(javaPluginInfoProvider, annotationProcessorOutputs);
   }
 
   @Override
   public ImmutableList<Artifact> processDeps(RuleContext ruleContext) {
-    return null;
+
+    ImmutableList.Builder<Artifact> dataBindingJavaInputs = ImmutableList.builder();
+    if (AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      dataBindingJavaInputs.add(DataBinding.getLayoutInfoFile(ruleContext));
+      dataBindingJavaInputs.add(getClassInfoFile(ruleContext));
+    }
+
+    for (Artifact transitiveBRFile : getTransitiveBRFiles(ruleContext)) {
+      dataBindingJavaInputs.add(
+          DataBinding.symlinkDepsMetadataIntoOutputTree(ruleContext, transitiveBRFile));
+    }
+
+    for (Artifact directSetterStoreFile : getDirectSetterStoreFiles(ruleContext)) {
+      dataBindingJavaInputs.add(
+          DataBinding.symlinkDepsMetadataIntoOutputTree(ruleContext, directSetterStoreFile));
+    }
+
+    for (Artifact classInfo : getDirectClassInfo(ruleContext)) {
+      dataBindingJavaInputs.add(
+          DataBinding.symlinkDepsMetadataIntoOutputTree(ruleContext, classInfo));
+    }
+
+    return dataBindingJavaInputs.build();
   }
 
+  private static ImmutableList<Artifact> getTransitiveBRFiles(RuleContext context) {
+    ImmutableList.Builder<Artifact> brFiles = ImmutableList.builder();
+    if (context.attributes().has("deps", BuildType.LABEL_LIST)) {
+
+      Iterable<DataBindingV2Provider> providers = context.getPrerequisites(
+          "deps", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+
+      for (DataBindingV2Provider provider : providers) {
+        brFiles.addAll(provider.getTransitiveBRFiles());
+      }
+    }
+    return brFiles.build();
+  }
+
+  private static List<Artifact> getDirectSetterStoreFiles(RuleContext context) {
+    ImmutableList.Builder<Artifact> setterStoreFiles = ImmutableList.builder();
+    if (context.attributes().has("deps", BuildType.LABEL_LIST)) {
+
+      Iterable<DataBindingV2Provider> providers = context.getPrerequisites(
+          "deps", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+
+      for (DataBindingV2Provider provider : providers) {
+        setterStoreFiles.addAll(provider.getSetterStores());
+      }
+    }
+    return setterStoreFiles.build();
+  }
+  
   @Override
-  public ImmutableList<Artifact> addAnnotationFileToSrcs(ImmutableList<Artifact> srcs,
-      RuleContext ruleContext) {
-    return null;
+  public ImmutableList<Artifact> getAnnotationSourceFiles(RuleContext ruleContext) {
+    ImmutableList.Builder<Artifact> srcs = ImmutableList.builder();
+
+    srcs.addAll(DataBinding.getAnnotationFile(ruleContext));
+    srcs.addAll(createBaseClasses(ruleContext));
+
+    return srcs.build();
+  }
+
+  private ImmutableList<Artifact> createBaseClasses(RuleContext ruleContext) {
+
+    if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      return ImmutableList.of(); // no resource, no base classes or class info
+    }
+
+    Artifact layoutInfo = DataBinding.getLayoutInfoFile(ruleContext);
+    Artifact classInfoFile = getClassInfoFile(ruleContext);
+    Artifact srcOutFile = DataBinding.getDataBindingArtifact(ruleContext, "baseClassSrc.srcjar");
+
+    FilesToRunProvider exec = ruleContext
+        .getExecutablePrerequisite(DataBinding.DATABINDING_EXEC_PROCESSOR_ATTR, Mode.HOST);
+
+    CustomCommandLine.Builder commandLineBuilder = CustomCommandLine.builder()
+        .add("GEN_BASE_CLASSES")
+        .addExecPath("-layoutInfoFiles", layoutInfo)
+        .add("-package", AndroidCommon.getJavaPackage(ruleContext))
+        .addExecPath("-classInfoOut", classInfoFile)
+        .addExecPath("-sourceOut", srcOutFile)
+        .add("-zipSourceOutput", "true")
+        .add("-useAndroidX", "false");
+
+    List<Artifact> dependencyClientInfos = getDirectClassInfo(ruleContext);
+    for (Artifact artifact : dependencyClientInfos) {
+      commandLineBuilder.addExecPath("-dependencyClassInfoList", artifact);
+    }
+
+    Action[] action = new SpawnAction.Builder()
+        .setExecutable(exec)
+        .setMnemonic("GenerateDataBindingBaseClasses")
+        .addInput(layoutInfo)
+        .addInputs(dependencyClientInfos)
+        .addOutput(classInfoFile)
+        .addOutput(srcOutFile)
+        .addCommandLine(commandLineBuilder.build())
+        .build(ruleContext);
+    ruleContext.registerAction(action);
+
+    return ImmutableList.of(srcOutFile);
+  }
+
+  private static List<Artifact> getDirectClassInfo(RuleContext context) {
+    ImmutableList.Builder<Artifact> clientInfoFiles = ImmutableList.builder();
+    if (context.attributes().has("deps", BuildType.LABEL_LIST)) {
+
+      Iterable<DataBindingV2Provider> providers = context.getPrerequisites(
+          "deps", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+
+      for (DataBindingV2Provider provider : providers) {
+        clientInfoFiles.addAll(provider.getClassInfos());
+      }
+    }
+    return clientInfoFiles.build();
   }
 
   @Override
   public void addProvider(RuleConfiguredTargetBuilder builder, RuleContext ruleContext) {
 
+    Artifact setterStore = DataBinding.getMetadataOutput(ruleContext, "setter_store.bin");
+    Artifact br = DataBinding.getMetadataOutput(ruleContext, "br.bin");
+
+    ImmutableList.Builder<Artifact> setterStores = ImmutableList.builder();
+    if (setterStore != null) {
+      setterStores.add(setterStore);
+    }
+
+    ImmutableList.Builder<Artifact> classInfos = ImmutableList.builder();
+    if (AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      Artifact classInfo = getClassInfoFile(ruleContext);
+      classInfos.add(classInfo);
+    }
+
+    // android_binary doesn't have "exports"
+    if (ruleContext.attributes().has("exports", BuildType.LABEL_LIST)) {
+      Iterable<DataBindingV2Provider> exportsProviders =
+          ruleContext.getPrerequisites(
+              "exports", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+      for (DataBindingV2Provider provider : exportsProviders) {
+        setterStores.addAll(provider.getSetterStores());
+        classInfos.addAll(provider.getClassInfos());
+      }
+    }
+
+    NestedSetBuilder<Artifact> brFiles = new NestedSetBuilder<>(Order.STABLE_ORDER);
+    if (br != null) {
+      brFiles.add(br);
+    }
+
+    Iterable<DataBindingV2Provider> depsProviders = ruleContext.getPrerequisites(
+        "deps", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+
+    for (DataBindingV2Provider provider : depsProviders) {
+      brFiles.addTransitive(provider.getTransitiveBRFiles());
+    }
+
+    builder.addNativeDeclaredProvider(
+        new DataBindingV2Provider(
+            classInfos.build(),
+            setterStores.build(),
+            brFiles.build()));
   }
 
   @Override
-  public AndroidResources processResources(AndroidResources resources) {
-    return null;
+  public AndroidResources processResources(
+      AndroidDataContext dataContext, AndroidResources resources, String appId) {
+
+    AndroidResources databindingProcessedResources = AndroidDataBindingProcessorBuilder.create(
+        dataContext,
+        resources,
+        appId,
+        DataBinding.getLayoutInfoFile(actionContext));
+
+    return databindingProcessedResources;
+
+  }
+
+  private static Artifact getClassInfoFile(ActionConstructionContext context) {
+    return context.getUniqueDirectoryArtifact("databinding", "class-info.zip");
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Provider.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Provider.java
new file mode 100644
index 0000000..0ffd180
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Provider.java
@@ -0,0 +1,87 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.rules.android.databinding;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.packages.BuiltinProvider;
+import com.google.devtools.build.lib.packages.NativeInfo;
+import com.google.devtools.build.lib.skylarkbuildapi.android.DataBindingV2ProviderApi;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/**
+ * A provider that exposes this enables <a
+ * href="https://developer.android.com/topic/libraries/data-binding/index.html">data binding</a>
+ * version 2 on its resource processing and Java compilation.
+ */
+public final class DataBindingV2Provider extends NativeInfo
+    implements DataBindingV2ProviderApi<Artifact> {
+
+  public static final Provider PROVIDER = new Provider();
+
+  private final ImmutableList<Artifact> classInfos;
+
+  private final ImmutableList<Artifact> setterStores;
+
+  private final NestedSet<Artifact> transitiveBRFiles;
+
+  public DataBindingV2Provider(
+      ImmutableList<Artifact> classInfos,
+      ImmutableList<Artifact> setterStores,
+      NestedSet<Artifact> transitiveBRFiles) {
+    super(PROVIDER);
+    this.classInfos = classInfos;
+    this.setterStores = setterStores;
+    this.transitiveBRFiles = transitiveBRFiles;
+  }
+
+  @Override
+  public ImmutableList<Artifact> getClassInfos() {
+    return classInfos;
+  }
+
+  @Override
+  public ImmutableList<Artifact> getSetterStores() {
+    return setterStores;
+  }
+
+  @Override
+  public NestedSet<Artifact> getTransitiveBRFiles() {
+    return transitiveBRFiles;
+  }
+
+  /** The provider can construct the DataBindingV2Provider provider. */
+  public static class Provider extends BuiltinProvider<DataBindingV2Provider>
+      implements DataBindingV2ProviderApi.Provider<Artifact> {
+
+    private Provider() {
+      super(NAME, DataBindingV2Provider.class);
+    }
+
+    @Override
+    public DataBindingV2ProviderApi<Artifact> createInfo(
+        SkylarkList<Artifact> setterStores,
+        SkylarkList<Artifact> clientInfos,
+        SkylarkNestedSet transitiveBrFiles) throws EvalException {
+
+      return new DataBindingV2Provider(
+          setterStores.getImmutableList(),
+          clientInfos.getImmutableList(),
+          transitiveBrFiles.getSet(Artifact.class));
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV1Context.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV1Context.java
index cae89c4..7b59900 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV1Context.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV1Context.java
@@ -17,6 +17,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.rules.android.AndroidDataContext;
 import com.google.devtools.build.lib.rules.android.AndroidResources;
 import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider;
 import java.util.ArrayList;
@@ -39,18 +40,30 @@
   }
 
   @Override
-  public ImmutableList<Artifact> addAnnotationFileToSrcs(
-      ImmutableList<Artifact> srcs, RuleContext ruleContext) {
-    return srcs;
-  };
-
-  @Override
-  public void addProvider(RuleConfiguredTargetBuilder builder, RuleContext ruleContext) {
-    DataBinding.maybeAddProvider(new ArrayList<>(), builder, ruleContext);
+  public ImmutableList<Artifact> getAnnotationSourceFiles(RuleContext ruleContext) {
+    return ImmutableList.of();
   }
 
   @Override
-  public AndroidResources processResources(AndroidResources resources) {
+  public void addProvider(RuleConfiguredTargetBuilder builder, RuleContext ruleContext) {
+
+    ArrayList<Artifact> dataBindingMetadataOutputs = new ArrayList<>();
+    // Expose the data binding provider if there are outputs.
+    dataBindingMetadataOutputs.addAll(DataBinding.getTransitiveMetadata(ruleContext, "exports"));
+    if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) {
+      // If this rule doesn't declare direct resources, no resource processing is run so no data
+      // binding outputs are produced. In that case, we need to explicitly propagate data binding
+      // outputs from the deps to make sure they continue up the build graph.
+      dataBindingMetadataOutputs.addAll(DataBinding.getTransitiveMetadata(ruleContext, "deps"));
+    }
+    if (!dataBindingMetadataOutputs.isEmpty()) {
+      builder.addNativeDeclaredProvider(new UsesDataBindingProvider(dataBindingMetadataOutputs));
+    }
+  }
+
+  @Override
+  public AndroidResources processResources(
+      AndroidDataContext dataContext, AndroidResources resources, String appId) {
     return resources;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV2Context.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV2Context.java
new file mode 100644
index 0000000..5bbef27
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DisabledDataBindingV2Context.java
@@ -0,0 +1,92 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.rules.android.databinding;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+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.AndroidDataContext;
+import com.google.devtools.build.lib.rules.android.AndroidResources;
+import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+class DisabledDataBindingV2Context implements DataBindingContext {
+
+  @Override
+  public void supplyJavaCoptsUsing(RuleContext ruleContext, boolean isBinary,
+      Consumer<Iterable<String>> consumer) { }
+
+  @Override
+  public void supplyAnnotationProcessor(RuleContext ruleContext,
+      BiConsumer<JavaPluginInfoProvider, Iterable<Artifact>> consumer) { }
+
+  @Override
+  public ImmutableList<Artifact> processDeps(RuleContext ruleContext) {
+    return ImmutableList.of();
+  }
+
+  @Override
+  public ImmutableList<Artifact> getAnnotationSourceFiles(RuleContext ruleContext) {
+    return ImmutableList.of();
+  }
+
+  @Override
+  public void addProvider(RuleConfiguredTargetBuilder builder, RuleContext ruleContext) {
+
+    ImmutableList.Builder<Artifact> setterStores = ImmutableList.builder();
+    ImmutableList.Builder<Artifact> classInfos = ImmutableList.builder();
+    NestedSetBuilder<Artifact> brFiles = new NestedSetBuilder<>(Order.STABLE_ORDER);
+
+    // android_binary doesn't have "exports"
+    if (ruleContext.attributes().has("exports", BuildType.LABEL_LIST)) {
+      Iterable<DataBindingV2Provider> exportsProviders =
+          ruleContext.getPrerequisites(
+              "exports", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+      for (DataBindingV2Provider provider : exportsProviders) {
+        setterStores.addAll(provider.getSetterStores());
+        classInfos.addAll(provider.getClassInfos());
+        brFiles.addTransitive(provider.getTransitiveBRFiles());
+      }
+    }
+
+
+    Iterable<DataBindingV2Provider> depsProviders = ruleContext.getPrerequisites(
+        "deps", RuleConfiguredTarget.Mode.TARGET, DataBindingV2Provider.PROVIDER);
+
+    for (DataBindingV2Provider provider : depsProviders) {
+      brFiles.addTransitive(provider.getTransitiveBRFiles());
+    }
+
+    builder.addNativeDeclaredProvider(
+        new DataBindingV2Provider(
+            classInfos.build(),
+            setterStores.build(),
+            brFiles.build()));
+  }
+
+  @Override
+  public AndroidResources processResources(
+      AndroidDataContext dataContext, AndroidResources resources, String appId) {
+    return resources;
+  }
+
+  @Override
+  public void supplyLayoutInfo(Consumer<Artifact> consumer) {  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/UsesDataBindingProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/UsesDataBindingProvider.java
index e6a4aaa..62ce14f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/UsesDataBindingProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/UsesDataBindingProvider.java
@@ -58,4 +58,4 @@
       return new UsesDataBindingProvider(metadataOutputs.getImmutableList());
     }
   }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/android/DataBindingV2ProviderApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/android/DataBindingV2ProviderApi.java
new file mode 100644
index 0000000..2c0f28e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/android/DataBindingV2ProviderApi.java
@@ -0,0 +1,99 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skylarkbuildapi.android;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
+import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
+import com.google.devtools.build.lib.skylarkbuildapi.StructApi;
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkConstructor;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/**
+ * An interface for a provider that exposes the use of <a
+ * href="https://developer.android.com/topic/libraries/data-binding/index.html">data binding</a>.
+ */
+@SkylarkModule(
+    name = "DataBindingV2Info",
+    doc =
+        "Do not use this module. It is intended for migration purposes only. If you depend on it, "
+            + "you will be broken when it is removed.",
+    documented = false)
+public interface DataBindingV2ProviderApi<T extends FileApi> extends StructApi {
+
+  /** Name of this info object. */
+  public static final String NAME = "DataBindingV2Info";
+
+  /** Returns the setter store files from this rule. */
+  @SkylarkCallable(name = "setter_stores", structField = true, doc = "", documented = false)
+  ImmutableList<T> getSetterStores();
+
+  /** Returns the client info files from this rule. */
+  @SkylarkCallable(name = "client_infos", structField = true, doc = "", documented = false)
+  ImmutableList<T> getClassInfos();
+
+  /** Returns the BR files from this rule and its dependencies. */
+  @SkylarkCallable(name = "transitive_br_files", structField = true, doc = "", documented = false)
+  NestedSet<T> getTransitiveBRFiles();
+
+  /** The provider implementing this can construct the DataBindingV2Info provider. */
+  @SkylarkModule(
+      name = "Provider",
+      doc =
+          "Do not use this module. It is intended for migration purposes only. If you depend on "
+              + "it, you will be broken when it is removed.",
+      documented = false)
+  public interface Provider<F extends FileApi> extends ProviderApi {
+
+    @SkylarkCallable(
+        name = NAME,
+        doc = "The <code>DataBindingV2Info</code> constructor.",
+        documented = false,
+        parameters = {
+            @Param(
+                name = "setter_stores",
+                doc = "A list of artifacts of setter_stores.bin.",
+                positional = true,
+                named = false,
+                type = SkylarkList.class,
+                generic1 = FileApi.class),
+            @Param(
+                name = "client_infos",
+                doc = "A list of artifacts of client_infos.bin.",
+                positional = true,
+                named = false,
+                type = SkylarkList.class,
+                generic1 = FileApi.class),
+            @Param(
+                name = "transitive_br_files",
+                doc = "A list of artifacts of br.bin.",
+                positional = true,
+                named = false,
+                type = SkylarkNestedSet.class,
+                generic1 = FileApi.class),
+        },
+        selfCall = true)
+    @SkylarkConstructor(objectType = DataBindingV2ProviderApi.class)
+    DataBindingV2ProviderApi<F> createInfo(
+        SkylarkList<F> setterStores,
+        SkylarkList<F> clientInfos,
+        SkylarkNestedSet transitiveBrFiles) throws EvalException;
+  }
+}
\ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidDataBindingV2Test.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidDataBindingV2Test.java
new file mode 100644
index 0000000..e62b1cf
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidDataBindingV2Test.java
@@ -0,0 +1,550 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.rules.android;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getFirstArtifactEndingWith;
+import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.truth.Truth;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.extra.JavaCompileInfo;
+import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.rules.android.databinding.DataBindingV2Provider;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for Bazel's Android data binding v2 support. */
+@RunWith(JUnit4.class)
+public class AndroidDataBindingV2Test extends AndroidBuildViewTestCase {
+
+  @Before
+  public void setDataBindingV2Flag() throws Exception {
+    useConfiguration("--experimental_android_databinding_v2");
+  }
+
+  private void writeDataBindingFiles() throws Exception {
+
+    scratch.file(
+        "java/android/library/BUILD",
+        "android_library(",
+        "    name = 'lib_with_data_binding',",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    srcs = ['MyLib.java'],",
+        "    resource_files = [],",
+        ")");
+
+    scratch.file(
+        "java/android/library/MyLib.java", "package android.library; public class MyLib {};");
+
+    scratch.file(
+        "java/android/binary/BUILD",
+        "android_binary(",
+        "    name = 'app',",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    srcs = ['MyApp.java'],",
+        "    deps = ['//java/android/library:lib_with_data_binding'],",
+        ")");
+
+    scratch.file(
+        "java/android/binary/MyApp.java", "package android.binary; public class MyApp {};");
+  }
+
+  private void writeDataBindingFilesWithNoResourcesDep() throws Exception {
+
+    scratch.file(
+        "java/android/lib_with_resource_files/BUILD",
+        "android_library(",
+        "    name = 'lib_with_resource_files',",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    srcs = ['LibWithResourceFiles.java'],",
+        "    resource_files = glob(['res/**']),",
+        ")");
+    scratch.file(
+        "java/android/lib_with_resource_files/LibWithResourceFiles.java",
+        "package android.lib_with_resource_files; public class LibWithResourceFiles {};");
+
+    scratch.file(
+        "java/android/lib_no_resource_files/BUILD",
+        "android_library(",
+        "    name = 'lib_no_resource_files',",
+        "    enable_data_binding = 1,",
+        "    srcs = ['LibNoResourceFiles.java'],",
+        "    deps = ['//java/android/lib_with_resource_files'],",
+        ")");
+    scratch.file(
+        "java/android/lib_no_resource_files/LibNoResourceFiles.java",
+        "package android.lib_no_resource_files; public class LibNoResourceFiles {};");
+
+    scratch.file(
+        "java/android/binary/BUILD",
+        "android_binary(",
+        "    name = 'app',",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    srcs = ['MyApp.java'],",
+        "    deps = ['//java/android/lib_no_resource_files'],",
+        ")");
+    scratch.file(
+        "java/android/binary/MyApp.java", "package android.binary; public class MyApp {};");
+  }
+
+  @Test
+  public void basicDataBindingIntegration() throws Exception {
+
+    writeDataBindingFiles();
+
+    ConfiguredTarget ctapp = getConfiguredTarget("//java/android/binary:app");
+    Set<Artifact> allArtifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(ctapp));
+
+    // "Data binding"-enabled targets invoke resource processing with a request for data binding
+    // output:
+    Artifact libResourceInfoOutput =
+        getFirstArtifactEndingWith(
+            allArtifacts, "databinding/lib_with_data_binding/layout-info.zip");
+    assertThat(getGeneratingSpawnActionArgs(libResourceInfoOutput))
+        .containsAllOf("--dataBindingInfoOut", libResourceInfoOutput.getExecPathString())
+        .inOrder();
+
+    Artifact binResourceInfoOutput =
+        getFirstArtifactEndingWith(allArtifacts, "databinding/app/layout-info.zip");
+    assertThat(getGeneratingSpawnActionArgs(binResourceInfoOutput))
+        .containsAllOf("--dataBindingInfoOut", binResourceInfoOutput.getExecPathString())
+        .inOrder();
+
+    // Java compilation includes the data binding annotation processor, the resource processor's
+    // output, and the auto-generated DataBindingInfo.java the annotation processor uses to figure
+    // out what to do:
+    SpawnAction libCompileAction =
+        (SpawnAction)
+            getGeneratingAction(
+                getFirstArtifactEndingWith(allArtifacts, "lib_with_data_binding.jar"));
+    assertThat(getProcessorNames(libCompileAction))
+        .contains("android.databinding.annotationprocessor.ProcessDataBinding");
+    assertThat(prettyArtifactNames(libCompileAction.getInputs()))
+        .containsAllOf(
+            "java/android/library/databinding/lib_with_data_binding/layout-info.zip",
+            "java/android/library/databinding/lib_with_data_binding/DataBindingInfo.java");
+
+    SpawnAction binCompileAction =
+        (SpawnAction) getGeneratingAction(getFirstArtifactEndingWith(allArtifacts, "app.jar"));
+    assertThat(getProcessorNames(binCompileAction))
+        .contains("android.databinding.annotationprocessor.ProcessDataBinding");
+    assertThat(prettyArtifactNames(binCompileAction.getInputs()))
+        .containsAllOf(
+            "java/android/binary/databinding/app/layout-info.zip",
+            "java/android/binary/databinding/app/DataBindingInfo.java");
+  }
+
+  @Test
+  public void dataBindingCompilationUsesMetadataFromDeps() throws Exception {
+
+    writeDataBindingFiles();
+
+    ConfiguredTarget ctapp = getConfiguredTarget("//java/android/binary:app");
+    Set<Artifact> allArtifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(ctapp));
+
+    // The library's compilation doesn't include any of the -setter_store.bin, layoutinfo.bin, etc.
+    // files that store a dependency's data binding results (since the library has no deps).
+    // We check that they don't appear as compilation inputs.
+    SpawnAction libCompileAction =
+        (SpawnAction)
+            getGeneratingAction(
+                getFirstArtifactEndingWith(allArtifacts, "lib_with_data_binding.jar"));
+    assertThat(
+            Iterables.filter(
+                libCompileAction.getInputs(), ActionsTestUtil.getArtifactSuffixMatcher(".bin")))
+        .isEmpty();
+
+    // The binary's compilation includes the library's data binding results.
+    SpawnAction binCompileAction =
+        (SpawnAction) getGeneratingAction(getFirstArtifactEndingWith(allArtifacts, "app.jar"));
+    Iterable<Artifact> depMetadataInputs =
+        Iterables.filter(
+            binCompileAction.getInputs(), ActionsTestUtil.getArtifactSuffixMatcher(".bin"));
+    final String depMetadataBaseDir =
+        Iterables.getFirst(depMetadataInputs, null).getExecPath().getParentDirectory().toString();
+    ActionsTestUtil.execPaths(
+        Iterables.filter(
+            binCompileAction.getInputs(), ActionsTestUtil.getArtifactSuffixMatcher(".bin")));
+    assertThat(ActionsTestUtil.execPaths(depMetadataInputs))
+        .containsExactly(
+            depMetadataBaseDir + "/android.library-android.library-setter_store.bin",
+            depMetadataBaseDir + "/android.library-android.library-br.bin");
+  }
+
+  @Test
+  public void dataBindingAnnotationProcessorFlags() throws Exception {
+
+    writeDataBindingFiles();
+
+    ConfiguredTarget ctapp = getConfiguredTarget("//java/android/binary:app");
+    Set<Artifact> allArtifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(ctapp));
+    SpawnAction binCompileAction =
+        (SpawnAction) getGeneratingAction(getFirstArtifactEndingWith(allArtifacts, "app.jar"));
+    String dataBindingFilesDir =
+        targetConfig
+            .getBinDirectory(RepositoryName.MAIN)
+            .getExecPath()
+            .getRelative("java/android/binary/databinding/app")
+            .getPathString();
+    ImmutableList<String> expectedJavacopts =
+        ImmutableList.of(
+            "-Aandroid.databinding.bindingBuildFolder=" + dataBindingFilesDir,
+            "-Aandroid.databinding.generationalFileOutDir=" + dataBindingFilesDir,
+            "-Aandroid.databinding.sdkDir=/not/used",
+            "-Aandroid.databinding.artifactType=APPLICATION",
+            "-Aandroid.databinding.exportClassListTo=/tmp/exported_classes",
+            "-Aandroid.databinding.modulePackage=android.binary",
+            "-Aandroid.databinding.minApi=14",
+            "-Aandroid.databinding.printEncodedErrors=0",
+            "-Aandroid.databinding.enableV2=1");
+    assertThat(paramFileArgsForAction(binCompileAction)).containsAllIn(expectedJavacopts);
+
+    // Regression test for b/63134122
+    JavaCompileInfo javaCompileInfo =
+        binCompileAction
+            .getExtraActionInfo(actionKeyContext)
+            .getExtension(JavaCompileInfo.javaCompileInfo);
+    assertThat(javaCompileInfo.getJavacOptList()).containsAllIn(expectedJavacopts);
+  }
+
+  @Test
+  public void dataBindingIncludesTransitiveDepsForLibsWithNoResources() throws Exception {
+
+    writeDataBindingFilesWithNoResourcesDep();
+
+    ConfiguredTarget ct = getConfiguredTarget("//java/android/binary:app");
+    Set<Artifact> allArtifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(ct));
+
+    // Data binding resource processing outputs are expected for the app and libs with resources.
+    assertThat(
+            getFirstArtifactEndingWith(
+                allArtifacts, "databinding/lib_with_resource_files/layout-info.zip"))
+        .isNotNull();
+    assertThat(getFirstArtifactEndingWith(allArtifacts, "databinding/app/layout-info.zip"))
+        .isNotNull();
+
+    // Compiling the app's Java source includes data binding metadata from the resource-equipped
+    // lib, but not the resource-empty one.
+    SpawnAction binCompileAction =
+        (SpawnAction) getGeneratingAction(getFirstArtifactEndingWith(allArtifacts, "app.jar"));
+
+    List<String> appJarInputs = prettyArtifactNames(binCompileAction.getInputs());
+
+    String libWithResourcesMetadataBaseDir =
+        "java/android/binary/databinding/app/"
+            + "dependent-lib-artifacts/java/android/lib_with_resource_files/databinding/"
+            + "lib_with_resource_files/bin-files/android.lib_with_resource_files-";
+
+    assertThat(appJarInputs)
+        .containsAllOf(
+            "java/android/binary/databinding/app/layout-info.zip",
+            libWithResourcesMetadataBaseDir + "android.lib_with_resource_files-br.bin");
+
+    for (String compileInput : appJarInputs) {
+      assertThat(compileInput).doesNotMatch(".*lib_no_resource_files.*.bin");
+    }
+  }
+
+  @Test
+  public void libsWithNoResourcesOnlyRunAnnotationProcessor() throws Exception {
+
+    // Bazel skips resource processing because there are no new resources to process. But it still
+    // runs the annotation processor to ensure the Java compiler reads Java sources referenced by
+    // the deps' resources (e.g. "<variable type="some.package.SomeClass" />"). Without this,
+    // JavaBuilder's --reduce_classpath feature would strip out those sources as "unused" and fail
+    // the binary's compilation with unresolved symbol errors.
+    writeDataBindingFilesWithNoResourcesDep();
+
+    ConfiguredTarget ct = getConfiguredTarget("//java/android/lib_no_resource_files");
+    Iterable<Artifact> libArtifacts = getFilesToBuild(ct);
+
+    assertThat(getFirstArtifactEndingWith(libArtifacts, "_resources.jar")).isNull();
+    assertThat(getFirstArtifactEndingWith(libArtifacts, "layout-info.zip")).isNull();
+
+    SpawnAction libCompileAction =
+        (SpawnAction)
+            getGeneratingAction(
+                getFirstArtifactEndingWith(libArtifacts, "lib_no_resource_files.jar"));
+    // The annotation processor is attached to the Java compilation:
+    assertThat(paramFileArgsForAction(libCompileAction))
+        .containsAllOf(
+            "--processors", "android.databinding.annotationprocessor.ProcessDataBinding");
+    // The dummy .java file with annotations that trigger the annotation process is present:
+    assertThat(prettyArtifactNames(libCompileAction.getInputs()))
+        .contains(
+            "java/android/lib_no_resource_files/databinding/lib_no_resource_files/"
+                + "DataBindingInfo.java");
+  }
+
+  @Test
+  public void missingDataBindingAttributeStillAnalyzes() throws Exception {
+
+    // When a library is missing enable_data_binding = 1, we expect it to fail in execution (because
+    // aapt doesn't know how to read the data binding expressions). But analysis should work.
+    scratch.file(
+        "java/android/library/BUILD",
+        "android_library(",
+        "    name = 'lib_with_data_binding',",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    srcs = ['MyLib.java'],",
+        "    resource_files = [],",
+        ")");
+
+    scratch.file(
+        "java/android/library/MyLib.java", "package android.library; public class MyLib {};");
+
+    scratch.file(
+        "java/android/binary/BUILD",
+        "android_binary(",
+        "    name = 'app',",
+        "    enable_data_binding = 0,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    srcs = ['MyApp.java'],",
+        "    deps = ['//java/android/library:lib_with_data_binding'],",
+        ")");
+
+    scratch.file(
+        "java/android/binary/MyApp.java", "package android.binary; public class MyApp {};");
+
+    assertThat(getConfiguredTarget("//java/android/binary:app")).isNotNull();
+  }
+
+  @Test
+  public void dataBindingProviderIsProvided() throws Exception {
+
+    useConfiguration("--android_sdk=//sdk:sdk", "--experimental_android_databinding_v2");
+
+    scratch.file(
+        "sdk/BUILD",
+        "android_sdk(",
+        "    name = 'sdk',",
+        "    aapt = 'aapt',",
+        "    aapt2 = 'aapt2',",
+        "    adb = 'adb',",
+        "    aidl = 'aidl',",
+        "    android_jar = 'android.jar',",
+        "    apksigner = 'apksigner',",
+        "    dx = 'dx',",
+        "    framework_aidl = 'framework_aidl',",
+        "    main_dex_classes = 'main_dex_classes',",
+        "    main_dex_list_creator = 'main_dex_list_creator',",
+        "    proguard = 'proguard',",
+        "    shrinked_android_jar = 'shrinked_android_jar',",
+        "    zipalign = 'zipalign',",
+        "    tags = ['__ANDROID_RULES_MIGRATION__'],",
+        ")");
+
+    scratch.file(
+        "java/a/BUILD",
+        "android_library(",
+        "    name = 'a', ",
+        "    srcs = ['A.java'],",
+        "    enable_data_binding = 1,",
+        "    manifest = 'a/AndroidManifest.xml',",
+        "    resource_files = ['res/values/a.xml'],",
+        ")");
+
+    scratch.file(
+        "java/b/BUILD",
+        "android_library(",
+        "    name = 'b', ",
+        "    srcs = ['B.java'],",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    resource_files = ['res/values/a.xml'],",
+        ")");
+
+    ConfiguredTarget a = getConfiguredTarget("//java/a:a");
+    final DataBindingV2Provider dataBindingV2Provider = a.get(DataBindingV2Provider.PROVIDER);
+
+    assertThat(dataBindingV2Provider)
+        .named(DataBindingV2Provider.NAME)
+        .isNotNull();
+
+    assertThat(
+        dataBindingV2Provider
+            .getSetterStores()
+            .stream()
+            .map(Artifact::getRootRelativePathString)
+            .collect(Collectors.toList()))
+        .containsExactly("java/a/databinding/a/bin-files/a-a-setter_store.bin");
+
+    assertThat(
+        dataBindingV2Provider
+            .getClassInfos()
+            .stream()
+            .map(Artifact::getRootRelativePathString)
+            .collect(Collectors.toList()))
+        .containsExactly("java/a/databinding/a/class-info.zip");
+
+    assertThat(
+        dataBindingV2Provider
+            .getTransitiveBRFiles()
+            .toCollection()
+            .stream()
+            .map(Artifact::getRootRelativePathString)
+            .collect(Collectors.toList()))
+        .containsExactly("java/a/databinding/a/bin-files/a-a-br.bin");
+  }
+
+  @Test
+  public void ensureDataBindingProviderIsPropagatedThroughNonDataBindingLibs() throws Exception {
+
+    useConfiguration("--android_sdk=//sdk:sdk", "--experimental_android_databinding_v2");
+
+    scratch.file(
+        "sdk/BUILD",
+        "android_sdk(",
+        "    name = 'sdk',",
+        "    aapt = 'aapt',",
+        "    aapt2 = 'aapt2',",
+        "    adb = 'adb',",
+        "    aidl = 'aidl',",
+        "    android_jar = 'android.jar',",
+        "    apksigner = 'apksigner',",
+        "    dx = 'dx',",
+        "    framework_aidl = 'framework_aidl',",
+        "    main_dex_classes = 'main_dex_classes',",
+        "    main_dex_list_creator = 'main_dex_list_creator',",
+        "    proguard = 'proguard',",
+        "    shrinked_android_jar = 'shrinked_android_jar',",
+        "    zipalign = 'zipalign',",
+        "    tags = ['__ANDROID_RULES_MIGRATION__'],",
+        ")");
+    scratch.file(
+        "java/a/BUILD",
+        "android_library(",
+        "    name = 'a', ",
+        "    srcs = ['A.java'],",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    resource_files = ['res/values/a.xml'],",
+        ")");
+    scratch.file(
+        "java/b/BUILD",
+        "android_library(",
+        "    name = 'b', ",
+        "    srcs = ['B.java'],",
+        "    deps = ['//java/a:a'],",
+        ")");
+
+    ConfiguredTarget b = getConfiguredTarget("//java/b:b");
+    Truth.assertThat(b.get(DataBindingV2Provider.PROVIDER))
+        .named("DataBindingV2Info")
+        .isNotNull();
+  }
+
+  @Test
+  public void testDataBindingCollectedThroughExports() throws Exception {
+
+    useConfiguration("--android_sdk=//sdk:sdk", "--experimental_android_databinding_v2");
+
+    scratch.file(
+        "sdk/BUILD",
+        "android_sdk(",
+        "    name = 'sdk',",
+        "    aapt = 'aapt',",
+        "    aapt2 = 'aapt2',",
+        "    adb = 'adb',",
+        "    aidl = 'aidl',",
+        "    android_jar = 'android.jar',",
+        "    apksigner = 'apksigner',",
+        "    dx = 'dx',",
+        "    framework_aidl = 'framework_aidl',",
+        "    main_dex_classes = 'main_dex_classes',",
+        "    main_dex_list_creator = 'main_dex_list_creator',",
+        "    proguard = 'proguard',",
+        "    shrinked_android_jar = 'shrinked_android_jar',",
+        "    zipalign = 'zipalign',",
+        "    tags = ['__ANDROID_RULES_MIGRATION__'],",
+        ")");
+
+    scratch.file(
+        "java/a/BUILD",
+        "android_library(",
+        "    name = 'a', ",
+        "    srcs = ['A.java'],",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    resource_files = ['res/values/a.xml'],",
+        ")");
+
+    scratch.file(
+        "java/b/BUILD",
+        "android_library(",
+        "    name = 'b', ",
+        "    srcs = ['B.java'],",
+        "    enable_data_binding = 1,",
+        "    manifest = 'AndroidManifest.xml',",
+        "    resource_files = ['res/values/a.xml'],",
+        ")");
+
+    scratch.file(
+        "java/c/BUILD",
+        "android_library(",
+        "    name = 'c', ",
+        "    exports = ['//java/a:a', '//java/b:b']",
+        ")");
+
+    ConfiguredTarget c = getConfiguredTarget("//java/c:c");
+    DataBindingV2Provider provider = c.get(DataBindingV2Provider.PROVIDER);
+
+    assertThat(
+        provider
+            .getClassInfos()
+            .stream()
+            .map(Artifact::getRootRelativePathString)
+            .collect(Collectors.toList()))
+        .containsExactly(
+            "java/a/databinding/a/class-info.zip",
+            "java/b/databinding/b/class-info.zip");
+
+    assertThat(
+        provider
+            .getSetterStores()
+            .stream()
+            .map(Artifact::getRootRelativePathString)
+            .collect(Collectors.toList()))
+        .containsExactly(
+            "java/a/databinding/a/bin-files/a-a-setter_store.bin",
+            "java/b/databinding/b/bin-files/b-b-setter_store.bin");
+
+    assertThat(
+        provider
+            .getTransitiveBRFiles()
+            .toCollection()
+            .stream()
+            .map(Artifact::getRootRelativePathString)
+            .collect(Collectors.toList()))
+        .containsExactly(
+            "java/a/databinding/a/bin-files/a-a-br.bin",
+            "java/b/databinding/b/bin-files/b-b-br.bin");
+  }
+}
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 fcdef8b..6cb9ea0 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
@@ -557,7 +557,10 @@
 
   private ParsedAndroidResources makeParsedResources(RuleContext ruleContext)
       throws RuleErrorException, InterruptedException {
-    return makeParsedResources(ruleContext, DataBinding.asDisabledDataBindingContext());
+    DataBindingContext dataBindingContext =
+        DataBinding.contextFrom(ruleContext,
+            ruleContext.getConfiguration().getFragment(AndroidConfiguration.class));
+    return makeParsedResources(ruleContext, dataBindingContext);
   }
 
   private ParsedAndroidResources makeParsedResources(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java
index 0d48adb..f46fd11 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java
@@ -258,7 +258,7 @@
                 includeAapt2Outs ? getOutput("symbols.zip") : null,
                 manifest.getManifest().getOwnerLabel(),
                 manifest,
-                DataBinding.asDisabledDataBindingContext()),
+                DataBinding.DISABLED_V1_CONTEXT),
             getOutput("merged/resources.zip"),
             getOutput("class.jar"),
             /* dataBindingInfoZip = */ null,
diff --git a/tools/android/BUILD.tools b/tools/android/BUILD.tools
index 427b33e..c5c3a5e 100644
--- a/tools/android/BUILD.tools
+++ b/tools/android/BUILD.tools
@@ -321,6 +321,14 @@
     srcs = ["bazel_debug.keystore"],
 )
 
+java_binary(
+    name = "exec_binary",
+    main_class = "android.databinding.AndroidDataBinding",
+    runtime_deps = [
+        "//third_party/java/android_databinding:exec",
+    ],
+)
+
 alias(
     name = "databinding_annotation_processor",
     actual = "//external:databinding_annotation_processor",