Initial publication of android_application rule and related changes.
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/BUILD
diff --git a/CODEOWNERS b/CODEOWNERS
deleted file mode 100644
index 6902cfb..0000000
--- a/CODEOWNERS
+++ /dev/null
@@ -1 +0,0 @@
-* @djwhang @jin @ahumesky @mauriciogg @timpeut @git-str
diff --git a/ROADMAP.md b/ROADMAP.md
deleted file mode 100644
index 57e46c3..0000000
--- a/ROADMAP.md
+++ /dev/null
@@ -1,71 +0,0 @@
-
-# Android Bazel Roadmap
-
-This document describes the major release milestones for the Android Bazel
-Rules. There are three major pillars that we are focused on when developing the
-Android rules - **Performance**, **Features**, and **Developer Experience** -
-and for each milestone we list the main items for each pillar. Progress on each
-item is tracked via an issue.
-
-If you have feedback on this roadmap (including feature and reprioritization
-requests) please open an issue or comment on the existing one.
-
-## Rules Alpha (est. mid 2019)
-
-The primary goal of the Rules Alpha release is to start collecting feedback from
-projects and developers that are interested in being early adopters of the
-rules. Our intention is for Rules Alpha to be a 1:1 identical drop-in
-replacement for the native Android rules, although undoubtedly there will be
-missing features and we cannot always guarantee 100% backwards compatibility.
-
-### Performance
-
-*   Use AAPT2 for resource processing
-*   Use D8 for Dexing
-
-### Features
-
-*   Support android_instrumentation_test on macOS
-*   Support building and testing on Google Cloud Platform Remote Build Execution
-*   Support new Android App Bundle format
-*   Accept APKs directly into android_instrumentation_test
-*   Simplified package and dependency management
-*   Improve Kotlin interoperability
-*   Integration with Bazel's platforms and toolchains support
-*   Modern and correct NDK support
-
-### Developer Experience
-
-*   Documentation for Android with Bazel compatibility across Windows, macOS,
-    Linux
-*   Documentation for Android with Bazel compatibility across Android Studio
-    versions
-*   Stable and reliable CI
-*   NDK documentation and samples
-
-## Rules Beta (est. late 2019)
-
-The goal for the Rules Beta release is to provide a stable, (mostly) feature
-complete version of the rules for all developers and projects. We intend the
-Rules Beta release to be the first version of the rules to be broadly adopted,
-and will comply with Bazel's backwards compatibility guarantees.
-
-### Performance
-
-*   Improve resource processing speed and incrementality
-*   Decouple Java compilation from R.class generation
-*   Launch Bazel mobile-install v2
-
-### Features
-
-*   New android_application rule for app packaging / sourceless binary /
-    android_application
-*   Improved support for AAR creation
-*   Support Databinding 3.4.0 (v2)
-*   Support `bazel coverage` for all test rules
-*   Integration with Android Lint
-
-### Developer Experience
-
-*   Document best practices
-*   Best in class tutorials and migration guides
diff --git a/defs.bzl b/defs.bzl
new file mode 100644
index 0000000..4ac34cc
--- /dev/null
+++ b/defs.bzl
@@ -0,0 +1,36 @@
+# Copyright 2021 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.
+
+"""Workspace setup macro for rules_android."""
+
+load("@rules_jvm_external//:defs.bzl", "maven_install")
+
+def rules_android_workspace(name):
+  """ Sets up workspace dependencies for rules_android."""
+
+  native.register_toolchains(
+      "@rules_android//toolchains/android:android_default_toolchain",
+      "@rules_android//toolchains/android_sdk:android_sdk_tools",
+  )
+
+  maven_install(
+      name = "rules_android_maven",
+      artifacts = [
+        "com.android.tools.build:bundletool:1.6.1",
+      ],
+      repositories = [
+          "https://maven.google.com",
+          "https://repo1.maven.org/maven2",
+      ],
+  )
diff --git a/rules/BUILD b/rules/BUILD
index b233605..d4c8d88 100644
--- a/rules/BUILD
+++ b/rules/BUILD
@@ -10,9 +10,3 @@
     actual = "@bazel_tools//tools/android:busybox",
     visibility =  ["//visibility:public"],
 )
-
-alias(
-    name = "current_java_runtime",
-    actual = "@bazel_tools//tools/jdk:current_java_runtime",
-    visibility = ["//visibility:public"],
-)
diff --git a/rules/aapt.bzl b/rules/aapt.bzl
new file mode 100644
index 0000000..284d89a
--- /dev/null
+++ b/rules/aapt.bzl
@@ -0,0 +1,200 @@
+# Copyright 2019 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.
+
+"""Bazel AAPT Commands."""
+
+def _link(
+        ctx,
+        out_r_java,
+        out_resource_apk,
+        manifest = None,
+        java_package = None,
+        assets = depset([]),
+        assets_dirs = [],
+        compiled_resources = depset([]),
+        config_filters = [],
+        make_r_java_ids_non_final = False,
+        compatible_with_resource_shrinking = True,
+        enable_debug = False,
+        enable_static_lib = False,
+        android_jar = None,
+        aapt = None):
+    """Links compiled Android Resources with AAPT.
+
+    Args:
+      ctx: The context.
+      out_r_java: A File. The R.java outputted by linking resources.
+      out_resource_apk: A File. The Resource APK outputted by linking resources.
+      manifest: A File. The AndroidManifest.xml.
+      java_package: A string. The Java package for the generated R.java.
+      assets: A list of Files. The list of assets from the transitive closure of
+        the project.
+      assets_dirs: A list of strings. The list of asset directories in the
+        transitive closure of the project.
+      compiled_resources: List of intermediate compiled android resource files.
+      config_filters: A list of Strings. The configuration filters.
+      make_r_java_ids_non_final: A bool. Makes the R.java produced from linkin
+        have non-final values.
+      compatible_with_resource_shrinking: A bool. When enabled produces the
+        output in proto format which is a requirement for resource shrinking.
+      enable_debug: A bool. Enable debugging
+      enable_static_lib: A bool. Enable static lib.
+      android_jar: A File. The Android Jar.
+      aapt: A FilesToRunProvider. The AAPT executable.
+    """
+
+    # Output the list of resources in reverse topological order.
+    resources_param = ctx.actions.declare_file(
+        out_r_java.basename + ".params",
+        sibling = out_r_java,
+    )
+    args = ctx.actions.args()
+    args.use_param_file("%s", use_always = True)
+    args.set_param_file_format("multiline")
+    args.add_all(compiled_resources, expand_directories = True)
+    ctx.actions.run_shell(
+        command = """
+# Reverses the set of inputs that have been topologically ordered to utilize the
+# overlay/override semantics of aapt2.
+set -e
+
+echo $(tac $1) > $2
+""",
+        arguments = [args, resources_param.path],
+        outputs = [resources_param],
+        inputs = compiled_resources,
+    )
+
+    args = ctx.actions.args()
+    args.add("link")
+    if enable_static_lib:
+        args.add("--static-lib")
+    args.add("--no-version-vectors")
+    args.add("--no-static-lib-packages")  # Turn off namespaced resource
+
+    args.add("--manifest", manifest)
+    args.add("--auto-add-overlay")  # Enables resource redefinition and merging
+    args.add("--override-styles-instead-of-overlaying")  # mimic AAPT1.
+    if make_r_java_ids_non_final:
+        args.add("--non-final-ids")
+    if compatible_with_resource_shrinking:
+        args.add("--proto-format")
+    if enable_debug:
+        args.add("--debug-mode")
+    args.add("--custom-package", java_package)
+    args.add("-I", android_jar)
+    args.add_all(assets_dirs, before_each = "-A")
+    args.add("-R", resources_param, format = "@%s")
+    args.add("-0", ".apk")
+    args.add_joined("-c", config_filters, join_with = ",", omit_if_empty = True)
+    args.add("--java", out_r_java.path.rpartition(java_package.replace(".", "/"))[0])
+    args.add("-o", out_resource_apk)
+
+    ctx.actions.run(
+        executable = aapt,
+        arguments = [args],
+        inputs = depset(
+            [android_jar, resources_param] +
+            ([manifest] if manifest else []),
+            transitive = [assets, compiled_resources],
+        ),
+        outputs = [out_resource_apk, out_r_java],
+        mnemonic = "LinkAndroidResources",
+        progress_message = "ResV3 Linking Android Resources to %s" % out_resource_apk.short_path,
+    )
+
+def _compile(
+        ctx,
+        out_dir,
+        resource_files,
+        aapt):
+    """Compile and store resources in a single archive.
+
+    Args:
+      ctx: The context.
+      out_dir: File. A file to store the output.
+      resource_files: A list of Files. The list of resource files or directories
+        to process.
+      aapt: AAPT. Tool for compiling resources.
+    """
+    if not out_dir:
+        fail("No output directory specified.")
+    if not out_dir.is_directory:
+        fail("Output directory is not a directory artifact.")
+    if not resource_files:
+        fail("No resource files given.")
+
+    # Retrieves the list of files at runtime when a directory is passed.
+    args = ctx.actions.args()
+    args.add_all(resource_files, expand_directories = True)
+
+    ctx.actions.run_shell(
+        command = """
+set -e
+
+AAPT=%s
+OUT_DIR=%s
+RESOURCE_FILES=$@
+
+i=0
+declare -A out_dir_map
+for f in ${RESOURCE_FILES}; do
+  res_dir="$(dirname $(dirname ${f}))"
+  if [ -z "${out_dir_map[${res_dir}]}" ]; then
+      out_dir="${OUT_DIR}/$((++i))"
+      mkdir -p ${out_dir}
+      out_dir_map[${res_dir}]="${out_dir}"
+  fi
+  # Outputs from multiple directories can overwrite the outputs. As we do not
+  # control the outputs for now store each in its own sub directory which will be
+  # captured by the over_dir.
+  # TODO(b/139757260): Re-evaluate this one compile per file or multiple and zip
+  # merge.
+  "${AAPT}" compile --legacy "${f}" -o "${out_dir_map[${res_dir}]}"
+done
+""" % (aapt.executable.path, out_dir.path),
+        tools = [aapt],
+        arguments = [args],
+        inputs = resource_files,
+        outputs = [out_dir],
+        mnemonic = "CompileAndroidResources",
+        progress_message = "ResV3 Compiling Android Resources in %s" % out_dir,
+    )
+
+def _convert(
+        ctx,
+        out = None,
+        input = None,
+        to_proto = False,
+        aapt = None):
+    args = ctx.actions.args()
+    args.add("convert")
+    args.add("--output-format", ("proto" if to_proto else "binary"))
+    args.add("-o", out)
+    args.add(input)
+
+    ctx.actions.run(
+        executable = aapt,
+        arguments = [args],
+        inputs = [input],
+        outputs = [out],
+        mnemonic = "AaptConvert",
+        progress_message = "ResV3 Convert to %s" % out.short_path,
+    )
+
+aapt = struct(
+    link = _link,
+    compile = _compile,
+    convert = _convert,
+)
diff --git a/rules/aar_import/impl.bzl b/rules/aar_import/impl.bzl
index 96baa2b..cec5a84 100644
--- a/rules/aar_import/impl.bzl
+++ b/rules/aar_import/impl.bzl
@@ -46,6 +46,10 @@
     "a lint.jar file."
 )
 
+# Resources context dict fields.
+_PROVIDERS = "providers"
+_VALIDATION_RESULTS = "validation_results"
+
 def _create_aar_artifact(ctx, name):
     return ctx.actions.declare_file("%s/%s/%s" % (RULE_PREFIX, ctx.label.name, name))
 
@@ -114,6 +118,7 @@
 def _process_resources(
         ctx,
         aar,
+        package,
         manifest,
         deps,
         aar_resources_extractor_tool,
@@ -139,6 +144,7 @@
         deps = ctx.attr.deps,
         exports = ctx.attr.exports,
         exports_manifest = getattr(ctx.attr, "exports_manifest", True),
+        propagate_resources = _acls.in_aar_propagate_resources(str(ctx.label)),
 
         # Tool and Processing related inputs
         aapt = _get_android_toolchain(ctx).aapt2.files_to_run,
@@ -151,23 +157,15 @@
         xsltproc = _get_android_toolchain(ctx).xsltproc_tool.files_to_run,
     )
 
-    # TODO: replace android_data
-    # data_ctx = android_data.make_context(ctx.actions, ctx.attr)
-    # resource_apk = android_data.process_aar_import_data(
-    #     data_ctx,
-    #     resources,
-    #     assets,
-    #     manifest,
-    #     deps = deps,
-    # )
-    # resources_ctx["validation_results"].append(
-    #     _utils.only(resource_apk[AndroidResourcesInfo].direct_android_resources.to_list()).java_class_jar,
-    # )
-    # resources_ctx["providers"].append(resource_apk[AndroidResourcesInfo])
-    # resources_ctx["providers"].append(resource_apk[AndroidAssetsInfo])
+    native_android_manifest = manifest
+    if not getattr(ctx.attr, "exports_manifest", True):
+        # Write an empty manifest, for the native pipeline.
+        native_android_manifest = ctx.actions.declare_file(ctx.label.name + "_aar/AndroidManifest.xml")
+        ctx.actions.write(native_android_manifest, content = """<?xml version="1.0" encoding="utf-8"?>
+<manifest package="%s">
+</manifest>
+""" % package)
 
-    if not _acls.in_aar_propagate_resources(str(ctx.label)):
-        resources_ctx["providers"] = []
 
     return struct(**resources_ctx)
 
@@ -355,19 +353,16 @@
 def _validate_rule(
         ctx,
         aar,
+        package,
         manifest,
         checks):
-    package = _java.resolve_package_from_label(ctx.label, ctx.attr.package)
     validation_output = ctx.actions.declare_file("%s_validation_output" % ctx.label.name)
 
     args = ctx.actions.args()
     args.add("-aar", aar)
-    inputs = [aar]
     args.add("-label", str(ctx.label))
-    if _acls.in_aar_import_pkg_check(str(ctx.label)):
-        args.add("-pkg", package)
-        args.add("-manifest", manifest)
-        inputs.append(manifest)
+    args.add("-pkg", package)
+    args.add("-manifest", manifest)
     if ctx.attr.has_lint_jar:
         args.add("-has_lint_jar")
     args.add("-output", validation_output)
@@ -375,7 +370,7 @@
     ctx.actions.run(
         executable = checks,
         arguments = [args],
-        inputs = inputs,
+        inputs = [aar, manifest],
         outputs = [validation_output],
         mnemonic = "ValidateAAR",
         progress_message = "Validating aar_import %s" % str(ctx.label),
@@ -407,6 +402,27 @@
     ))
     return providers
 
+def _collect_proguard(
+        ctx,
+        out_proguard,
+        aar,
+        aar_embedded_proguard_extractor):
+    args = ctx.actions.args()
+    args.add("--input_aar", aar)
+    args.add("--output_proguard_file", out_proguard)
+    ctx.actions.run(
+        executable = aar_embedded_proguard_extractor,
+        arguments = [args],
+        inputs = [aar],
+        outputs = [out_proguard],
+        mnemonic = "AarEmbeddedProguardExtractor",
+        progress_message = "Extracting proguard spec from %s" % aar.basename,
+    )
+    transitive_proguard_specs = []
+    for p in _utils.collect_providers(ProguardSpecProvider, ctx.attr.deps, ctx.attr.exports):
+        transitive_proguard_specs.append(p.specs)
+    return ProguardSpecProvider(depset([out_proguard], transitive = transitive_proguard_specs))
+
 def impl(ctx):
     """The rule implementation.
 
@@ -421,6 +437,7 @@
 
     aar = _utils.only(ctx.files.aar)
     unzip_tool = _get_android_toolchain(ctx).unzip_tool.files_to_run
+    package = _java.resolve_package_from_label(ctx.label, ctx.attr.package)
 
     # Extract the AndroidManifest.xml from the AAR.
     android_manifest = _create_aar_artifact(ctx, ANDROID_MANIFEST)
@@ -435,6 +452,7 @@
     resources_ctx = _process_resources(
         ctx,
         aar = aar,
+        package = package,
         manifest = android_manifest,
         deps = ctx.attr.deps,
         aar_resources_extractor_tool =
@@ -495,6 +513,15 @@
         ),
     )
 
+    # Will be empty if there's no proguard.txt file in the aar
+    proguard_spec = _create_aar_artifact(ctx, "proguard.txt")
+    providers.append(_collect_proguard(
+        ctx,
+        proguard_spec,
+        aar,
+        _get_android_toolchain(ctx).aar_embedded_proguard_extractor.files_to_run,
+    ))
+
     lint_providers = _process_lint_rules(
         ctx,
         aar = aar,
@@ -505,6 +532,7 @@
     validation_outputs.append(_validate_rule(
         ctx,
         aar = aar,
+        package = package,
         manifest = android_manifest,
         checks = _get_android_toolchain(ctx).aar_import_checks.files_to_run,
     ))
diff --git a/rules/aar_import/rule.bzl b/rules/aar_import/rule.bzl
index fa78a88..02a1d61 100644
--- a/rules/aar_import/rule.bzl
+++ b/rules/aar_import/rule.bzl
@@ -21,6 +21,11 @@
     attrs = _ATTRS,
     fragments = ["android"],
     implementation = _impl,
-    provides = [AndroidNativeLibsInfo, JavaInfo],
+    provides = [
+        AndroidIdeInfo,
+        AndroidLibraryResourceClassJarProvider,
+        AndroidNativeLibsInfo,
+        JavaInfo,
+    ],
     toolchains = ["@rules_android//toolchains/android:toolchain_type"],
 )
diff --git a/rules/acls.bzl b/rules/acls.bzl
index ade99db..ea5032d 100644
--- a/rules/acls.bzl
+++ b/rules/acls.bzl
@@ -30,19 +30,20 @@
 load("@rules_android//rules/acls:aar_import_deps_checker.bzl", "AAR_IMPORT_DEPS_CHECKER_FALLBACK", "AAR_IMPORT_DEPS_CHECKER_ROLLOUT")
 load("@rules_android//rules/acls:aar_import_explicit_exports_manifest.bzl", "AAR_IMPORT_EXPLICIT_EXPORTS_MANIFEST")
 load("@rules_android//rules/acls:aar_import_exports_r_java.bzl", "AAR_IMPORT_EXPORTS_R_JAVA")
-load("@rules_android//rules/acls:aar_import_package_check.bzl", "AAR_IMPORT_PKG_CHECK_FALLBACK", "AAR_IMPORT_PKG_CHECK_ROLLOUT")
 load("@rules_android//rules/acls:aar_propagate_resources.bzl", "AAR_PROPAGATE_RESOURCES_FALLBACK", "AAR_PROPAGATE_RESOURCES_ROLLOUT")
 load("@rules_android//rules/acls:ait_install_snapshots.bzl", "APP_INSTALLATION_SNAPSHOT", "APP_INSTALLATION_SNAPSHOT_FALLBACK")
 load("@rules_android//rules/acls:ait_virtual_device.bzl", "AIT_VIRTUAL_DEVICE_FALLBACK", "AIT_VIRTUAL_DEVICE_ROLLOUT")
 load("@rules_android//rules/acls:allow_resource_conflicts.bzl", "ALLOW_RESOURCE_CONFLICTS")
 load("@rules_android//rules/acls:android_archive_dogfood.bzl", "ANDROID_ARCHIVE_DOGFOOD")
+load("@rules_android//rules/acls:android_archive_excluded_deps_denylist.bzl", "ANDROID_ARCHIVE_EXCLUDED_DEPS_DENYLIST")
 load("@rules_android//rules/acls:android_test_lockdown.bzl", "ANDROID_TEST_LOCKDOWN_GENERATOR_FUNCTIONS", "ANDROID_TEST_LOCKDOWN_TARGETS")
 load("@rules_android//rules/acls:android_device_plugin_rollout.bzl", "ANDROID_DEVICE_PLUGIN_FALLBACK", "ANDROID_DEVICE_PLUGIN_ROLLOUT")
 load("@rules_android//rules/acls:android_instrumentation_binary_starlark_resources.bzl", "ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_FALLBACK", "ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_ROLLOUT")
 load("@rules_android//rules/acls:android_feature_splits_dogfood.bzl", "ANDROID_FEATURE_SPLITS_DOGFOOD")
 load("@rules_android//rules/acls:android_library_implicit_exports.bzl", "ANDROID_LIBRARY_IMPLICIT_EXPORTS", "ANDROID_LIBRARY_IMPLICIT_EXPORTS_GENERATOR_FUNCTIONS")
 load("@rules_android//rules/acls:android_library_resources_without_srcs.bzl", "ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS", "ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS_GENERATOR_FUNCTIONS")
-load("@rules_android//rules/acls:android_lint_rollout.bzl", "ANDROID_LINT_ROLLOUT")
+load("@rules_android//rules/acls:android_lint_checks_rollout.bzl", "ANDROID_LINT_CHECKS_FALLBACK", "ANDROID_LINT_CHECKS_ROLLOUT")
+load("@rules_android//rules/acls:android_lint_rollout.bzl", "ANDROID_LINT_FALLBACK", "ANDROID_LINT_ROLLOUT")
 load("@rules_android//rules/acls:android_build_stamping_rollout.bzl", "ANDROID_BUILD_STAMPING_FALLBACK", "ANDROID_BUILD_STAMPING_ROLLOUT")
 load("@rules_android//rules/acls:b122039567.bzl", "B122039567")
 load("@rules_android//rules/acls:b123854163.bzl", "B123854163")
@@ -55,7 +56,6 @@
 load("@rules_android//rules/acls:local_test_multi_proto.bzl", "LOCAL_TEST_MULTI_PROTO_PKG")
 load("@rules_android//rules/acls:local_test_rollout.bzl", "LOCAL_TEST_FALLBACK", "LOCAL_TEST_ROLLOUT")
 load("@rules_android//rules/acls:local_test_starlark_resources.bzl", "LOCAL_TEST_STARLARK_RESOURCES_FALLBACK", "LOCAL_TEST_STARLARK_RESOURCES_ROLLOUT")
-load("@rules_android//rules/acls:nitrogen_test_runner_rollout.bzl", "NITROGEN_AT_TEST_RUNNER_ROLLOUT", "NITROGEN_TEST_RUNNER_FALLBACK", "NITROGEN_TEST_RUNNER_ROLLOUT")
 load("@rules_android//rules/acls:android_test_platform_rollout.bzl", "ANDROID_TEST_PLATFORM_FALLBACK", "ANDROID_TEST_PLATFORM_ROLLOUT")
 load("@rules_android//rules/acls:sourceless_binary_rollout.bzl", "SOURCELESS_BINARY_FALLBACK", "SOURCELESS_BINARY_ROLLOUT")
 load("@rules_android//rules/acls:test_to_instrument_test_rollout.bzl", "TEST_TO_INSTRUMENT_TEST_FALLBACK", "TEST_TO_INSTRUMENT_TEST_ROLLOUT")
@@ -75,9 +75,6 @@
 def _in_aar_import_exports_r_java(fqn):
     return _matches(fqn, AAR_IMPORT_EXPORTS_R_JAVA_DICT)
 
-def _in_aar_import_pkg_check(fqn):
-    return not _matches(fqn, AAR_IMPORT_PKG_CHECK_FALLBACK_DICT) and _matches(fqn, AAR_IMPORT_PKG_CHECK_ROLLOUT_DICT)
-
 def _in_aar_propagate_resources(fqn):
     return not _matches(fqn, AAR_PROPAGATE_RESOURCES_FALLBACK_DICT) and _matches(fqn, AAR_PROPAGATE_RESOURCES_ROLLOUT_DICT)
 
@@ -87,6 +84,9 @@
 def _in_android_archive_dogfood(fqn):
     return _matches(fqn, ANDROID_ARCHIVE_DOGFOOD_DICT)
 
+def _in_android_archive_excluded_deps_denylist(fqn):
+    return _matches(fqn, ANDROID_ARCHIVE_EXCLUDED_DEPS_DENYLIST_DICT)
+
 def _in_android_device_plugin_rollout(fqn):
     return not _matches(fqn, ANDROID_DEVICE_PLUGIN_FALLBACK_DICT) and _matches(fqn, ANDROID_DEVICE_PLUGIN_ROLLOUT_DICT)
 
@@ -96,14 +96,19 @@
 def _in_android_feature_splits_dogfood(fqn):
     return _matches(fqn, ANDROID_FEATURE_SPLITS_DOGFOOD_DICT)
 
+def _in_android_lint_checks_rollout(fqn):
+    return not _matches(fqn, ANDROID_LINT_CHECKS_FALLBACK_DICT) and _matches(fqn, ANDROID_LINT_CHECKS_ROLLOUT_DICT)
+
 def _in_android_lint_rollout(fqn):
-    return _matches(fqn, ANDROID_LINT_ROLLOUT_DICT)
+    return not _matches(fqn, ANDROID_LINT_FALLBACK_DICT) and _matches(fqn, ANDROID_LINT_ROLLOUT_DICT)
 
 def _in_android_build_stamping_rollout(fqn):
     return not _matches(fqn, ANDROID_BUILD_STAMPING_FALLBACK_DICT) and _matches(fqn, ANDROID_BUILD_STAMPING_ROLLOUT_DICT)
 
 def _in_android_test_lockdown_allowlist(fqn, generator):
-    return _matches(fqn, ANDROID_TEST_LOCKDOWN_TARGETS_DICT) or generator in ANDROID_TEST_LOCKDOWN_GENERATOR_FUNCTIONS_DICT
+    if generator == "android_test":
+        return _matches(fqn, ANDROID_TEST_LOCKDOWN_TARGETS)
+    return generator in ANDROID_TEST_LOCKDOWN_GENERATOR_FUNCTIONS_DICT
 
 def _in_b122039567(fqn):
     return _matches(fqn, B122039567_DICT)
@@ -153,12 +158,6 @@
 def _in_local_test_starlark_resources(fqn):
     return not _matches(fqn, LOCAL_TEST_STARLARK_RESOURCES_FALLBACK_DICT) and _matches(fqn, LOCAL_TEST_STARLARK_RESOURCES_ROLLOUT_DICT)
 
-def _in_nitrogen_test_runner_rollout(fqn):
-    return not _matches(fqn, NITROGEN_TEST_RUNNER_FALLBACK_DICT) and _matches(fqn, NITROGEN_TEST_RUNNER_ROLLOUT_DICT)
-
-def _in_nitrogen_at_test_runner_rollout(fqn):
-    return not _matches(fqn, NITROGEN_TEST_RUNNER_FALLBACK_DICT) and _matches(fqn, NITROGEN_AT_TEST_RUNNER_ROLLOUT_DICT)
-
 def _in_android_test_platform_rollout(fqn):
     return not _matches(fqn, ANDROID_TEST_PLATFORM_FALLBACK_DICT) and _matches(fqn, ANDROID_TEST_PLATFORM_ROLLOUT_DICT)
 
@@ -185,13 +184,12 @@
 AAR_IMPORT_DEPS_CHECKER_ROLLOUT_DICT = _make_dict(AAR_IMPORT_DEPS_CHECKER_ROLLOUT)
 AAR_IMPORT_EXPLICIT_EXPORTS_MANIFEST_DICT = _make_dict(AAR_IMPORT_EXPLICIT_EXPORTS_MANIFEST)
 AAR_IMPORT_EXPORTS_R_JAVA_DICT = _make_dict(AAR_IMPORT_EXPORTS_R_JAVA)
-AAR_IMPORT_PKG_CHECK_FALLBACK_DICT = _make_dict(AAR_IMPORT_PKG_CHECK_FALLBACK)
-AAR_IMPORT_PKG_CHECK_ROLLOUT_DICT = _make_dict(AAR_IMPORT_PKG_CHECK_ROLLOUT)
 AAR_PROPAGATE_RESOURCES_FALLBACK_DICT = _make_dict(AAR_PROPAGATE_RESOURCES_FALLBACK)
 AAR_PROPAGATE_RESOURCES_ROLLOUT_DICT = _make_dict(AAR_PROPAGATE_RESOURCES_ROLLOUT)
 AIT_VIRTUAL_DEVICE_FALLBACK_DICT = _make_dict(AIT_VIRTUAL_DEVICE_FALLBACK)
 AIT_VIRTUAL_DEVICE_ROLLOUT_DICT = _make_dict(AIT_VIRTUAL_DEVICE_ROLLOUT)
 ANDROID_ARCHIVE_DOGFOOD_DICT = _make_dict(ANDROID_ARCHIVE_DOGFOOD)
+ANDROID_ARCHIVE_EXCLUDED_DEPS_DENYLIST_DICT = _make_dict(ANDROID_ARCHIVE_EXCLUDED_DEPS_DENYLIST)
 ANDROID_DEVICE_PLUGIN_ROLLOUT_DICT = _make_dict(ANDROID_DEVICE_PLUGIN_ROLLOUT)
 ANDROID_DEVICE_PLUGIN_FALLBACK_DICT = _make_dict(ANDROID_DEVICE_PLUGIN_FALLBACK)
 ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_ROLLOUT_DICT = _make_dict(ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_ROLLOUT)
@@ -201,6 +199,9 @@
 ANDROID_LIBRARY_IMPLICIT_EXPORTS_GENERATOR_FUNCTIONS_DICT = _make_dict(ANDROID_LIBRARY_IMPLICIT_EXPORTS_GENERATOR_FUNCTIONS)
 ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS_DICT = _make_dict(ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS)
 ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS_GENERATOR_FUNCTIONS_DICT = _make_dict(ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS_GENERATOR_FUNCTIONS)
+ANDROID_LINT_CHECKS_FALLBACK_DICT = _make_dict(ANDROID_LINT_CHECKS_FALLBACK)
+ANDROID_LINT_CHECKS_ROLLOUT_DICT = _make_dict(ANDROID_LINT_CHECKS_ROLLOUT)
+ANDROID_LINT_FALLBACK_DICT = _make_dict(ANDROID_LINT_FALLBACK)
 ANDROID_LINT_ROLLOUT_DICT = _make_dict(ANDROID_LINT_ROLLOUT)
 ANDROID_BUILD_STAMPING_ROLLOUT_DICT = _make_dict(ANDROID_BUILD_STAMPING_ROLLOUT)
 ANDROID_BUILD_STAMPING_FALLBACK_DICT = _make_dict(ANDROID_BUILD_STAMPING_FALLBACK)
@@ -225,9 +226,6 @@
 LOCAL_TEST_ROLLOUT_DICT = _make_dict(LOCAL_TEST_ROLLOUT)
 LOCAL_TEST_STARLARK_RESOURCES_FALLBACK_DICT = _make_dict(LOCAL_TEST_STARLARK_RESOURCES_FALLBACK)
 LOCAL_TEST_STARLARK_RESOURCES_ROLLOUT_DICT = _make_dict(LOCAL_TEST_STARLARK_RESOURCES_ROLLOUT)
-NITROGEN_TEST_RUNNER_FALLBACK_DICT = _make_dict(NITROGEN_TEST_RUNNER_FALLBACK)
-NITROGEN_TEST_RUNNER_ROLLOUT_DICT = _make_dict(NITROGEN_TEST_RUNNER_ROLLOUT)
-NITROGEN_AT_TEST_RUNNER_ROLLOUT_DICT = _make_dict(NITROGEN_AT_TEST_RUNNER_ROLLOUT)
 ANDROID_TEST_PLATFORM_FALLBACK_DICT = _make_dict(ANDROID_TEST_PLATFORM_FALLBACK)
 ANDROID_TEST_PLATFORM_ROLLOUT_DICT = _make_dict(ANDROID_TEST_PLATFORM_ROLLOUT)
 SOURCELESS_BINARY_FALLBACK_DICT = _make_dict(SOURCELESS_BINARY_FALLBACK)
@@ -241,6 +239,10 @@
 KT_ANDROID_LIBRARY_FALLBACK_DICT = _make_dict(KT_ANDROID_LIBRARY_FALLBACK)
 
 def _matches(fqn, dct):
+    # Labels with workspace names ("@workspace//pkg:target") are not supported.
+    if fqn.startswith("@"):
+        return False
+
     if not fqn.startswith("//"):
         fail("Fully qualified target should start with '//', got: " + fqn)
 
@@ -273,7 +275,6 @@
 
 acls = struct(
     in_aar_import_deps_checker = _in_aar_import_deps_checker,
-    in_aar_import_pkg_check = _in_aar_import_pkg_check,
     in_aar_import_explicit_exports_manifest = _in_aar_import_explicit_exports_manifest,
     in_aar_import_exports_r_java = _in_aar_import_exports_r_java,
     in_aar_propagate_resources = _in_aar_propagate_resources,
@@ -281,6 +282,7 @@
     in_b122039567 = _in_b122039567,
     in_b123854163 = _in_b123854163,
     in_android_archive_dogfood = _in_android_archive_dogfood,
+    in_android_archive_excluded_deps_denylist = _in_android_archive_excluded_deps_denylist,
     in_android_device_plugin_rollout = _in_android_device_plugin_rollout,
     in_android_instrumentation_binary_starlark_resources = _in_android_instrumentation_binary_starlark_resources,
     in_android_feature_splits_dogfood = _in_android_feature_splits_dogfood,
@@ -288,6 +290,7 @@
     in_android_library_implicit_exports_generator_functions = _in_android_library_implicit_exports_generator_functions,
     in_android_library_resources_without_srcs = _in_android_library_resources_without_srcs,
     in_android_library_resources_without_srcs_generator_functions = _in_android_library_resources_without_srcs_generator_functions,
+    in_android_lint_checks_rollout = _in_android_lint_checks_rollout,
     in_android_lint_rollout = _in_android_lint_rollout,
     in_android_build_stamping_rollout = _in_android_build_stamping_rollout,
     in_android_test_lockdown_allowlist = _in_android_test_lockdown_allowlist,
@@ -301,8 +304,6 @@
     in_local_test_multi_proto = _in_local_test_multi_proto,
     in_local_test_rollout = _in_local_test_rollout,
     in_local_test_starlark_resources = _in_local_test_starlark_resources,
-    in_nitrogen_test_runner_rollout = _in_nitrogen_test_runner_rollout,
-    in_nitrogen_at_test_runner_rollout = _in_nitrogen_at_test_runner_rollout,
     in_android_test_platform_rollout = _in_android_test_platform_rollout,
     in_sourceless_binary_rollout = _in_sourceless_binary_rollout,
     in_test_to_instrument_test_rollout = _in_test_to_instrument_test_rollout,
diff --git a/rules/acls/aar_import_exports_r_java.bzl b/rules/acls/aar_import_exports_r_java.bzl
index c0a07a4..7d2aff1 100644
--- a/rules/acls/aar_import_exports_r_java.bzl
+++ b/rules/acls/aar_import_exports_r_java.bzl
@@ -1,4 +1,4 @@
-# Copyright 2020 The Bazel Authors. All rights reserved.
+# Copyright 2021 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.
diff --git a/rules/acls/aar_import_package_check.bzl b/rules/acls/android_archive_excluded_deps_denylist.bzl
similarity index 70%
copy from rules/acls/aar_import_package_check.bzl
copy to rules/acls/android_archive_excluded_deps_denylist.bzl
index 54b2b51..2a46e68 100644
--- a/rules/acls/aar_import_package_check.bzl
+++ b/rules/acls/android_archive_excluded_deps_denylist.bzl
@@ -12,10 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Allow list for checking the package value with the manifest."""
-AAR_IMPORT_PKG_CHECK_ROLLOUT = [
-    "//:__subpackages__",
-]
+"""Denylist for rules that are not allowed in android_archive excluded_deps."""
 
-AAR_IMPORT_PKG_CHECK_FALLBACK = [
+# keep sorted
+ANDROID_ARCHIVE_EXCLUDED_DEPS_DENYLIST = [
+    # Failure test support.
+    "@rules_android//test/rules/android_archive/java/com/testdata/denied:__pkg__",
 ]
diff --git a/rules/acls/android_build_stamping_rollout.bzl b/rules/acls/android_build_stamping_rollout.bzl
index 5b1169a..8747db8 100644
--- a/rules/acls/android_build_stamping_rollout.bzl
+++ b/rules/acls/android_build_stamping_rollout.bzl
@@ -19,4 +19,5 @@
 ]
 
 # keep sorted
-ANDROID_BUILD_STAMPING_FALLBACK = []
+ANDROID_BUILD_STAMPING_FALLBACK = [
+]
diff --git a/rules/acls/android_feature_splits_dogfood.bzl b/rules/acls/android_feature_splits_dogfood.bzl
index 159ef42..0e7ade0 100644
--- a/rules/acls/android_feature_splits_dogfood.bzl
+++ b/rules/acls/android_feature_splits_dogfood.bzl
@@ -12,13 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Allowlist for packages able to use Android feature splits.
-
-Dynamic feature splits are still in development and at this stage are only suitable for use
-in an experimental capacity.
-"""
+"""Packages able to use deprecated Android feature splits features."""
 
 # keep sorted
 ANDROID_FEATURE_SPLITS_DOGFOOD = [
-    "//:__subpackages__",
 ]
diff --git a/rules/acls/aar_import_package_check.bzl b/rules/acls/android_lint_checks_rollout.bzl
similarity index 78%
rename from rules/acls/aar_import_package_check.bzl
rename to rules/acls/android_lint_checks_rollout.bzl
index 54b2b51..ee44280 100644
--- a/rules/acls/aar_import_package_check.bzl
+++ b/rules/acls/android_lint_checks_rollout.bzl
@@ -12,10 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Allow list for checking the package value with the manifest."""
-AAR_IMPORT_PKG_CHECK_ROLLOUT = [
-    "//:__subpackages__",
+"""Allow list for enabling Android Lint checks in the Android Rules."""
+
+# keep sorted
+ANDROID_LINT_CHECKS_ROLLOUT = [
 ]
 
-AAR_IMPORT_PKG_CHECK_FALLBACK = [
+ANDROID_LINT_CHECKS_FALLBACK = [
 ]
diff --git a/rules/acls/android_lint_rollout.bzl b/rules/acls/android_lint_rollout.bzl
index 65f9ff7..aab1d59 100644
--- a/rules/acls/android_lint_rollout.bzl
+++ b/rules/acls/android_lint_rollout.bzl
@@ -17,3 +17,5 @@
 # keep sorted
 ANDROID_LINT_ROLLOUT = [
 ]
+
+ANDROID_LINT_FALLBACK = []
diff --git a/rules/acls/aar_import_package_check.bzl b/rules/acls/use_classic_desugar.bzl
similarity index 78%
copy from rules/acls/aar_import_package_check.bzl
copy to rules/acls/use_classic_desugar.bzl
index 54b2b51..37110c4 100644
--- a/rules/acls/aar_import_package_check.bzl
+++ b/rules/acls/use_classic_desugar.bzl
@@ -12,10 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Allow list for checking the package value with the manifest."""
-AAR_IMPORT_PKG_CHECK_ROLLOUT = [
-    "//:__subpackages__",
-]
+"""List of targets that require classic desugar."""
 
-AAR_IMPORT_PKG_CHECK_FALLBACK = [
+USE_CLASSIC_DESUGAR = [
 ]
diff --git a/rules/android_application/BUILD b/rules/android_application/BUILD
new file mode 100644
index 0000000..31cf119
--- /dev/null
+++ b/rules/android_application/BUILD
@@ -0,0 +1,27 @@
+# The android_application rule.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+licenses(["notice"])
+
+exports_files([
+    "bundle_deploy.sh_template",
+    "feature_module_validation.sh",
+    "gen_android_feature_manifest.sh",
+    "gen_priority_android_feature_manifest.sh",
+    "rule.bzl",
+])
+
+filegroup(
+    name = "all_files",
+    srcs = glob(["**"]),
+)
+
+bzl_library(
+    name = "bzl",
+    srcs = glob(["*.bzl"]),
+    deps = [
+        "@rules_android//rules:common_bzl",
+        "@rules_android//rules/flags:bzl",
+    ],
+)
diff --git a/rules/android_application/android_application.bzl b/rules/android_application/android_application.bzl
new file mode 100644
index 0000000..f7e1710
--- /dev/null
+++ b/rules/android_application/android_application.bzl
@@ -0,0 +1,51 @@
+# Copyright 2021 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.
+
+"""android_application rule.
+
+This file exists to inject the correct version of android_binary.
+"""
+
+load(":android_application_rule.bzl", _android_application_macro = "android_application_macro")
+load("@rules_android//rules:android_binary.bzl", _android_binary = "android_binary")
+
+def android_application(**attrs):
+    """Rule to build an Android Application (app bundle).
+
+    `android_application` produces an app bundle (.aab) rather than an apk, and treats splits
+    (both configuration and dynamic feature modules) as first-class constructs. If
+    `feature_modules`, `bundle_config` or both are supplied this rule will produce an .aab.
+    Otherwise it will fall back to `android_binary` and produce an apk.
+
+    **Attributes**
+
+    `android_application` accepts all the same attributes as `android_binary`, with the following
+    key differences.
+
+    Name | Description
+    --- | ---
+    `srcs` | `android_application` does not accept sources.
+    `manifest_values` | Required. Must specify `applicationId` in the `manifest_values`
+    `feature_modules` | New. List of labels to `android_feature_module`s to include as feature splits. Note: must be fully qualified paths (//some:target), not relative.
+    `bundle_config_file` | New. String path to .pb.json file containing the bundle config. See the [bundletool docs](https://developer.android.com/studio/build/building-cmdline#bundleconfig) for format and examples. Note: this attribute is subject to changes which may require teams to migrate their configurations to a build target.
+    `app_integrity_config` | Optional. String path to .binarypb file containing the play integrity config. See https://github.com/google/bundletool/blob/master/src/main/proto/app_integrity_config.proto.
+    `rotation_config` | Optional. String path to .textproto file containing the V3 rotation config.
+
+    Args:
+          **attrs: Rule attributes
+    """
+    _android_application_macro(
+        _android_binary = _android_binary,
+        **attrs
+    )
diff --git a/rules/android_application/android_application_rule.bzl b/rules/android_application/android_application_rule.bzl
new file mode 100644
index 0000000..ab26456
--- /dev/null
+++ b/rules/android_application/android_application_rule.bzl
@@ -0,0 +1,385 @@
+# Copyright 2021 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.
+
+"""android_application rule."""
+
+load(":android_feature_module_rule.bzl", "get_feature_module_paths")
+load(":attrs.bzl", "ANDROID_APPLICATION_ATTRS")
+load(
+    "@rules_android//rules:aapt.bzl",
+    _aapt = "aapt",
+)
+load(
+    "@rules_android//rules:bundletool.bzl",
+    _bundletool = "bundletool",
+)
+load(
+    "@rules_android//rules:busybox.bzl",
+    _busybox = "busybox",
+)
+load(
+    "@rules_android//rules:common.bzl",
+    _common = "common",
+)
+load(
+    "@rules_android//rules:java.bzl",
+    _java = "java",
+)
+load(
+    "@rules_android//rules:providers.bzl",
+    "AndroidBundleInfo",
+    "AndroidFeatureModuleInfo",
+    "StarlarkAndroidResourcesInfo",
+)
+load(
+    "@rules_android//rules:utils.bzl",
+    "get_android_toolchain",
+    _log = "log",
+)
+
+UNSUPPORTED_ATTRS = [
+    "srcs",
+]
+
+def _verify_attrs(attrs, fqn):
+    for attr in UNSUPPORTED_ATTRS:
+        if hasattr(attrs, attr):
+            _log.error("Unsupported attr: %s in android_application" % attr)
+
+    if not attrs.get("manifest_values", default = {}).get("applicationId"):
+        _log.error("%s missing required applicationId in manifest_values" % fqn)
+
+    for attr in ["deps"]:
+        if attr not in attrs:
+            _log.error("%s missing require attribute `%s`" % (fqn, attr))
+
+def _process_feature_module(
+        ctx,
+        out = None,
+        base_apk = None,
+        feature_target = None,
+        java_package = None,
+        application_id = None):
+    manifest = _create_feature_manifest(
+        ctx,
+        base_apk,
+        java_package,
+        feature_target,
+        ctx.attr._android_sdk[AndroidSdkInfo].aapt2,
+        ctx.executable._feature_manifest_script,
+        ctx.executable._priority_feature_manifest_script,
+        get_android_toolchain(ctx).android_resources_busybox,
+        _common.get_host_javabase(ctx),
+    )
+    res = feature_target[AndroidFeatureModuleInfo].library[StarlarkAndroidResourcesInfo]
+    binary = feature_target[AndroidFeatureModuleInfo].binary[ApkInfo].unsigned_apk
+    has_native_libs = bool(feature_target[AndroidFeatureModuleInfo].binary[AndroidIdeInfo].native_libs)
+
+    # Create res .proto-apk_, output depending on whether this split has native libs.
+    if has_native_libs:
+        res_apk = ctx.actions.declare_file(ctx.label.name + "/" + feature_target.label.name + "/res.proto-ap_")
+    else:
+        res_apk = out
+    _busybox.package(
+        ctx,
+        out_r_src_jar = ctx.actions.declare_file("R.srcjar", sibling = manifest),
+        out_r_txt = ctx.actions.declare_file("R.txt", sibling = manifest),
+        out_symbols = ctx.actions.declare_file("merged.bin", sibling = manifest),
+        out_manifest = ctx.actions.declare_file("AndroidManifest_processed.xml", sibling = manifest),
+        out_proguard_cfg = ctx.actions.declare_file("proguard.cfg", sibling = manifest),
+        out_main_dex_proguard_cfg = ctx.actions.declare_file(
+            "main_dex_proguard.cfg",
+            sibling = manifest,
+        ),
+        out_resource_files_zip = ctx.actions.declare_file("resource_files.zip", sibling = manifest),
+        out_file = res_apk,
+        manifest = manifest,
+        java_package = java_package,
+        direct_resources_nodes = res.direct_resources_nodes,
+        transitive_resources_nodes = res.transitive_resources_nodes,
+        transitive_manifests = [res.transitive_manifests],
+        transitive_assets = [res.transitive_assets],
+        transitive_compiled_assets = [res.transitive_compiled_assets],
+        transitive_resource_files = [res.transitive_resource_files],
+        transitive_compiled_resources = [res.transitive_compiled_resources],
+        transitive_r_txts = [res.transitive_r_txts],
+        additional_apks_to_link_against = [base_apk],
+        proto_format = True,  # required for aab.
+        android_jar = ctx.attr._android_sdk[AndroidSdkInfo].android_jar,
+        aapt = get_android_toolchain(ctx).aapt2.files_to_run,
+        busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run,
+        host_javabase = _common.get_host_javabase(ctx),
+        should_throw_on_conflict = True,
+        application_id = application_id,
+    )
+
+    if not has_native_libs:
+        return
+
+    # Extract libs/ from split binary
+    native_libs = ctx.actions.declare_file(ctx.label.name + "/" + feature_target.label.name + "/native_libs.zip")
+    _common.filter_zip(ctx, binary, native_libs, ["lib/*"])
+
+    # Extract AndroidManifest.xml and assets from res-ap_
+    filtered_res = ctx.actions.declare_file(ctx.label.name + "/" + feature_target.label.name + "/filtered_res.zip")
+    _common.filter_zip(ctx, res_apk, filtered_res, ["AndroidManifest.xml", "assets/*"])
+
+    # Merge into output
+    _java.singlejar(
+        ctx,
+        inputs = [filtered_res, native_libs],
+        output = out,
+        exclude_build_data = True,
+        java_toolchain = _common.get_java_toolchain(ctx),
+    )
+
+def _create_feature_manifest(
+        ctx,
+        base_apk,
+        java_package,
+        feature_target,
+        aapt2,
+        feature_manifest_script,
+        priority_feature_manifest_script,
+        android_resources_busybox,
+        host_javabase):
+    info = feature_target[AndroidFeatureModuleInfo]
+    manifest = ctx.actions.declare_file(ctx.label.name + "/" + feature_target.label.name + "/AndroidManifest.xml")
+
+    # Rule has not specified a manifest. Populate the default manifest template.
+    if not info.manifest:
+        args = ctx.actions.args()
+        args.add(manifest.path)
+        args.add(base_apk.path)
+        args.add(java_package)
+        args.add(info.feature_name)
+        args.add(info.title_id)
+        args.add(info.fused)
+        args.add(aapt2.executable)
+
+        ctx.actions.run(
+            executable = feature_manifest_script,
+            inputs = [base_apk],
+            outputs = [manifest],
+            arguments = [args],
+            tools = [
+                aapt2,
+            ],
+            mnemonic = "GenFeatureManifest",
+            progress_message = "Generating AndroidManifest.xml for " + feature_target.label.name,
+        )
+        return manifest
+
+    # Rule has a manifest (already validated by android_feature_module).
+    # Generate a priority manifest and then merge the user supplied manifest.
+    priority_manifest = ctx.actions.declare_file(
+        ctx.label.name + "/" + feature_target.label.name + "/Prioriy_AndroidManifest.xml",
+    )
+    args = ctx.actions.args()
+    args.add(priority_manifest.path)
+    args.add(base_apk.path)
+    args.add(java_package)
+    args.add(info.feature_name)
+    args.add(aapt2.executable)
+    ctx.actions.run(
+        executable = priority_feature_manifest_script,
+        inputs = [base_apk],
+        outputs = [priority_manifest],
+        arguments = [args],
+        tools = [
+            aapt2,
+        ],
+        mnemonic = "GenPriorityFeatureManifest",
+        progress_message = "Generating Priority AndroidManifest.xml for " + feature_target.label.name,
+    )
+
+    _busybox.merge_manifests(
+        ctx,
+        out_file = manifest,
+        manifest = priority_manifest,
+        mergee_manifests = depset([info.manifest]),
+        java_package = java_package,
+        busybox = android_resources_busybox.files_to_run,
+        host_javabase = host_javabase,
+        manifest_values = {"MODULE_TITLE": "@string/" + info.title_id},
+    )
+
+    return manifest
+
+def _impl(ctx):
+    # Convert base apk to .proto_ap_
+    base_apk = ctx.attr.base_module[ApkInfo].unsigned_apk
+    base_proto_apk = ctx.actions.declare_file(ctx.label.name + "/modules/base.proto-ap_")
+    _aapt.convert(
+        ctx,
+        out = base_proto_apk,
+        input = base_apk,
+        to_proto = True,
+        aapt = get_android_toolchain(ctx).aapt2.files_to_run,
+    )
+    proto_apks = [base_proto_apk]
+
+    # Convert each feature to .proto-ap_
+    for feature in ctx.attr.feature_modules:
+        feature_proto_apk = ctx.actions.declare_file(
+            "%s.proto-ap_" % feature.label.name,
+            sibling = base_proto_apk,
+        )
+        _process_feature_module(
+            ctx,
+            out = feature_proto_apk,
+            base_apk = base_apk,
+            feature_target = feature,
+            java_package = _java.resolve_package_from_label(ctx.label, ctx.attr.custom_package),
+            application_id = ctx.attr.application_id,
+        )
+        proto_apks.append(feature_proto_apk)
+
+    # Convert each each .proto-ap_ to module zip
+    modules = []
+    for proto_apk in proto_apks:
+        module = ctx.actions.declare_file(
+            proto_apk.basename + ".zip",
+            sibling = proto_apk,
+        )
+        modules.append(module)
+        _bundletool.proto_apk_to_module(
+            ctx,
+            out = module,
+            proto_apk = proto_apk,
+            unzip = get_android_toolchain(ctx).unzip_tool.files_to_run,
+            zip = get_android_toolchain(ctx).zip_tool.files_to_run,
+        )
+
+    metadata = dict()
+    if ProguardMappingInfo in ctx.attr.base_module:
+        metadata["com.android.tools.build.obfuscation/proguard.map"] = ctx.attr.base_module[ProguardMappingInfo].proguard_mapping
+
+    if ctx.file.rotation_config:
+        metadata["com.google.play.apps.signing/RotationConfig.textproto"] = ctx.file.rotation_config
+
+    if ctx.file.app_integrity_config:
+        metadata["com.google.play.apps.integrity/AppIntegrityConfig.pb"] = ctx.file.app_integrity_config
+
+    # Create .aab
+    _bundletool.build(
+        ctx,
+        out = ctx.outputs.unsigned_aab,
+        modules = modules,
+        config = ctx.file.bundle_config_file,
+        metadata = metadata,
+        bundletool = get_android_toolchain(ctx).bundletool.files_to_run,
+        host_javabase = _common.get_host_javabase(ctx),
+    )
+
+    # Create `blaze run` script
+    subs = {
+        "%bundletool_path%": get_android_toolchain(ctx).bundletool.files_to_run.executable.short_path,
+        "%aab%": ctx.outputs.unsigned_aab.short_path,
+        "%key%": ctx.attr.base_module[ApkInfo].signing_keys[0].short_path,
+    }
+    ctx.actions.expand_template(
+        template = ctx.file._bundle_deploy,
+        output = ctx.outputs.deploy_script,
+        substitutions = subs,
+        is_executable = True,
+    )
+
+    return [
+        ctx.attr.base_module[ApkInfo],
+        ctx.attr.base_module[AndroidPreDexJarInfo],
+        AndroidBundleInfo(unsigned_aab = ctx.outputs.unsigned_aab),
+        DefaultInfo(
+            executable = ctx.outputs.deploy_script,
+            runfiles = ctx.runfiles([
+                ctx.outputs.unsigned_aab,
+                ctx.attr.base_module[ApkInfo].signing_keys[0],
+                get_android_toolchain(ctx).bundletool.files_to_run.executable,
+            ]),
+        ),
+    ]
+
+android_application = rule(
+    attrs = ANDROID_APPLICATION_ATTRS,
+    fragments = [
+        "android",
+        "java",
+    ],
+    executable = True,
+    implementation = _impl,
+    outputs = {
+        "deploy_script": "%{name}.sh",
+        "unsigned_aab": "%{name}_unsigned.aab",
+    },
+    toolchains = ["@rules_android//toolchains/android:toolchain_type"],
+    _skylark_testable = True,
+)
+
+def android_application_macro(_android_binary, **attrs):
+    """android_application_macro.
+
+    Args:
+      _android_binary: The android_binary rule to use.
+      **attrs: android_application attributes.
+    """
+
+    fqn = "//%s:%s" % (native.package_name(), attrs["name"])
+
+    # Must pop these because android_binary does not have these attributes.
+    app_integrity_config = attrs.pop("app_integrity_config", default = None)
+    rotation_config = attrs.pop("rotation_config", default = None)
+
+    # Simply fall back to android_binary if no feature splits or bundle_config
+    if not attrs.get("feature_modules", None) and not (attrs.get("bundle_config", None) or attrs.get("bundle_config_file", None)):
+        _android_binary(**attrs)
+        return
+
+    _verify_attrs(attrs, fqn)
+
+    # Create an android_binary base split, plus an android_application to produce the aab
+    name = attrs.pop("name")
+    base_split_name = "%s_base" % name
+
+    # default to [] if feature_modules = None is passed
+    feature_modules = attrs.pop("feature_modules", default = []) or []
+    bundle_config = attrs.pop("bundle_config", default = None)
+    bundle_config_file = attrs.pop("bundle_config_file", default = None)
+
+    # bundle_config is deprecated in favor of bundle_config_file
+    # In the future bundle_config will accept a build rule rather than a raw file.
+    bundle_config_file = bundle_config_file or bundle_config
+
+    for feature_module in feature_modules:
+        if not feature_module.startswith("//") or ":" not in feature_module:
+            _log.error("feature_modules expects fully qualified paths, i.e. //some/path:target")
+        module_targets = get_feature_module_paths(feature_module)
+        attrs["deps"].append(str(module_targets.title_lib))
+
+    _android_binary(
+        name = base_split_name,
+        **attrs
+    )
+
+    android_application(
+        name = name,
+        base_module = ":%s" % base_split_name,
+        bundle_config_file = bundle_config_file,
+        app_integrity_config = app_integrity_config,
+        rotation_config = rotation_config,
+        custom_package = attrs.get("custom_package", None),
+        testonly = attrs.get("testonly"),
+        transitive_configs = attrs.get("transitive_configs", []),
+        feature_modules = feature_modules,
+        application_id = attrs["manifest_values"]["applicationId"],
+    )
diff --git a/rules/android_application/android_feature_module.bzl b/rules/android_application/android_feature_module.bzl
new file mode 100644
index 0000000..840d961
--- /dev/null
+++ b/rules/android_application/android_feature_module.bzl
@@ -0,0 +1,58 @@
+# Copyright 2021 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.
+
+"""android_feature_module rule.
+
+This file exists to inject the correct version of android_binary and android_library.
+"""
+
+load(
+    ":android_feature_module_rule.bzl",
+    _android_feature_module_macro = "android_feature_module_macro",
+)
+load(
+    "@rules_android//rules:android_binary.bzl",
+    _android_binary = "android_binary",
+)
+load(
+    "@rules_android//rules/android_library:rule.bzl",
+    _android_library_macro = "android_library_macro",
+)
+
+def android_feature_module(**attrs):
+    """Macro to declare a Dynamic Feature Module.
+
+    Generates the following:
+
+    * strings.xml containing a unique split identifier (currently a hash of the fully qualified target label)
+    * dummy AndroidManifest.xml for the split
+    * `android_library` to create the split resources
+    * `android_feature_module` rule to be consumed by `android_application`
+
+    **Attributes**
+
+    Name | Description
+    --- | ---
+    name | Required string, split name
+    custom_package | Optional string, custom package for this split
+    manifest | Required label, the AndroidManifest.xml to use for this module.
+    library | Required label, the `android_library` contained in this split. Must only contain assets.
+    title | Required string, the split title
+    feature_flags | Optional dict, pass through feature_flags dict for native split binary.
+    """
+    _android_feature_module_macro(
+        _android_binary = _android_binary,
+        _android_library = _android_library_macro,
+        **attrs
+    )
diff --git a/rules/android_application/android_feature_module_rule.bzl b/rules/android_application/android_feature_module_rule.bzl
new file mode 100644
index 0000000..87c57b5
--- /dev/null
+++ b/rules/android_application/android_feature_module_rule.bzl
@@ -0,0 +1,196 @@
+# Copyright 2021 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.
+
+"""android_feature_module rule."""
+
+load(":attrs.bzl", "ANDROID_FEATURE_MODULE_ATTRS")
+load("@rules_android//rules:java.bzl", _java = "java")
+load(
+    "@rules_android//rules:providers.bzl",
+    "AndroidFeatureModuleInfo",
+)
+load("@rules_android//rules:acls.bzl", "acls")
+load(
+    "@rules_android//rules:utils.bzl",
+    "get_android_toolchain",
+)
+
+def _impl(ctx):
+    validation = ctx.actions.declare_file(ctx.label.name + "_validation")
+    inputs = [ctx.attr.binary[ApkInfo].unsigned_apk]
+    args = ctx.actions.args()
+    args.add(validation.path)
+    if ctx.file.manifest:
+        args.add(ctx.file.manifest.path)
+        inputs.append(ctx.file.manifest)
+    else:
+        args.add("")
+    args.add(ctx.attr.binary[ApkInfo].unsigned_apk.path)
+    args.add(ctx.configuration.coverage_enabled)
+    args.add(ctx.fragments.android.desugar_java8_libs)
+    args.add(ctx.attr.library.label)
+    args.add(get_android_toolchain(ctx).xmllint_tool.files_to_run.executable)
+    args.add(get_android_toolchain(ctx).unzip_tool.files_to_run.executable)
+
+    ctx.actions.run(
+        executable = ctx.executable._feature_module_validation_script,
+        inputs = inputs,
+        outputs = [validation],
+        arguments = [args],
+        tools = [
+            get_android_toolchain(ctx).xmllint_tool.files_to_run.executable,
+            get_android_toolchain(ctx).unzip_tool.files_to_run.executable,
+        ],
+        mnemonic = "ValidateFeatureModule",
+        progress_message = "Validating feature module %s" % str(ctx.label),
+    )
+
+    return [
+        AndroidFeatureModuleInfo(
+            binary = ctx.attr.binary,
+            library = ctx.attr.library,
+            title_id = ctx.attr.title_id,
+            title_lib = ctx.attr.title_lib,
+            feature_name = ctx.attr.feature_name,
+            fused = ctx.attr.fused,
+            manifest = ctx.file.manifest,
+        ),
+        OutputGroupInfo(_validation = depset([validation])),
+    ]
+
+android_feature_module = rule(
+    attrs = ANDROID_FEATURE_MODULE_ATTRS,
+    fragments = [
+        "android",
+        "java",
+    ],
+    implementation = _impl,
+    provides = [AndroidFeatureModuleInfo],
+    toolchains = ["@rules_android//toolchains/android:toolchain_type"],
+    _skylark_testable = True,
+)
+
+def get_feature_module_paths(fqn):
+    # Given a fqn to an android_feature_module, returns the absolute paths to
+    # all implicitly generated targets
+    return struct(
+        binary = Label("%s_bin" % fqn),
+        manifest_lib = Label("%s_AndroidManifest" % fqn),
+        title_strings_xml = Label("%s_title_strings_xml" % fqn),
+        title_lib = Label("%s_title_lib" % fqn),
+    )
+
+def android_feature_module_macro(_android_binary, _android_library, **attrs):
+    """android_feature_module_macro.
+
+    Args:
+      _android_binary: The android_binary rule to use.
+      _android_library: The android_library rule to use.
+      **attrs: android_feature_module attributes.
+    """
+
+    # Enable dot syntax
+    attrs = struct(**attrs)
+    fqn = "//%s:%s" % (native.package_name(), attrs.name)
+
+    required_attrs = ["name", "library", "title"]
+    if not acls.in_android_feature_splits_dogfood(fqn):
+        required_attrs.append("manifest")
+
+    # Check for required macro attributes
+    for attr in required_attrs:
+        if not getattr(attrs, attr, None):
+            fail("%s missing required attr <%s>" % (fqn, attr))
+
+    if hasattr(attrs, "fused") and hasattr(attrs, "manifest"):
+        fail("%s cannot specify <fused> and <manifest>. Prefer <manifest>")
+
+    targets = get_feature_module_paths(fqn)
+
+    tags = getattr(attrs, "tags", [])
+    transitive_configs = getattr(attrs, "transitive_configs", [])
+    visibility = getattr(attrs, "visibility", None)
+
+    # Create strings.xml containing split title
+    title_id = "split_" + str(hash(fqn)).replace("-", "N")
+    native.genrule(
+        name = targets.title_strings_xml.name,
+        outs = [attrs.name + "/res/values/strings.xml"],
+        cmd = """cat > $@ <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"
+xmlns:tools="http://schemas.android.com/tools"
+tools:keep="@string/{title_id}">
+    <string name="{title_id}">{title}</string>
+</resources>
+EOF
+""".format(title = attrs.title, title_id = title_id),
+    )
+
+    # Create AndroidManifest.xml
+    min_sdk_version = getattr(attrs, "min_sdk_version", "14") or "14"
+    package = _java.resolve_package_from_label(Label(fqn), getattr(attrs, "custom_package", None))
+    native.genrule(
+        name = targets.manifest_lib.name,
+        outs = [attrs.name + "/AndroidManifest.xml"],
+        cmd = """cat > $@ <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="{package}">
+    <uses-sdk
+      android:minSdkVersion="{min_sdk_version}"/>
+</manifest>
+EOF
+""".format(package = package, min_sdk_version = min_sdk_version),
+    )
+
+    # Resource processing requires an android_library target
+    _android_library(
+        name = targets.title_lib.name,
+        custom_package = getattr(attrs, "custom_package", None),
+        manifest = str(targets.manifest_lib),
+        resource_files = [str(targets.title_strings_xml)],
+        tags = tags,
+        transitive_configs = transitive_configs,
+        visibility = visibility,
+    )
+
+    # Wrap any deps in an android_binary. Will be validated to ensure does not contain any dexes
+    binary_attrs = {
+        "name": targets.binary.name,
+        "custom_package": getattr(attrs, "custom_package", None),
+        "manifest": str(targets.manifest_lib),
+        "deps": [attrs.library],
+        "multidex": "native",
+        "tags": tags,
+        "transitive_configs": transitive_configs,
+        "visibility": visibility,
+        "feature_flags": getattr(attrs, "feature_flags", None),
+        "$enable_manifest_merging": False,
+    }
+    _android_binary(**binary_attrs)
+
+    android_feature_module(
+        name = attrs.name,
+        library = attrs.library,
+        binary = str(targets.binary),
+        title_id = title_id,
+        title_lib = str(targets.title_lib),
+        feature_name = getattr(attrs, "feature_name", attrs.name),
+        fused = getattr(attrs, "fused", True),
+        manifest = getattr(attrs, "manifest", None),
+        tags = tags,
+        transitive_configs = transitive_configs,
+        visibility = visibility,
+    )
diff --git a/rules/android_application/attrs.bzl b/rules/android_application/attrs.bzl
new file mode 100644
index 0000000..33e43fb
--- /dev/null
+++ b/rules/android_application/attrs.bzl
@@ -0,0 +1,89 @@
+# Copyright 2021 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.
+
+"""Attributes for android_application."""
+
+load(
+    "@rules_android//rules:attrs.bzl",
+    _attrs = "attrs",
+)
+
+ANDROID_APPLICATION_ATTRS = _attrs.add(
+    dict(
+        application_id = attr.string(),
+        base_module = attr.label(allow_files = False),
+        bundle_config_file = attr.label(
+            allow_single_file = [".pb.json"],
+            doc = ("Path to config.pb.json file, see " +
+                   "https://github.com/google/bundletool/blob/master/src/main/proto/config.proto " +
+                   "for definition.\n\nNote: this attribute is subject to changes which may " +
+                   "require teams to migrate their configurations to a build target."),
+        ),
+        app_integrity_config = attr.label(
+            allow_single_file = [".binarypb"],
+            doc = "Configuration of the integrity protection options. " +
+                  "Provide a path to a binary .binarypb instance of " +
+                  "https://github.com/google/bundletool/blob/master/src/main/proto/app_integrity_config.proto",
+        ),
+        rotation_config = attr.label(
+            allow_single_file = [".textproto"],
+            default = None,
+        ),
+        custom_package = attr.string(),
+        feature_modules = attr.label_list(allow_files = False),
+        _bundle_deploy = attr.label(
+            allow_single_file = True,
+            default = ":bundle_deploy.sh_template",
+        ),
+        _feature_manifest_script = attr.label(
+            allow_single_file = True,
+            cfg = "host",
+            executable = True,
+            default = ":gen_android_feature_manifest.sh",
+        ),
+        _java_toolchain = attr.label(
+            default = Label("//tools/jdk:toolchain_android_only"),
+        ),
+        _priority_feature_manifest_script = attr.label(
+            allow_single_file = True,
+            cfg = "host",
+            executable = True,
+            default = ":gen_priority_android_feature_manifest.sh",
+        ),
+        _host_javabase = attr.label(
+            cfg = "host",
+            default = Label("//tools/jdk:current_java_runtime"),
+        ),
+    ),
+    _attrs.ANDROID_SDK,
+)
+
+ANDROID_FEATURE_MODULE_ATTRS = dict(
+    binary = attr.label(),
+    feature_name = attr.string(),
+    library = attr.label(
+        allow_rules = ["android_library"],
+        mandatory = True,
+        doc = "android_library target to include as a feature split.",
+    ),
+    manifest = attr.label(allow_single_file = True),
+    title_id = attr.string(),
+    title_lib = attr.string(),
+    _feature_module_validation_script = attr.label(
+        allow_single_file = True,
+        cfg = "host",
+        executable = True,
+        default = ":feature_module_validation.sh",
+    ),
+)
diff --git a/rules/android_application/bundle_deploy.sh_template b/rules/android_application/bundle_deploy.sh_template
new file mode 100644
index 0000000..37f6d4d
--- /dev/null
+++ b/rules/android_application/bundle_deploy.sh_template
@@ -0,0 +1,26 @@
+#!/bin/bash --posix
+
+bundletool="%bundletool_path%"
+aab="%aab%"
+key="%key%"
+tmp="$(mktemp /tmp/XXXXbundle.apks)"
+
+function cleanup {
+  rm  -r "$tmp"
+}
+trap cleanup EXIT
+
+java -jar "$bundletool" build-apks \
+  --bundle="$aab" \
+  --output="$tmp" \
+  --overwrite \
+  --local-testing \
+  --ks="$key" \
+  --ks-pass=pass:android \
+  --ks-key-alias=androiddebugkey \
+  --key-pass=pass:android || exit
+
+java -jar "$bundletool" install-apks \
+  --adb="$(which adb)" \
+  --apks "$tmp" \
+  --modules=_ALL_ || exit
diff --git a/rules/android_application/feature_module_validation.sh b/rules/android_application/feature_module_validation.sh
new file mode 100644
index 0000000..405b77d
--- /dev/null
+++ b/rules/android_application/feature_module_validation.sh
@@ -0,0 +1,78 @@
+#!/bin/bash --posix
+# Copyright 2021 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.
+
+out="${1}"
+manifest="${2}"
+apk="${3}"
+is_coverage="${4}"
+is_java8="${5}"
+lib_label="${6}"
+xmllint="${7}"
+unzip="${8}"
+
+if [[ -n "$manifest" ]]; then
+  node_count=$("$xmllint" --xpath "count(//manifest/*)" "$manifest")
+  module_count=$("$xmllint" --xpath "count(//manifest/*[local-name()='module'])" "$manifest")
+  application_count=$("$xmllint" --xpath "count(//manifest/*[local-name()='application'])" "$manifest")
+  application_attr_count=$("$xmllint" --xpath "count(//manifest/application/@*)" "$manifest")
+  application_content_count=$("$xmllint" --xpath "count(//manifest/application/*)" "$manifest")
+  module_title=$("$xmllint" --xpath "string(//manifest/*[local-name()='module'][1]/@*[local-name()='title'])" "$manifest")
+  valid=0
+
+  # Valid manifest, containing a dist:module and an empty <application/>
+  if [[ "$node_count" == "2" &&
+  "$module_count" == "1" &&
+  "$application_count" == "1" &&
+  "$application_attr_count" == "0" &&
+  "$application_content_count" == "0" ]]; then
+    valid=1
+  fi
+
+  # Valid manifest, containing a dist:module
+  if [[ "$node_count" == "1" && "$module_count" == "1" ]]; then
+    valid=1
+  fi
+
+  if [[ "$valid" == "0" ]]; then
+    echo ""
+    echo "$manifest should only contain a single <dist:module /> element (and optional empty <application/>), nothing else"
+    echo "Manifest contents: "
+    cat "$manifest"
+    exit 1
+  fi
+
+  if [[ "$module_title" != "\${MODULE_TITLE}" ]]; then
+    echo ""
+    echo "$manifest dist:title should be \${MODULE_TITLE} placeholder"
+    echo ""
+    exit 1
+  fi
+fi
+
+# Skip dex validation when running under code coverage.
+# When running under code coverage an additional dep is implicitly added to all
+# binary targets, causing a validation failure.
+if [[ "$is_coverage" == "false" ]]; then
+  dexes=$("$unzip" -l "$apk" | grep ".dex" | wc -l)
+  if [[ ("$is_java8" == "true" && "$dexes" -gt 1 ) || ( "$is_java8" == "false" && "$dexes" -gt 0)]]; then
+    echo ""
+    echo "android_feature_module does not support Java or Kotlin sources."
+    echo "Check $lib_label for any srcs or deps."
+    echo ""
+    exit 1
+  fi
+fi
+
+touch "$out"
diff --git a/rules/android_application/gen_android_feature_manifest.sh b/rules/android_application/gen_android_feature_manifest.sh
new file mode 100644
index 0000000..5b5552e
--- /dev/null
+++ b/rules/android_application/gen_android_feature_manifest.sh
@@ -0,0 +1,51 @@
+#!/bin/bash --posix
+# Copyright 2021 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.
+
+out_manifest="${1}"
+base_apk="${2}"
+package="${3}"
+split="${4}"
+title_id="${5}"
+fused="${6}"
+aapt="${7}"
+
+aapt_cmd="$aapt dump xmltree $base_apk --file AndroidManifest.xml"
+version_code=$(${aapt_cmd} | grep "http://schemas.android.com/apk/res/android:versionCode" | cut -d "=" -f2 | head -n 1 )
+if [[ -z "$version_code" ]]
+then
+  echo "Base app missing versionCode in AndroidManifest.xml"
+  exit 1
+fi
+
+cat >$out_manifest <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:dist="http://schemas.android.com/apk/distribution"
+    package="$package"
+    split="$split"
+    android:versionCode="$version_code"
+    android:isFeatureSplit="true">
+
+  <dist:module
+      dist:instant="false"
+      dist:title="@string/$title_id"> <!-- title must be an ID! Needs to work with proguard/resource shrinking -->
+    <dist:fusing dist:include="$fused" />
+    <dist:delivery>
+      <dist:on-demand /></dist:delivery>
+  </dist:module>
+
+  <application android:hasCode="false" /> <!-- currently only supports asset splits -->
+</manifest>
+EOF
diff --git a/rules/android_application/gen_priority_android_feature_manifest.sh b/rules/android_application/gen_priority_android_feature_manifest.sh
new file mode 100644
index 0000000..cf646c8
--- /dev/null
+++ b/rules/android_application/gen_priority_android_feature_manifest.sh
@@ -0,0 +1,49 @@
+#!/bin/bash --posix
+# Copyright 2021 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.
+
+out_manifest="${1}"
+base_apk="${2}"
+package="${3}"
+split="${4}"
+aapt="${5}"
+
+aapt_cmd="$aapt dump xmltree $base_apk --file AndroidManifest.xml"
+version_code=$(${aapt_cmd} | grep "http://schemas.android.com/apk/res/android:versionCode" | cut -d "=" -f2 | head -n 1)
+min_sdk=$(${aapt_cmd} | grep "http://schemas.android.com/apk/res/android:minSdkVersion" | cut -d "=" -f2 | head -n 1)
+if [[ -z "$version_code" ]]
+then
+  echo "Base app missing versionCode in AndroidManifest.xml"
+  exit 1
+fi
+
+if [[ -z "$min_sdk" ]]
+then
+  echo "Base app missing minsdk in AndroidManifest.xml"
+  exit 1
+fi
+
+cat >$out_manifest <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:dist="http://schemas.android.com/apk/distribution"
+    package="$package"
+    split="$split"
+    android:versionCode="$version_code"
+    android:isFeatureSplit="true">
+
+  <application android:hasCode="false" /> <!-- currently only supports asset splits -->
+  <uses-sdk android:minSdkVersion="$min_sdk" />
+</manifest>
+EOF
diff --git a/rules/android_binary.bzl b/rules/android_binary.bzl
index 1760e75..5d33512 100644
--- a/rules/android_binary.bzl
+++ b/rules/android_binary.bzl
@@ -15,7 +15,7 @@
 """Bazel rule for building an APK."""
 
 load(":migration_tag_DONOTUSE.bzl", "add_migration_tag")
-load("@rules_android//rules/android_packaged_resources:rule.bzl", "android_packaged_resources_macro")
+load("@rules_android//rules/android_binary_internal:rule.bzl", "android_binary_internal_macro")
 
 def android_binary(**attrs):
     """Bazel android_binary rule.
@@ -25,11 +25,11 @@
     Args:
       **attrs: Rule attributes
     """
-    packaged_resources_name = ":%s_RESOURCES_DO_NOT_USE" % attrs["name"]
-    android_packaged_resources_macro(
+    android_binary_internal_name = ":%s_RESOURCES_DO_NOT_USE" % attrs["name"]
+    android_binary_internal_macro(
         **dict(
             attrs,
-            name = packaged_resources_name[1:],
+            name = android_binary_internal_name[1:],
             visibility = ["//visibility:private"],
         )
     )
@@ -37,6 +37,6 @@
     attrs.pop("$enable_manifest_merging", None)
 
     native.android_binary(
-        application_resources = packaged_resources_name,
+        application_resources = android_binary_internal_name,
         **add_migration_tag(attrs)
     )
diff --git a/rules/android_packaged_resources/BUILD b/rules/android_binary_internal/BUILD
similarity index 61%
rename from rules/android_packaged_resources/BUILD
rename to rules/android_binary_internal/BUILD
index f858689..2440016 100644
--- a/rules/android_packaged_resources/BUILD
+++ b/rules/android_binary_internal/BUILD
@@ -1,16 +1,9 @@
-# Starlark Resource Packaging for Android Rules.
+# The android_binary_internal rule.
 
 load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
 
-package(
-    default_visibility =
-        ["//third_party/bazel_rules/rules_android"],
-)
-
 licenses(["notice"])
 
-exports_files(["rule.bzl"])
-
 filegroup(
     name = "all_files",
     srcs = glob(["**"]),
diff --git a/rules/android_packaged_resources/attrs.bzl b/rules/android_binary_internal/attrs.bzl
similarity index 100%
rename from rules/android_packaged_resources/attrs.bzl
rename to rules/android_binary_internal/attrs.bzl
diff --git a/rules/android_packaged_resources/impl.bzl b/rules/android_binary_internal/impl.bzl
similarity index 98%
rename from rules/android_packaged_resources/impl.bzl
rename to rules/android_binary_internal/impl.bzl
index e3d6ac0..6838a81 100644
--- a/rules/android_packaged_resources/impl.bzl
+++ b/rules/android_binary_internal/impl.bzl
@@ -44,7 +44,7 @@
         should_throw_on_conflict = not acls.in_allow_resource_conflicts(str(ctx.label)),
         enable_data_binding = ctx.attr.enable_data_binding,
         enable_manifest_merging = ctx.attr._enable_manifest_merging,
-        deps = ctx.attr.deps,
+        deps = utils.dedupe_split_attr(ctx.split_attr.deps),
         instruments = ctx.attr.instruments,
         aapt = get_android_toolchain(ctx).aapt2.files_to_run,
         android_jar = ctx.attr._android_sdk[AndroidSdkInfo].android_jar,
diff --git a/rules/android_packaged_resources/rule.bzl b/rules/android_binary_internal/rule.bzl
similarity index 83%
rename from rules/android_packaged_resources/rule.bzl
rename to rules/android_binary_internal/rule.bzl
index db3f96a..3070688 100644
--- a/rules/android_packaged_resources/rule.bzl
+++ b/rules/android_binary_internal/rule.bzl
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Starlark Resource Packaging for Android Rules."""
+"""Starlark Android Binary for Android Rules."""
 
 load(":attrs.bzl", "ATTRS")
 load(":impl.bzl", "impl")
@@ -25,7 +25,6 @@
 
 _DEFAULT_PROVIDES = [AndroidApplicationResourceInfo, OutputGroupInfo]
 
-# TODO(b/167721629): Rename android_packaged_resources to android_binary_internal.
 def make_rule(
         attrs = ATTRS,
         implementation = impl,
@@ -52,17 +51,17 @@
         ],
     )
 
-_android_packaged_resources = make_rule()
+android_binary_internal = make_rule()
 
 def sanitize_attrs(attrs, allowed_attrs = ATTRS.keys()):
     """Sanitizes the attributes.
 
-    The android_packaged_resources has a subset of the android_binary attributes, but is
+    The android_binary_internal has a subset of the android_binary attributes, but is
     called from the android_binary macro with the same full set of attributes. This removes
     any unnecessary attributes.
 
     Args:
-      attrs: A dict. The attributes for the android_packaged_resources rule.
+      attrs: A dict. The attributes for the android_binary_internal rule.
       allowed_attrs: The list of attribute keys to keep.
 
     Returns:
@@ -82,10 +81,10 @@
 
     return attrs
 
-def android_packaged_resources_macro(**attrs):
-    """android_packaged_resources rule.
+def android_binary_internal_macro(**attrs):
+    """android_binary_internal rule.
 
     Args:
       **attrs: Rule attributes
     """
-    _android_packaged_resources(**sanitize_attrs(attrs))
+    android_binary_internal(**sanitize_attrs(attrs))
diff --git a/rules/android_library/attrs.bzl b/rules/android_library/attrs.bzl
index 16a18e7..b71b466 100644
--- a/rules/android_library/attrs.bzl
+++ b/rules/android_library/attrs.bzl
@@ -29,8 +29,8 @@
         ),
         enable_data_binding = attr.bool(default = False),
         exported_plugins = attr.label_list(
-            allow_rules = [
-                "java_plugin",
+            providers = [
+                [JavaPluginInfo],
             ],
             cfg = "host",
         ),
@@ -59,7 +59,6 @@
         _defined_idl_srcs = attr.bool(default = False),
         _defined_local_resources = attr.bool(default = False),
         _java_toolchain = attr.label(
-            cfg = "host",
             default = Label("//tools/jdk:toolchain_android_only"),
         ),
         # TODO(str): Remove when fully migrated to android_instrumentation_test
diff --git a/rules/android_library/impl.bzl b/rules/android_library/impl.bzl
index 232899c..cd7e2c0 100644
--- a/rules/android_library/impl.bzl
+++ b/rules/android_library/impl.bzl
@@ -151,7 +151,7 @@
         # misbehavior on the Java side.
         fix_resource_transitivity = bool(ctx.attr.srcs),
         fix_export_exporting = acls.in_fix_export_exporting_rollout(str(ctx.label)),
-        android_test_migration = ctx.attr._android_test_migration,
+        propagate_resources = not ctx.attr._android_test_migration,
 
         # Tool and Processing related inputs
         aapt = get_android_toolchain(ctx).aapt2.files_to_run,
@@ -211,6 +211,7 @@
             defines_resources = resources_ctx.defines_resources,
             enable_data_binding = ctx.attr.enable_data_binding,
             java_package = java_package,
+            layout_info = resources_ctx.data_binding_layout_info,
             deps = utils.collect_providers(DataBindingV2Info, ctx.attr.deps),
             exports = utils.collect_providers(DataBindingV2Info, ctx.attr.exports),
             data_binding_exec = get_android_toolchain(ctx).data_binding_exec.files_to_run,
@@ -252,11 +253,11 @@
             utils.collect_providers(JavaInfo, ctx.attr.deps, idl_ctx.idl_deps),
         exports = utils.collect_providers(JavaInfo, ctx.attr.exports),
         plugins = (
-            utils.collect_providers(JavaInfo, ctx.attr.plugins) +
+            utils.collect_providers(JavaPluginInfo, ctx.attr.plugins) +
             db_ctx.java_plugins
         ),
         exported_plugins = utils.collect_providers(
-            JavaInfo,
+            JavaPluginInfo,
             ctx.attr.exported_plugins,
         ),
         annotation_processor_additional_outputs = (
@@ -339,9 +340,9 @@
                 AndroidCcLinkParamsInfo(
                     cc_common.merge_cc_infos(
                         cc_infos = [
-                                       info.cc_info
+                                       info.cc_link_params_info
                                        for info in utils.collect_providers(
-                                           JavaCcLinkParamsInfo,
+                                           JavaInfo,
                                            ctx.attr.deps,
                                            ctx.attr.exports,
                                            idl_ctx.idl_deps,
@@ -431,11 +432,9 @@
         android = _intellij.make_legacy_android_provider(intellij_ctx.android_ide_info),
         java = struct(
             annotation_processing = jvm_ctx.java_info.annotation_processing,
-            compilation_info = jvm_ctx.java_info.compilation_info,
             outputs = jvm_ctx.java_info.outputs,
             source_jars = depset(jvm_ctx.java_info.source_jars),
             transitive_deps = jvm_ctx.java_info.transitive_compile_time_jars,
-            transitive_exports = jvm_ctx.java_info.transitive_exports,
             transitive_runtime_deps = jvm_ctx.java_info.transitive_runtime_jars,
             transitive_source_jars = jvm_ctx.java_info.transitive_source_jars,
         ),
@@ -500,6 +499,7 @@
                 [ctx.outputs.lib_src_jar],
                 transitive = [jvm_ctx.java_info.transitive_source_jars],
             ),
+            _direct_source_jars = depset([ctx.outputs.lib_src_jar]),
             _hidden_top_level_INTERNAL_ = depset(
                 resources_ctx.validation_results,
                 transitive = [
diff --git a/rules/android_sdk.bzl b/rules/android_sdk.bzl
index cf824e1..e5e1fa7 100644
--- a/rules/android_sdk.bzl
+++ b/rules/android_sdk.bzl
@@ -39,6 +39,7 @@
         # Passing the 'system' here is only necessary to support native android_binary.
         # TODO(b/149114743): remove this after the migration to android_application.
         ctx.attr._system[java_common.BootClassPathInfo] if ctx.attr._system and java_common.BootClassPathInfo in ctx.attr._system else None,
+        ctx.attr.legacy_main_dex_list_generator.files_to_run if ctx.attr.legacy_main_dex_list_generator else None,
     )
     return [
         android_sdk_info,
diff --git a/rules/attrs.bzl b/rules/attrs.bzl
index eca1947..af389ff 100644
--- a/rules/attrs.bzl
+++ b/rules/attrs.bzl
@@ -79,7 +79,7 @@
 _JAVA_RUNTIME = dict(
     _host_javabase = attr.label(
         cfg = "host",
-        default = Label("@rules_android//rules:current_java_runtime"),
+        default = Label("@rules_android//tools/jdk:current_java_runtime"),
     ),
 )
 
@@ -115,7 +115,7 @@
             allow_files = True,
         ),
         plugins = attr.label_list(
-            allow_rules = ["java_plugin"],
+            providers = [JavaPluginInfo],
             cfg = "host",
         ),
         javacopts = attr.string_list(),
@@ -228,6 +228,11 @@
         cfg = "host",
         mandatory = True,
     ),
+    legacy_main_dex_list_generator = attr.label(
+        allow_files = True,
+        cfg = "host",
+        executable = True,
+    ),
     main_dex_classes = attr.label(
         allow_single_file = True,
         cfg = "host",
@@ -248,7 +253,6 @@
     shrinked_android_jar = attr.label(
         allow_single_file = True,
         cfg = "host",
-        mandatory = True,
     ),
     source_properties = attr.label(
         allow_single_file = True,
diff --git a/rules/bundletool.bzl b/rules/bundletool.bzl
new file mode 100644
index 0000000..07f5217
--- /dev/null
+++ b/rules/bundletool.bzl
@@ -0,0 +1,190 @@
+# Copyright 2020 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.
+
+"""Bazel Bundletool Commands."""
+
+load(":java.bzl", _java = "java")
+
+def _proto_apk_to_module(
+        ctx,
+        out = None,
+        proto_apk = None,
+        zip = None,
+        unzip = None):
+    # TODO(timpeut): rewrite this as a standalone golang tool
+    ctx.actions.run_shell(
+        command = """
+set -e
+
+IN_DIR=$(mktemp -d)
+OUT_DIR=$(mktemp -d)
+CUR_PWD=$(pwd)
+UNZIP=%s
+ZIP=%s
+INPUT=%s
+OUTPUT=%s
+
+"${UNZIP}" -qq "${INPUT}" -d "${IN_DIR}"
+cd "${IN_DIR}"
+
+if [ -f resources.pb ]; then
+  mv resources.pb "${OUT_DIR}/"
+fi
+
+if [ -f AndroidManifest.xml ]; then
+  mkdir "${OUT_DIR}/manifest"
+  mv AndroidManifest.xml "${OUT_DIR}/manifest/"
+fi
+
+NUM_DEX=`ls -1 *.dex 2>/dev/null | wc -l`
+if [ $NUM_DEX != 0 ]; then
+  mkdir "${OUT_DIR}/dex"
+  mv *.dex "${OUT_DIR}/dex/"
+fi
+
+if [ -d res ]; then
+  mv res "${OUT_DIR}/res"
+fi
+
+if [ -d assets ]; then
+  mv assets "${OUT_DIR}/"
+fi
+
+if [ -d lib ]; then
+  mv lib "${OUT_DIR}/"
+fi
+
+UNKNOWN=`ls -1 * 2>/dev/null | wc -l`
+if [ $UNKNOWN != 0 ]; then
+  mkdir "${OUT_DIR}/root"
+  mv * "${OUT_DIR}/root/"
+fi
+
+cd "${OUT_DIR}"
+"${CUR_PWD}/${ZIP}" "${CUR_PWD}/${OUTPUT}" -Drqq .
+""" % (
+            unzip.executable.path,
+            zip.executable.path,
+            proto_apk.path,
+            out.path,
+        ),
+        tools = [zip, unzip],
+        arguments = [],
+        inputs = [proto_apk],
+        outputs = [out],
+        mnemonic = "Rebundle",
+        progress_message = "Rebundle to %s" % out.short_path,
+    )
+
+def _build(
+        ctx,
+        out = None,
+        modules = [],
+        config = None,
+        metadata = dict(),
+        bundletool = None,
+        host_javabase = None):
+    args = ctx.actions.args()
+    args.add("build-bundle")
+    args.add("--output", out)
+    if modules:
+        args.add_joined("--modules", modules, join_with = ",")
+    if config:
+        args.add("--config", config)
+    for path, f in metadata.items():
+        args.add("--metadata-file", "%s:%s" % (path, f.path))
+
+    _java.run(
+        ctx = ctx,
+        host_javabase = host_javabase,
+        executable = bundletool,
+        arguments = [args],
+        inputs = (
+            modules +
+            ([config] if config else []) +
+            metadata.values()
+        ),
+        outputs = [out],
+        mnemonic = "BuildBundle",
+        progress_message = "Building bundle %s" % out.short_path,
+    )
+
+def _extract_config(
+        ctx,
+        out = None,
+        aab = None,
+        bundletool = None,
+        host_javabase = None):
+    # Need to execute as a shell script as the tool outputs to stdout
+    cmd = """
+set -e
+contents=`%s -jar %s dump config --bundle %s`
+echo "$contents" > %s
+""" % (
+        host_javabase[java_common.JavaRuntimeInfo].java_executable_exec_path,
+        bundletool.executable.path,
+        aab.path,
+        out.path,
+    )
+
+    ctx.actions.run_shell(
+        inputs = [aab],
+        outputs = [out],
+        tools = depset([bundletool.executable], transitive = [host_javabase[java_common.JavaRuntimeInfo].files]),
+        mnemonic = "ExtractBundleConfig",
+        progress_message = "Extract bundle config to %s" % out.short_path,
+        command = cmd,
+    )
+
+def _extract_manifest(
+        ctx,
+        out = None,
+        aab = None,
+        module = None,
+        xpath = None,
+        bundletool = None,
+        host_javabase = None):
+    # Need to execute as a shell script as the tool outputs to stdout
+    extra_flags = []
+    if module:
+        extra_flags.append("--module " + module)
+    if xpath:
+        extra_flags.append("--xpath " + xpath)
+    cmd = """
+set -e
+contents=`%s -jar %s dump manifest --bundle %s %s`
+echo "$contents" > %s
+""" % (
+        host_javabase[java_common.JavaRuntimeInfo].java_executable_exec_path,
+        bundletool.executable.path,
+        aab.path,
+        " ".join(extra_flags),
+        out.path,
+    )
+
+    ctx.actions.run_shell(
+        inputs = [aab],
+        outputs = [out],
+        tools = depset([bundletool.executable], transitive = [host_javabase[java_common.JavaRuntimeInfo].files]),
+        mnemonic = "ExtractBundleManifest",
+        progress_message = "Extract bundle manifest to %s" % out.short_path,
+        command = cmd,
+    )
+
+bundletool = struct(
+    build = _build,
+    extract_config = _extract_config,
+    extract_manifest = _extract_manifest,
+    proto_apk_to_module = _proto_apk_to_module,
+)
diff --git a/rules/data_binding.bzl b/rules/data_binding.bzl
index 39923ec..70df90f 100644
--- a/rules/data_binding.bzl
+++ b/rules/data_binding.bzl
@@ -54,8 +54,7 @@
     _utils.copy_file(ctx, annotation_template, annotation_out)
     return annotation_out
 
-def _gen_sources(ctx, output_dir, java_package, deps, data_binding_exec):
-    layout_info = ctx.actions.declare_file(output_dir + "layout-info.zip")
+def _gen_sources(ctx, output_dir, java_package, deps, layout_info, data_binding_exec):
     class_info = ctx.actions.declare_file(output_dir + "class-info.zip")
     srcjar = ctx.actions.declare_file(output_dir + "baseClassSrc.srcjar")
 
@@ -82,7 +81,7 @@
             "GenerateDataBindingBaseClasses %s" % class_info.short_path
         ),
     )
-    return srcjar, class_info, layout_info
+    return srcjar, class_info
 
 def _setup_dependent_lib_artifacts(ctx, output_dir, deps):
     # DataBinding requires files in very specific locations.
@@ -157,6 +156,7 @@
         defines_resources = False,
         enable_data_binding = False,
         java_package = None,
+        layout_info = None,
         deps = [],
         exports = [],
         data_binding_exec = None,
@@ -174,6 +174,7 @@
       deps: sequence of DataBindingV2Info providers. A list of deps. Optional.
       exports: sequence of DataBindingV2Info providers. A list of exports.
         Optional.
+      layout_info: A file. The layout-info zip file.
       data_binding_exec: The DataBinding executable.
       data_binding_annotation_processor: JavaInfo. The JavaInfo for the
         annotation processor.
@@ -219,7 +220,6 @@
     br_out = None
     setter_store_out = None
     class_info = None
-    layout_info = None
     if defines_resources:
         # Outputs of the Data Binding annotation processor.
         br_out = ctx.actions.declare_file(
@@ -233,11 +233,12 @@
             setter_store_out,
         )
 
-        srcjar, class_info, layout_info = _gen_sources(
+        srcjar, class_info = _gen_sources(
             ctx,
             output_dir,
             java_package,
             deps,
+            layout_info,
             data_binding_exec,
         )
         db_info[_JAVA_SRCS].append(srcjar)
diff --git a/rules/flags/flag_defs.bzl b/rules/flags/flag_defs.bzl
index cecb40a..7b9a8d8 100644
--- a/rules/flags/flag_defs.bzl
+++ b/rules/flags/flag_defs.bzl
@@ -86,6 +86,7 @@
         description = "",
     )
 
+
     flags.EXPOSE_native_bool(
         name = "stamp",
         description = "Accesses the native --stamp CLI flag",
diff --git a/rules/java.bzl b/rules/java.bzl
index 7b23b35..42470f0 100644
--- a/rules/java.bzl
+++ b/rules/java.bzl
@@ -14,6 +14,7 @@
 
 """Bazel Java APIs for the Android rules."""
 
+load(":acls.bzl", "acls")
 load(":path.bzl", _path = "path")
 load(":utils.bzl", "log")
 
@@ -168,6 +169,29 @@
         (not custom_package and _check_for_invalid_java_package(java_package))
     )
 
+def _set_default_applicationid(fqn, attrs):
+    """Sets the manifest value applicationId to the package.
+
+    If applicationId is missing from the manifest_values, set it
+    to the package as a default value to avoid using library packages
+    when merging manifests.
+    """
+    if not acls.in_fix_application_id(fqn):
+        return attrs
+    new_attrs = {}
+    new_attrs.update(attrs)
+    package_string = _resolve_package_from_label(Label(fqn), None)
+
+    # TODO(timpeut): handle select()s
+    mv_attr = attrs.get("manifest_values", None) or {}
+    if type(mv_attr) == "dict" and "applicationId" not in mv_attr:
+        manifest_values = {}
+        manifest_values.update(mv_attr)
+        manifest_values.update({"__INTERNAL_PKG_DO_NOT_USE__": package_string})
+        new_attrs["manifest_values"] = manifest_values
+
+    return new_attrs
+
 # The Android specific Java compile.
 def _compile_android(
         ctx,
@@ -219,7 +243,6 @@
         see https://docs.bazel.build/versions/master/user-manual.html#flag--strict_java_deps.
         By default 'ERROR'.
       java_toolchain: The java_toolchain Target.
-      host_javabase: The host_javabase Target.
 
     Returns:
       A JavaInfo provider representing the Java compilation.
@@ -321,7 +344,6 @@
         see https://docs.bazel.build/versions/master/user-manual.html#flag--strict_java_deps.
         By default 'ERROR'.
       java_toolchain: The java_toolchain Target.
-      host_javabase: The host_javabase Target.
 
     Returns:
       A JavaInfo provider representing the Java compilation.
@@ -385,7 +407,7 @@
         args.add_all(inputs)
 
     ctx.actions.run(
-        executable = java_toolchain.java_toolchain.single_jar,
+        executable = java_toolchain[java_common.JavaToolchainInfo].single_jar,
         arguments = [args],
         inputs = inputs,
         outputs = [output],
@@ -396,12 +418,14 @@
 def _run(
         ctx,
         host_javabase,
+        jvm_flags = [],
         **args):
     """Run a java binary
 
     Args:
       ctx: The context.
       host_javabase: Target. The host_javabase.
+      jvm_flags: Additional arguments to the JVM itself.
       **args: Additional arguments to pass to ctx.actions.run(). Some will get modified.
     """
 
@@ -411,6 +435,10 @@
     if type(host_javabase) != "Target":
         fail("Expected type Target for argument host_javabase, got %s" % type(host_javabase))
 
+    # Set reasonable max heap default. Required to prevent runaway memory usage.
+    # Can still be overridden by callers of this method.
+    jvm_flags = ["-Xmx4G", "-XX:+ExitOnOutOfMemoryError"] + jvm_flags
+
     # executable should be a File or a FilesToRunProvider
     jar = args.get("executable")
     if type(jar) == "FilesToRunProvider":
@@ -431,7 +459,7 @@
     jar_args = ctx.actions.args()
     jar_args.add("-jar", jar)
 
-    args["arguments"] = [jar_args] + args.get("arguments", default = [])
+    args["arguments"] = jvm_flags + [jar_args] + args.get("arguments", default = [])
 
     ctx.actions.run(**args)
 
@@ -441,6 +469,7 @@
     resolve_package = _resolve_package,
     resolve_package_from_label = _resolve_package_from_label,
     root = _root,
+    set_default_applicationid = _set_default_applicationid,
     invalid_java_package = _invalid_java_package,
     run = _run,
     singlejar = _singlejar,
diff --git a/rules/platforms/BUILD b/rules/platforms/BUILD
deleted file mode 100644
index 778c849..0000000
--- a/rules/platforms/BUILD
+++ /dev/null
@@ -1,33 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-platform(
-	name = "armeabi_v7a",
-	constraint_values = [
-		"@platforms//cpu:armv7",
-		"@platforms//os:android",
-	],
-)
-
-platform(
-	name = "arm64-v8a",
-	constraint_values = [
-		"@platforms//cpu:arm64",
-		"@platforms//os:android",
-	],
-)
-
-platform(
-	name = "x86",
-	constraint_values = [
-		"@platforms//cpu:x86_32",
-		"@platforms//os:android",
-	],
-)
-
-platform(
-	name = "x86_64",
-	constraint_values = [
-		"@platforms//cpu:x86_64",
-		"@platforms//os:android",
-	],
-)
diff --git a/rules/providers.bzl b/rules/providers.bzl
index fd92708..e7db209 100644
--- a/rules/providers.bzl
+++ b/rules/providers.bzl
@@ -92,6 +92,7 @@
         transitive_manifests = "Depset of transitive manifests",
         transitive_r_txts = "Depset of transitive R.txt files",
         transitive_resource_files = "Depset of transitive resource files",
+        packages_to_r_txts = "Map of packages to depset of r_txt files",
     ),
 )
 
@@ -102,8 +103,38 @@
     ),
 )
 
+AndroidFeatureModuleInfo = provider(
+    doc = "Contains data required to build an Android feature split.",
+    fields = dict(
+        binary = "String, target of the underlying split android_binary target",
+        feature_name = "String, the name of the feature module. If unspecified, the target name will be used.",
+        fused = "Boolean, whether the split is \"fused\" for the system image and for pre-L devices.",
+        library = "String, target of the underlying split android_library target",
+        manifest = "Optional AndroidManifest.xml file to use for this feature.",
+        min_sdk_version = "String, the min SDK version for this feature.",
+        title_id = "String, resource identifier for the split title.",
+        title_lib = "String, target of the split title android_library.",
+    ),
+)
 
 
+Dex2OatApkInfo = provider(
+    doc = "Contains data about artifacts generated through host dex2oat.",
+    fields = dict(
+        signed_apk = "Signed APK",
+        oat_file = "Oat file generated through dex2oat.",
+        vdex_file = "Vdex file generated through dex2oat.",
+        art_file = "ART file generated through dex2oat.",
+    ),
+)
+
+InstrumentedAppInfo = provider(
+    doc = "Contains data about an android_binary's instrumented android_binary.",
+    fields = dict(
+        android_ide_info = "AndroidIdeInfo provider from the instrumented android_binary.",
+    ),
+)
+
 FailureInfo = provider(
     fields = dict(
         error = "Error message",
diff --git a/rules/resources.bzl b/rules/resources.bzl
index 386196d..9bebb87 100644
--- a/rules/resources.bzl
+++ b/rules/resources.bzl
@@ -76,6 +76,7 @@
 
 # Resources context attributes.
 _ASSETS_PROVIDER = "assets_provider"
+_DATA_BINDING_LAYOUT_INFO = "data_binding_layout_info"
 _DEFINES_RESOURCES = "defines_resources"
 _DIRECT_ANDROID_RESOURCES = "direct_android_resources"
 _MERGED_MANIFEST = "merged_manifest"
@@ -97,6 +98,7 @@
         _MERGED_MANIFEST: "Merged manifest.",
         _PROVIDERS: "The list of all providers to propagate.",
         _R_JAVA: "JavaInfo for R.jar.",
+        _DATA_BINDING_LAYOUT_INFO: "Databinding layout info file.",
         _RESOURCES_APK: "ResourcesApk.",
         _VALIDATION_RESULTS: "List of validation results.",
         _VALIDATION_OUTPUTS: "List of outputs given to OutputGroupInfo _validation group",
@@ -125,6 +127,7 @@
         _PACKAGED_CLASS_JAR: "R class jar.",
         _PACKAGED_VALIDATION_RESULT: "Validation result.",
         _R_JAVA: "JavaInfo for R.jar",
+        _DATA_BINDING_LAYOUT_INFO: "Databinding layout info file.",
         _PROVIDERS: "The list of all providers to propagate.",
     },
 )
@@ -490,9 +493,6 @@
     """
     _validate_resources(resource_files)
 
-    # Filtering is necessary if a build is requested with multiple CPU configurations.
-    deps = _filter_multi_cpu_configuration_targets(deps)
-
     packaged_resources_ctx = {
         _PROVIDERS: [],
     }
@@ -520,6 +520,7 @@
     transitive_compiled_resources = []
     transitive_manifests = []
     transitive_r_txts = []
+    packages_to_r_txts_depset = dict()
     for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, deps):
         direct_resources_nodes.append(dep.direct_resources_nodes)
         transitive_resources_nodes.append(dep.transitive_resources_nodes)
@@ -530,6 +531,8 @@
         transitive_compiled_resources.append(dep.transitive_compiled_resources)
         transitive_manifests.append(dep.transitive_manifests)
         transitive_r_txts.append(dep.transitive_r_txts)
+        for pkg, r_txts in dep.packages_to_r_txts.items():
+            packages_to_r_txts_depset.setdefault(pkg, []).append(r_txts)
 
     mergee_manifests = depset([
         node_info.manifest
@@ -574,16 +577,16 @@
             )
 
     processed_resources = resource_files
-    databinding_info = None
+    data_binding_layout_info = None
     if enable_data_binding:
-        databinding_info = ctx.actions.declare_file("_migrated/databinding/" + ctx.label.name + "/layout-info.zip")
+        data_binding_layout_info = ctx.actions.declare_file("_migrated/databinding/" + ctx.label.name + "/layout-info.zip")
         processed_resources, resources_dirname = _make_databinding_outputs(
             ctx,
             resource_files,
         )
         _busybox.process_databinding(
             ctx,
-            out_databinding_info = databinding_info,
+            out_databinding_info = data_binding_layout_info,
             out_databinding_processed_resources = processed_resources,
             databinding_resources_dirname = resources_dirname,
             resource_files = resource_files,
@@ -688,6 +691,29 @@
     )
 
     packaged_resources_ctx[_R_JAVA] = java_info
+    packaged_resources_ctx[_DATA_BINDING_LAYOUT_INFO] = data_binding_layout_info
+
+    packages_to_r_txts_depset.setdefault(java_package, []).append(depset([r_txt]))
+
+    packages_to_r_txts = dict()
+    for pkg, depsets in packages_to_r_txts_depset.items():
+        packages_to_r_txts[pkg] = depset(transitive = depsets)
+
+    # Adding empty depsets to unused fields of StarlarkAndroidResourcesInfo.
+    # Some root targets may depends on other root targets and try to access those fields.
+    packaged_resources_ctx[_PROVIDERS].append(StarlarkAndroidResourcesInfo(
+        direct_resources_nodes = depset(),
+        transitive_resources_nodes = depset(),
+        transitive_assets = depset(),
+        transitive_assets_symbols = depset(),
+        transitive_compiled_assets = depset(),
+        transitive_resource_files = depset(),
+        direct_compiled_resources = depset(),
+        transitive_compiled_resources = depset(),
+        transitive_manifests = depset(),
+        transitive_r_txts = depset(),
+        packages_to_r_txts = packages_to_r_txts,
+    ))
 
     packaged_resources_ctx[_PROVIDERS].append(AndroidApplicationResourceInfo(
         resource_apk = resource_apk,
@@ -698,7 +724,7 @@
         main_dex_proguard_config = main_dex_proguard_cfg,
         r_txt = r_txt,
         resources_zip = resource_files_zip,
-        databinding_info = databinding_info,
+        databinding_info = data_binding_layout_info,
     ))
     return _ResourcesPackageContextInfo(**packaged_resources_ctx)
 
@@ -955,7 +981,7 @@
         resource_files = None,
         neverlink = False,
         enable_data_binding = False,
-        android_test_migration = False,
+        propagate_resources = True,
         fix_resource_transitivity = False,
         aapt = None,
         android_jar = None,
@@ -1002,9 +1028,9 @@
         expressions in layout resources included through the resource_files
         parameter is enabled. Without this setting, data binding expressions
         produce build failures.
-      android_test_migration: boolean. If true, the target is part of the android
-      test to android instrumentation test migration and should not propagate
-      any Android Resource providers.
+      propagate_resources: boolean. If false, the target will no longer propagate
+        providers required for Android Resource processing/packaging. But will
+        continue to propagate others (AndroidLibraryResourceClassJarProvider).
       fix_resource_transitivity: Whether to ensure that transitive resources are
         correctly marked as transitive.
       aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
@@ -1056,6 +1082,7 @@
         _VALIDATION_RESULTS: [],
         _DEFINES_RESOURCES: defines_resources,
         _R_JAVA: None,
+        _DATA_BINDING_LAYOUT_INFO: None,
         _MERGED_MANIFEST: None,
         _STARLARK_PROCESSED_MANIFEST: None,
         _STARLARK_R_TXT: None,
@@ -1078,6 +1105,7 @@
     transitive_resources_files = []
     transitive_manifests = []
     transitive_r_txts = []
+    packages_to_r_txts_depset = dict()
 
     for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, deps):
         direct_resources_nodes.append(dep.direct_resources_nodes)
@@ -1090,6 +1118,8 @@
         transitive_resources_files.append(dep.transitive_resource_files)
         transitive_manifests.append(dep.transitive_manifests)
         transitive_r_txts.append(dep.transitive_r_txts)
+        for pkg, r_txts in dep.packages_to_r_txts.items():
+            packages_to_r_txts_depset.setdefault(pkg, []).append(r_txts)
 
     exports_direct_resources_nodes = []
     exports_transitive_resources_nodes = []
@@ -1112,6 +1142,8 @@
         exports_transitive_resources_files.append(dep.transitive_resource_files)
         exports_transitive_manifests.append(dep.transitive_manifests)
         exports_transitive_r_txts.append(dep.transitive_r_txts)
+        for pkg, r_txts in dep.packages_to_r_txts.items():
+            packages_to_r_txts_depset.setdefault(pkg, []).append(r_txts)
 
     # TODO(b/144134042): Don't merge exports; exports are not deps.
     direct_resources_nodes.extend(exports_direct_resources_nodes)
@@ -1130,6 +1162,7 @@
     compiled_resources = None
     out_aapt2_r_txt = None
     r_txt = None
+    data_binding_layout_info = None
     processed_resources = resource_files
     processed_manifest = None
     if not defines_resources:
@@ -1140,8 +1173,9 @@
             )
             _generate_dummy_manifest(
                 ctx,
-                generated_manifest,
-                java_package if java_package else ctx.label.package.replace("/", "."),
+                out_manifest = generated_manifest,
+                java_package = java_package if java_package else ctx.label.package.replace("/", "."),
+                min_sdk_version = 14,
             )
             r_txt = ctx.actions.declare_file(
                 "_migrated/" + ctx.label.name + "_symbols/R.txt",
@@ -1261,7 +1295,7 @@
             )
 
         if enable_data_binding:
-            out_databinding_info = ctx.actions.declare_file(
+            data_binding_layout_info = ctx.actions.declare_file(
                 "_migrated/databinding/" + ctx.label.name + "/layout-info.zip",
             )
             processed_resources, resources_dirname = _make_databinding_outputs(
@@ -1270,7 +1304,7 @@
             )
             _busybox.process_databinding(
                 ctx,
-                out_databinding_info = out_databinding_info,
+                out_databinding_info = data_binding_layout_info,
                 out_databinding_processed_resources = processed_resources,
                 databinding_resources_dirname = resources_dirname,
                 resource_files = resource_files,
@@ -1375,7 +1409,10 @@
             source_jar = r_java,
         )
 
+        packages_to_r_txts_depset.setdefault(java_package, []).append(depset([out_aapt2_r_txt]))
+
         resources_ctx[_R_JAVA] = java_info
+        resources_ctx[_DATA_BINDING_LAYOUT_INFO] = data_binding_layout_info
 
         # In a normal build, the outputs of _busybox.validate_and_link are unused. However we need
         # this action to run to support resource visibility checks.
@@ -1406,6 +1443,10 @@
         # inputs are missing, we implicitly export deps here. This legacy behavior must exist in the
         # Starlark resource processing pipeline until we can clean up the depot.
 
+    packages_to_r_txts = dict()
+    for pkg, depsets in packages_to_r_txts_depset.items():
+        packages_to_r_txts[pkg] = depset(transitive = depsets)
+
     # TODO(b/159916013): Audit neverlink behavior. Some processing can likely be skipped if the target is neverlink.
     # TODO(b/69668042): Don't propagate exported providers/artifacts. Exports should respect neverlink.
     if resources_neverlink:
@@ -1452,6 +1493,7 @@
                 transitive = exports_transitive_r_txts,
                 order = "preorder",
             ),
+            packages_to_r_txts = packages_to_r_txts,
         ))
     else:
         # Depsets are ordered below to match the order in the legacy native rules.
@@ -1516,10 +1558,10 @@
                 transitive = transitive_r_txts + exports_transitive_r_txts,
                 order = "preorder",
             ),
+            packages_to_r_txts = packages_to_r_txts,
         ))
 
-    # Do not collect resources and R.java for test apk
-    if android_test_migration:
+    if not propagate_resources:
         resources_ctx[_R_JAVA] = None
         resources_ctx[_PROVIDERS] = []
 
@@ -1574,7 +1616,7 @@
         res_v3_dummy_r_txt = None,
         fix_resource_transitivity = False,
         fix_export_exporting = False,
-        android_test_migration = False,
+        propagate_resources = True,
         zip_tool = None):
     out_ctx = _process_starlark(
         ctx,
@@ -1596,7 +1638,7 @@
         enable_data_binding = enable_data_binding,
         fix_resource_transitivity = fix_resource_transitivity,
         neverlink = neverlink,
-        android_test_migration = android_test_migration,
+        propagate_resources = propagate_resources,
         android_jar = android_jar,
         aapt = aapt,
         android_kit = android_kit,
diff --git a/rules/rules.bzl b/rules/rules.bzl
index e849d72..2a0a585 100644
--- a/rules/rules.bzl
+++ b/rules/rules.bzl
@@ -18,44 +18,18 @@
     "//rules/aar_import:rule.bzl",
     _aar_import = "aar_import",
 )
-
-#load(
-#    ":apk_import.bzl",
-#    _apk_import = "apk_import",
-#)
-
+load(
+    "//rules/android_application:android_application.bzl",
+     _android_application = "android_application"
+)
 load(
     ":android_binary.bzl",
     _android_binary = "android_binary",
 )
-
-# load(
-#     ":android_device.bzl",
-#     _android_device = "android_device",
-# )
-# load(
-#     ":android_device_script_fixture.bzl",
-#     _android_device_script_fixture = "android_device_script_fixture",
-# )
-# load(
-#     ":android_host_service_fixture.bzl",
-#     _android_host_service_fixture = "android_host_service_fixture",
-# )
-# load(
-#     ":android_instrumentation_test.bzl",
-#     _android_instrumentation_test = "android_instrumentation_test",
-# )
-
 load(
     "//rules/android_library:rule.bzl",
     _android_library = "android_library_macro",
 )
-
-# load(
-#     ":android_local_test.bzl",
-#     _android_local_test = "android_local_test",
-# )
-
 load(
     ":android_ndk_repository.bzl",
     _android_ndk_repository = "android_ndk_repository",
@@ -77,53 +51,10 @@
 RULES_ANDROID_VERSION = "0.1.0"
 
 aar_import = _aar_import
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_apk_to_bundle"""
-
+android_application = _android_application
 android_binary = _android_binary
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_binary"""
-
-#android_device = _android_device
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_device"""
-
-#android_device_script_fixture = _android_device_script_fixture
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_host_service_fixture"""
-
-#android_host_service_fixture = _android_host_service_fixture
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_device_script_fixture"""
-
-#android_instrumentation_test = _android_instrumentation_test
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_instrumentation_test"""
-
 android_library = _android_library
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_library"""
-
-#android_local_test = _android_local_test
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_local_test"""
-
 android_ndk_repository = _android_ndk_repository
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_ndk_repository"""
-
 android_sdk = _android_sdk
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_sdk"""
-
 android_sdk_repository = _android_sdk_repository
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_sdk_repository"""
-
 android_tools_defaults_jar = _android_tools_defaults_jar
-
-"""https://docs.bazel.build/versions/master/be/android.html#android_tools_defaults_jar"""
-
-#apk_import = _apk_import
-#
-#"""https://docs.bazel.build/versions/master/be/android.html#apk_import"""
diff --git a/rules/toolchains/emulator/BUILD b/rules/toolchains/emulator/BUILD
deleted file mode 100644
index a02375a..0000000
--- a/rules/toolchains/emulator/BUILD
+++ /dev/null
@@ -1,27 +0,0 @@
-# Description:
-#   Defines an emulator toolchain so that the emulator used for android_device
-#   can be configured at build-time.
-
-load(":toolchain.bzl", "emulator_toolchain")
-
-package(default_visibility = ["//visibility:public"])
-
-# By convention, toolchain_type targets are named "toolchain_type"
-# and distinguished by their package path.
-toolchain_type(
-    name = "toolchain_type",
-)
-
-emulator_toolchain(
-    name = "emulator_default",
-    emulator = "@androidsdk//:emulator",
-    emulator_deps = [
-        "@androidsdk//:emulator_shared_libs",
-    ],
-)
-
-toolchain(
-    name = "emulator_default_toolchain",
-    toolchain = ":emulator_default",
-    toolchain_type = ":toolchain_type",
-)
diff --git a/rules/utils.bzl b/rules/utils.bzl
index 76a0fd2..5bd764e 100644
--- a/rules/utils.bzl
+++ b/rules/utils.bzl
@@ -278,6 +278,12 @@
         res[k] = _expand_var(ctx.var, v)
     return res
 
+def _dedupe_split_attr(attr):
+    if not attr:
+        return []
+    arch = _first(sorted(attr.keys()))
+    return attr[arch]
+
 def _get_runfiles(ctx, attrs):
     runfiles = ctx.runfiles()
     for attr in attrs:
@@ -430,6 +436,7 @@
     copy_dir = _copy_dir,
     expand_make_vars = _expand_make_vars,
     first = _first,
+    dedupe_split_attr = _dedupe_split_attr,
     get_runfiles = _get_runfiles,
     join_depsets = _join_depsets,
     only = _only,
diff --git a/src/validations/aar_import_checks/BUILD b/src/validations/aar_import_checks/BUILD
new file mode 100644
index 0000000..eb11bcf
--- /dev/null
+++ b/src/validations/aar_import_checks/BUILD
@@ -0,0 +1,26 @@
+# Description:
+#   Package for aar_import validation checks
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+genrule(
+    name = "gen_aar_import_checks",
+    outs = ["aar_import_checks"],
+    executable = True,
+    cmd = """
+cat > $@ <<EOF
+#!/bin/bash
+while [[ $$# -gt 0 ]]
+do
+case $$1 in
+    -output)
+    out="$$2"
+    shift # past argument
+    shift # past value
+    ;;
+esac
+done
+touch $$out
+EOF
+""")
diff --git a/toolchains/android/toolchain.bzl b/toolchains/android/toolchain.bzl
index b356447..a63fe63 100644
--- a/toolchains/android/toolchain.bzl
+++ b/toolchains/android/toolchain.bzl
@@ -19,12 +19,24 @@
         allow_files = True,
         default = "@androidsdk//:aapt2_binary",
     ),
+    aar_import_checks = attr.label(
+        allow_single_file = True,
+        cfg = "host",
+        default = "//src/validations/aar_import_checks",
+        executable = True,
+    ),
     aar_embedded_jars_extractor = attr.label(
         allow_files = True,
         cfg = "host",
         default = "@bazel_tools//tools/android:aar_embedded_jars_extractor",
         executable = True,
     ),
+    aar_embedded_proguard_extractor = attr.label(
+        allow_files = True,
+        cfg = "host",
+        default = "@bazel_tools//tools/android:aar_embedded_proguard_extractor",
+        executable = True,
+    ),
     aar_native_libs_zip_creator = attr.label(
         allow_files = True,
         cfg = "host",
@@ -48,6 +60,24 @@
         default = Label("//tools/android/xslt:add_g3itr.xslt"),
         allow_files = True,
     ),
+    android_archive_jar_optimization_inputs_validator = attr.label(
+        allow_files = True,
+        default = "@androidsdk//:fail",
+        cfg = "host",
+        executable = True,
+    ),
+    android_archive_manifest_package_validator = attr.label(
+        allow_files = True,
+        default = "@androidsdk//:fail",
+        cfg = "host",
+        executable = True,
+    ),
+    android_archive_packages_validator = attr.label(
+        allow_files = True,
+        default = "@androidsdk//:fail",
+        cfg = "host",
+        executable = True,
+    ),
     android_kit = attr.label(
         allow_files = True,
         cfg = "host",
@@ -69,7 +99,7 @@
     bundletool = attr.label(
         allow_files = True,
         cfg = "host",
-        default = "@androidsdk//:fail",
+        default = "//tools/android:bundletool_deploy.jar",
         executable = True,
     ),
     data_binding_annotation_processor = attr.label(
@@ -123,6 +153,12 @@
         default = "@bazel_tools//tools/jdk:proguard_whitelister",
         executable = True,
     ),
+    proto_map_generator = attr.label(
+        cfg = "host",
+        default = "@androidsdk//:fail",
+        allow_files = True,
+        executable = True,
+    ),
     res_v3_dummy_manifest = attr.label(
         allow_files = True,
         default = "//rules:res_v3_dummy_AndroidManifest.xml",
diff --git a/tools/android/BUILD b/tools/android/BUILD
index 7c33f67..61ee16c 100644
--- a/tools/android/BUILD
+++ b/tools/android/BUILD
@@ -23,3 +23,10 @@
   name = "fail",
   srcs =[":fail.sh"],
 )
+
+java_binary(
+    name = "bundletool",
+    main_class = "com.android.tools.build.bundletool.BundleToolMain",
+    runtime_deps = ["@rules_android_maven//:com_android_tools_build_bundletool"],
+    visibility = ["//visibility:public"],
+)
diff --git a/tools/jdk/BUILD b/tools/jdk/BUILD
index c688d1a..d83484b 100644
--- a/tools/jdk/BUILD
+++ b/tools/jdk/BUILD
@@ -9,3 +9,9 @@
     ],
     visibility = ["//visibility:public"],
 )
+
+alias(
+    name = "current_java_runtime",
+    actual = "@bazel_tools//tools/jdk:current_java_runtime",
+    visibility = ["//visibility:public"],
+)