From 5c8bdd44193894594fa01fd527c5cf3af17e7652 Mon Sep 17 00:00:00 2001 From: ahumesky Date: Fri, 4 Jun 2021 19:00:08 -0400 Subject: Initial publication of android_application rule and related changes. --- BUILD | 0 CODEOWNERS | 1 - ROADMAP.md | 71 ---- defs.bzl | 36 ++ rules/BUILD | 6 - rules/aapt.bzl | 200 +++++++++++ rules/aar_import/impl.bzl | 76 ++-- rules/aar_import/rule.bzl | 7 +- rules/acls.bzl | 45 +-- rules/acls/aar_import_exports_r_java.bzl | 2 +- rules/acls/aar_import_package_check.bzl | 21 -- .../android_archive_excluded_deps_denylist.bzl | 21 ++ rules/acls/android_build_stamping_rollout.bzl | 3 +- rules/acls/android_feature_splits_dogfood.bzl | 7 +- rules/acls/android_lint_checks_rollout.bzl | 22 ++ rules/acls/android_lint_rollout.bzl | 2 + rules/acls/use_classic_desugar.bzl | 18 + rules/android_application/BUILD | 27 ++ rules/android_application/android_application.bzl | 51 +++ .../android_application_rule.bzl | 385 +++++++++++++++++++++ .../android_application/android_feature_module.bzl | 58 ++++ .../android_feature_module_rule.bzl | 196 +++++++++++ rules/android_application/attrs.bzl | 89 +++++ .../android_application/bundle_deploy.sh_template | 26 ++ .../feature_module_validation.sh | 78 +++++ .../gen_android_feature_manifest.sh | 51 +++ .../gen_priority_android_feature_manifest.sh | 49 +++ rules/android_binary.bzl | 10 +- rules/android_binary_internal/BUILD | 18 + rules/android_binary_internal/attrs.bzl | 69 ++++ rules/android_binary_internal/impl.bzl | 111 ++++++ rules/android_binary_internal/rule.bzl | 90 +++++ rules/android_library/attrs.bzl | 5 +- rules/android_library/impl.bzl | 14 +- rules/android_packaged_resources/BUILD | 25 -- rules/android_packaged_resources/attrs.bzl | 69 ---- rules/android_packaged_resources/impl.bzl | 111 ------ rules/android_packaged_resources/rule.bzl | 91 ----- rules/android_sdk.bzl | 1 + rules/attrs.bzl | 10 +- rules/bundletool.bzl | 190 ++++++++++ rules/data_binding.bzl | 11 +- rules/flags/flag_defs.bzl | 1 + rules/java.bzl | 37 +- rules/platforms/BUILD | 33 -- rules/providers.bzl | 31 ++ rules/resources.bzl | 80 ++++- rules/rules.bzl | 79 +---- rules/toolchains/emulator/BUILD | 27 -- rules/utils.bzl | 7 + src/validations/aar_import_checks/BUILD | 26 ++ toolchains/android/toolchain.bzl | 38 +- tools/android/BUILD | 7 + tools/jdk/BUILD | 6 + 54 files changed, 2114 insertions(+), 631 deletions(-) create mode 100644 BUILD delete mode 100644 CODEOWNERS delete mode 100644 ROADMAP.md create mode 100644 defs.bzl create mode 100644 rules/aapt.bzl delete mode 100644 rules/acls/aar_import_package_check.bzl create mode 100644 rules/acls/android_archive_excluded_deps_denylist.bzl create mode 100644 rules/acls/android_lint_checks_rollout.bzl create mode 100644 rules/acls/use_classic_desugar.bzl create mode 100644 rules/android_application/BUILD create mode 100644 rules/android_application/android_application.bzl create mode 100644 rules/android_application/android_application_rule.bzl create mode 100644 rules/android_application/android_feature_module.bzl create mode 100644 rules/android_application/android_feature_module_rule.bzl create mode 100644 rules/android_application/attrs.bzl create mode 100644 rules/android_application/bundle_deploy.sh_template create mode 100644 rules/android_application/feature_module_validation.sh create mode 100644 rules/android_application/gen_android_feature_manifest.sh create mode 100644 rules/android_application/gen_priority_android_feature_manifest.sh create mode 100644 rules/android_binary_internal/BUILD create mode 100644 rules/android_binary_internal/attrs.bzl create mode 100644 rules/android_binary_internal/impl.bzl create mode 100644 rules/android_binary_internal/rule.bzl delete mode 100644 rules/android_packaged_resources/BUILD delete mode 100644 rules/android_packaged_resources/attrs.bzl delete mode 100644 rules/android_packaged_resources/impl.bzl delete mode 100644 rules/android_packaged_resources/rule.bzl create mode 100644 rules/bundletool.bzl delete mode 100644 rules/platforms/BUILD delete mode 100644 rules/toolchains/emulator/BUILD create mode 100644 src/validations/aar_import_checks/BUILD diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..e69de29 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 @@ alias( 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 @@ _UNEXPECTED_LINT_JAR_ERROR = ( "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 _extract_native_libs( def _process_resources( ctx, aar, + package, manifest, deps, aar_resources_extractor_tool, @@ -139,6 +144,7 @@ def _process_resources( 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 @@ def _process_resources( 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]) - - if not _acls.in_aar_propagate_resources(str(ctx.label)): - resources_ctx["providers"] = [] + 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 = """ + + +""" % package) + return struct(**resources_ctx) @@ -355,19 +353,16 @@ def _process_jars( 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 @@ def _validate_rule( 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 @@ def _process_lint_rules( )) 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 @@ def impl(ctx): 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 @@ def impl(ctx): resources_ctx = _process_resources( ctx, aar = aar, + package = package, manifest = android_manifest, deps = ctx.attr.deps, aar_resources_extractor_tool = @@ -495,6 +513,15 @@ def impl(ctx): ), ) + # 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 @@ def impl(ctx): 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 @@ aar_import = rule( 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 @@ To update a list: 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:install_apps_in_data.bzl", "INSTALL_APPS_IN_DAT 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_explicit_exports_manifest(fqn): 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_ait_virtual_device(fqn): 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_instrumentation_binary_starlark_resources(fqn): 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_rollout(fqn): 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_FALLBACK_DICT = _make_dict(AAR_IMPORT_DEPS_CHECKER_FALLB 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_DICT = _make_dict(ANDROID_LIBRARY_IMPLICIT_EXPO 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_FALLBACK_DICT = _make_dict(LOCAL_TEST_FALLBACK) 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_ROLLOUT_DICT = _make_dict(KT_ANDROID_LIBRARY_ROLLOUT) 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 @@ def _matches(fqn, dct): 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 @@ acls = struct( 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 @@ acls = struct( 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 @@ acls = struct( 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/aar_import_package_check.bzl deleted file mode 100644 index 54b2b51..0000000 --- a/rules/acls/aar_import_package_check.bzl +++ /dev/null @@ -1,21 +0,0 @@ -# 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. - -"""Allow list for checking the package value with the manifest.""" -AAR_IMPORT_PKG_CHECK_ROLLOUT = [ - "//:__subpackages__", -] - -AAR_IMPORT_PKG_CHECK_FALLBACK = [ -] diff --git a/rules/acls/android_archive_excluded_deps_denylist.bzl b/rules/acls/android_archive_excluded_deps_denylist.bzl new file mode 100644 index 0000000..2a46e68 --- /dev/null +++ b/rules/acls/android_archive_excluded_deps_denylist.bzl @@ -0,0 +1,21 @@ +# 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. + +"""Denylist for rules that are not allowed in android_archive excluded_deps.""" + +# 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 @@ ANDROID_BUILD_STAMPING_ROLLOUT = [ ] # 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/android_lint_checks_rollout.bzl b/rules/acls/android_lint_checks_rollout.bzl new file mode 100644 index 0000000..ee44280 --- /dev/null +++ b/rules/acls/android_lint_checks_rollout.bzl @@ -0,0 +1,22 @@ +# 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. + +"""Allow list for enabling Android Lint checks in the Android Rules.""" + +# keep sorted +ANDROID_LINT_CHECKS_ROLLOUT = [ +] + +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/use_classic_desugar.bzl b/rules/acls/use_classic_desugar.bzl new file mode 100644 index 0000000..37110c4 --- /dev/null +++ b/rules/acls/use_classic_desugar.bzl @@ -0,0 +1,18 @@ +# 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. + +"""List of targets that require classic desugar.""" + +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 and . Prefer ") + + 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 > $@ < + + {title} + +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 +""".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 + 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 element (and optional empty ), 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 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 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 @@ def android_binary(**attrs): 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 @@ def android_binary(**attrs): 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_binary_internal/BUILD b/rules/android_binary_internal/BUILD new file mode 100644 index 0000000..2440016 --- /dev/null +++ b/rules/android_binary_internal/BUILD @@ -0,0 +1,18 @@ +# The android_binary_internal rule. + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +licenses(["notice"]) + +filegroup( + name = "all_files", + srcs = glob(["**"]), +) + +bzl_library( + name = "bzl", + srcs = glob(["*.bzl"]), + deps = [ + "@rules_android//rules:common_bzl", + ], +) diff --git a/rules/android_binary_internal/attrs.bzl b/rules/android_binary_internal/attrs.bzl new file mode 100644 index 0000000..5a7bca7 --- /dev/null +++ b/rules/android_binary_internal/attrs.bzl @@ -0,0 +1,69 @@ +# Copyright 2018 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Attributes.""" + +load( + "@rules_android//rules:attrs.bzl", + _attrs = "attrs", +) + +ATTRS = _attrs.replace( + _attrs.add( + dict( + deps = attr.label_list( + allow_files = True, + allow_rules = [ + "aar_import", + "android_library", + "cc_library", + "java_import", + "java_library", + "java_lite_proto_library", + ], + providers = [ + [CcInfo], + [JavaInfo], + ["AndroidResourcesInfo", "AndroidAssetsInfo"], + ], + cfg = android_common.multi_cpu_configuration, + ), + enable_data_binding = attr.bool(), + instruments = attr.label(), + manifest_values = attr.string_dict(), + manifest_merger = attr.string( + default = "auto", + values = ["auto", "legacy", "android", "force_android"], + ), + native_target = attr.label( + allow_files = False, + allow_rules = ["android_binary", "android_test"], + ), + resource_configuration_filters = attr.string_list(), + densities = attr.string_list(), + nocompress_extensions = attr.string_list(), + shrink_resources = _attrs.tristate.create( + default = _attrs.tristate.auto, + ), + _defined_resource_files = attr.bool(default = False), + _enable_manifest_merging = attr.bool(default = True), + ), + _attrs.COMPILATION, + _attrs.DATA_CONTEXT, + ), + # TODO(b/167599192): don't override manifest attr to remove .xml file restriction. + manifest = attr.label( + allow_single_file = True, + ), +) diff --git a/rules/android_binary_internal/impl.bzl b/rules/android_binary_internal/impl.bzl new file mode 100644 index 0000000..6838a81 --- /dev/null +++ b/rules/android_binary_internal/impl.bzl @@ -0,0 +1,111 @@ +# 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. + +"""Implementation.""" + +load("@rules_android//rules:acls.bzl", "acls") +load("@rules_android//rules:java.bzl", "java") +load( + "@rules_android//rules:processing_pipeline.bzl", + "ProviderInfo", + "processing_pipeline", +) +load("@rules_android//rules:resources.bzl", _resources = "resources") +load("@rules_android//rules:utils.bzl", "compilation_mode", "get_android_toolchain", "utils") + +def _process_resources(ctx, java_package, **unused_ctxs): + packaged_resources_ctx = _resources.package( + ctx, + assets = ctx.files.assets, + assets_dir = ctx.attr.assets_dir, + resource_files = ctx.files.resource_files, + manifest = ctx.file.manifest, + manifest_values = utils.expand_make_vars(ctx, ctx.attr.manifest_values), + resource_configs = ctx.attr.resource_configuration_filters, + densities = ctx.attr.densities, + nocompress_extensions = ctx.attr.nocompress_extensions, + java_package = java_package, + compilation_mode = compilation_mode.get(ctx), + shrink_resources = ctx.attr.shrink_resources, + use_android_resource_shrinking = ctx.fragments.android.use_android_resource_shrinking, + use_android_resource_cycle_shrinking = ctx.fragments.android.use_android_resource_cycle_shrinking, + use_legacy_manifest_merger = use_legacy_manifest_merger(ctx), + 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 = 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, + legacy_merger = ctx.attr._android_manifest_merge_tool.files_to_run, + xsltproc = ctx.attr._xsltproc_tool.files_to_run, + instrument_xslt = ctx.file._add_g3itr_xslt, + busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, + host_javabase = ctx.attr._host_javabase, + ) + return ProviderInfo( + name = "packaged_resources_ctx", + value = packaged_resources_ctx, + ) + +def use_legacy_manifest_merger(ctx): + """Whether legacy manifest merging is enabled. + + Args: + ctx: The context. + + Returns: + Boolean indicating whether legacy manifest merging is enabled. + """ + manifest_merger = ctx.attr.manifest_merger + android_manifest_merger = ctx.fragments.android.manifest_merger + + if android_manifest_merger == "force_android": + return False + if manifest_merger == "auto": + manifest_merger = android_manifest_merger + + return manifest_merger == "legacy" + +def finalize(ctx, providers, validation_outputs, **unused_ctxs): + providers.append( + OutputGroupInfo( + _validation = depset(validation_outputs), + ), + ) + return providers + +# Order dependent, as providers will not be available to downstream processors +# that may depend on the provider. Iteration order for a dictionary is based on +# insertion. +PROCESSORS = dict( + ResourceProcessor = _process_resources, +) + +_PROCESSING_PIPELINE = processing_pipeline.make_processing_pipeline( + processors = PROCESSORS, + finalize = finalize, +) + +def impl(ctx): + """The rule implementation. + + Args: + ctx: The context. + + Returns: + A list of providers. + """ + java_package = java.resolve_package_from_label(ctx.label, ctx.attr.custom_package) + return processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE) diff --git a/rules/android_binary_internal/rule.bzl b/rules/android_binary_internal/rule.bzl new file mode 100644 index 0000000..3070688 --- /dev/null +++ b/rules/android_binary_internal/rule.bzl @@ -0,0 +1,90 @@ +# 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. + +"""Starlark Android Binary for Android Rules.""" + +load(":attrs.bzl", "ATTRS") +load(":impl.bzl", "impl") +load( + "@rules_android//rules:attrs.bzl", + _attrs = "attrs", +) + +_DEFAULT_ALLOWED_ATTRS = ["name", "visibility", "tags", "testonly", "transitive_configs", "$enable_manifest_merging"] + +_DEFAULT_PROVIDES = [AndroidApplicationResourceInfo, OutputGroupInfo] + +def make_rule( + attrs = ATTRS, + implementation = impl, + provides = _DEFAULT_PROVIDES): + """Makes the rule. + + Args: + attrs: A dict. The attributes for the rule. + implementation: A function. The rule's implementation method. + provides: A list. The providers that the rule must provide. + + Returns: + A rule. + """ + return rule( + attrs = attrs, + implementation = implementation, + provides = provides, + toolchains = ["@rules_android//toolchains/android:toolchain_type"], + _skylark_testable = True, + fragments = [ + "android", + "java", + ], + ) + +android_binary_internal = make_rule() + +def sanitize_attrs(attrs, allowed_attrs = ATTRS.keys()): + """Sanitizes the attributes. + + 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_binary_internal rule. + allowed_attrs: The list of attribute keys to keep. + + Returns: + A dictionary containing valid attributes. + """ + for attr_name in attrs.keys(): + if attr_name not in allowed_attrs and attr_name not in _DEFAULT_ALLOWED_ATTRS: + attrs.pop(attr_name, None) + + # Some teams set this to a boolean/None which works for the native attribute but breaks + # the Starlark attribute. + if attr_name == "shrink_resources": + if attrs[attr_name] == None: + attrs.pop(attr_name, None) + else: + attrs[attr_name] = _attrs.tristate.normalize(attrs[attr_name]) + + return attrs + +def android_binary_internal_macro(**attrs): + """android_binary_internal rule. + + Args: + **attrs: Rule attributes + """ + 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 @@ ATTRS = _attrs.add( ), enable_data_binding = attr.bool(default = False), exported_plugins = attr.label_list( - allow_rules = [ - "java_plugin", + providers = [ + [JavaPluginInfo], ], cfg = "host", ), @@ -59,7 +59,6 @@ ATTRS = _attrs.add( _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 @@ def _process_resources(ctx, java_package, **unused_ctxs): # 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 @@ def _process_data_binding(ctx, java_package, resources_ctx, **unused_sub_ctxs): 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 @@ def _process_jvm(ctx, exceptions_ctx, resources_ctx, idl_ctx, db_ctx, **unused_s 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 @@ def _process_native(ctx, idl_ctx, **unused_ctx): 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 @@ def _make_legacy_provider(intellij_ctx, jvm_ctx, providers): 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 @@ def finalize( [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_packaged_resources/BUILD b/rules/android_packaged_resources/BUILD deleted file mode 100644 index f858689..0000000 --- a/rules/android_packaged_resources/BUILD +++ /dev/null @@ -1,25 +0,0 @@ -# Starlark Resource Packaging for Android Rules. - -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(["**"]), -) - -bzl_library( - name = "bzl", - srcs = glob(["*.bzl"]), - deps = [ - "@rules_android//rules:common_bzl", - ], -) diff --git a/rules/android_packaged_resources/attrs.bzl b/rules/android_packaged_resources/attrs.bzl deleted file mode 100644 index 5a7bca7..0000000 --- a/rules/android_packaged_resources/attrs.bzl +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Attributes.""" - -load( - "@rules_android//rules:attrs.bzl", - _attrs = "attrs", -) - -ATTRS = _attrs.replace( - _attrs.add( - dict( - deps = attr.label_list( - allow_files = True, - allow_rules = [ - "aar_import", - "android_library", - "cc_library", - "java_import", - "java_library", - "java_lite_proto_library", - ], - providers = [ - [CcInfo], - [JavaInfo], - ["AndroidResourcesInfo", "AndroidAssetsInfo"], - ], - cfg = android_common.multi_cpu_configuration, - ), - enable_data_binding = attr.bool(), - instruments = attr.label(), - manifest_values = attr.string_dict(), - manifest_merger = attr.string( - default = "auto", - values = ["auto", "legacy", "android", "force_android"], - ), - native_target = attr.label( - allow_files = False, - allow_rules = ["android_binary", "android_test"], - ), - resource_configuration_filters = attr.string_list(), - densities = attr.string_list(), - nocompress_extensions = attr.string_list(), - shrink_resources = _attrs.tristate.create( - default = _attrs.tristate.auto, - ), - _defined_resource_files = attr.bool(default = False), - _enable_manifest_merging = attr.bool(default = True), - ), - _attrs.COMPILATION, - _attrs.DATA_CONTEXT, - ), - # TODO(b/167599192): don't override manifest attr to remove .xml file restriction. - manifest = attr.label( - allow_single_file = True, - ), -) diff --git a/rules/android_packaged_resources/impl.bzl b/rules/android_packaged_resources/impl.bzl deleted file mode 100644 index e3d6ac0..0000000 --- a/rules/android_packaged_resources/impl.bzl +++ /dev/null @@ -1,111 +0,0 @@ -# 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. - -"""Implementation.""" - -load("@rules_android//rules:acls.bzl", "acls") -load("@rules_android//rules:java.bzl", "java") -load( - "@rules_android//rules:processing_pipeline.bzl", - "ProviderInfo", - "processing_pipeline", -) -load("@rules_android//rules:resources.bzl", _resources = "resources") -load("@rules_android//rules:utils.bzl", "compilation_mode", "get_android_toolchain", "utils") - -def _process_resources(ctx, java_package, **unused_ctxs): - packaged_resources_ctx = _resources.package( - ctx, - assets = ctx.files.assets, - assets_dir = ctx.attr.assets_dir, - resource_files = ctx.files.resource_files, - manifest = ctx.file.manifest, - manifest_values = utils.expand_make_vars(ctx, ctx.attr.manifest_values), - resource_configs = ctx.attr.resource_configuration_filters, - densities = ctx.attr.densities, - nocompress_extensions = ctx.attr.nocompress_extensions, - java_package = java_package, - compilation_mode = compilation_mode.get(ctx), - shrink_resources = ctx.attr.shrink_resources, - use_android_resource_shrinking = ctx.fragments.android.use_android_resource_shrinking, - use_android_resource_cycle_shrinking = ctx.fragments.android.use_android_resource_cycle_shrinking, - use_legacy_manifest_merger = use_legacy_manifest_merger(ctx), - 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, - instruments = ctx.attr.instruments, - aapt = get_android_toolchain(ctx).aapt2.files_to_run, - android_jar = ctx.attr._android_sdk[AndroidSdkInfo].android_jar, - legacy_merger = ctx.attr._android_manifest_merge_tool.files_to_run, - xsltproc = ctx.attr._xsltproc_tool.files_to_run, - instrument_xslt = ctx.file._add_g3itr_xslt, - busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, - host_javabase = ctx.attr._host_javabase, - ) - return ProviderInfo( - name = "packaged_resources_ctx", - value = packaged_resources_ctx, - ) - -def use_legacy_manifest_merger(ctx): - """Whether legacy manifest merging is enabled. - - Args: - ctx: The context. - - Returns: - Boolean indicating whether legacy manifest merging is enabled. - """ - manifest_merger = ctx.attr.manifest_merger - android_manifest_merger = ctx.fragments.android.manifest_merger - - if android_manifest_merger == "force_android": - return False - if manifest_merger == "auto": - manifest_merger = android_manifest_merger - - return manifest_merger == "legacy" - -def finalize(ctx, providers, validation_outputs, **unused_ctxs): - providers.append( - OutputGroupInfo( - _validation = depset(validation_outputs), - ), - ) - return providers - -# Order dependent, as providers will not be available to downstream processors -# that may depend on the provider. Iteration order for a dictionary is based on -# insertion. -PROCESSORS = dict( - ResourceProcessor = _process_resources, -) - -_PROCESSING_PIPELINE = processing_pipeline.make_processing_pipeline( - processors = PROCESSORS, - finalize = finalize, -) - -def impl(ctx): - """The rule implementation. - - Args: - ctx: The context. - - Returns: - A list of providers. - """ - java_package = java.resolve_package_from_label(ctx.label, ctx.attr.custom_package) - return processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE) diff --git a/rules/android_packaged_resources/rule.bzl b/rules/android_packaged_resources/rule.bzl deleted file mode 100644 index db3f96a..0000000 --- a/rules/android_packaged_resources/rule.bzl +++ /dev/null @@ -1,91 +0,0 @@ -# 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. - -"""Starlark Resource Packaging for Android Rules.""" - -load(":attrs.bzl", "ATTRS") -load(":impl.bzl", "impl") -load( - "@rules_android//rules:attrs.bzl", - _attrs = "attrs", -) - -_DEFAULT_ALLOWED_ATTRS = ["name", "visibility", "tags", "testonly", "transitive_configs", "$enable_manifest_merging"] - -_DEFAULT_PROVIDES = [AndroidApplicationResourceInfo, OutputGroupInfo] - -# TODO(b/167721629): Rename android_packaged_resources to android_binary_internal. -def make_rule( - attrs = ATTRS, - implementation = impl, - provides = _DEFAULT_PROVIDES): - """Makes the rule. - - Args: - attrs: A dict. The attributes for the rule. - implementation: A function. The rule's implementation method. - provides: A list. The providers that the rule must provide. - - Returns: - A rule. - """ - return rule( - attrs = attrs, - implementation = implementation, - provides = provides, - toolchains = ["@rules_android//toolchains/android:toolchain_type"], - _skylark_testable = True, - fragments = [ - "android", - "java", - ], - ) - -_android_packaged_resources = 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 - 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. - allowed_attrs: The list of attribute keys to keep. - - Returns: - A dictionary containing valid attributes. - """ - for attr_name in attrs.keys(): - if attr_name not in allowed_attrs and attr_name not in _DEFAULT_ALLOWED_ATTRS: - attrs.pop(attr_name, None) - - # Some teams set this to a boolean/None which works for the native attribute but breaks - # the Starlark attribute. - if attr_name == "shrink_resources": - if attrs[attr_name] == None: - attrs.pop(attr_name, None) - else: - attrs[attr_name] = _attrs.tristate.normalize(attrs[attr_name]) - - return attrs - -def android_packaged_resources_macro(**attrs): - """android_packaged_resources rule. - - Args: - **attrs: Rule attributes - """ - _android_packaged_resources(**sanitize_attrs(attrs)) 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 @@ def _impl(ctx): # 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 @@ _tristate = struct( _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 @@ _COMPILATION = _add( allow_files = True, ), plugins = attr.label_list( - allow_rules = ["java_plugin"], + providers = [JavaPluginInfo], cfg = "host", ), javacopts = attr.string_list(), @@ -228,6 +228,11 @@ ANDROID_SDK_ATTRS = dict( 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 @@ ANDROID_SDK_ATTRS = dict( 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 @@ def _copy_annotation_file(ctx, output_dir, annotation_template): _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 @@ def _gen_sources(ctx, output_dir, java_package, deps, data_binding_exec): "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 @@ def _process( defines_resources = False, enable_data_binding = False, java_package = None, + layout_info = None, deps = [], exports = [], data_binding_exec = None, @@ -174,6 +174,7 @@ def _process( 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 @@ def _process( 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 @@ def _process( 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 @@ def define_flags(): 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 @@ def _invalid_java_package(custom_package, java_package): (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 @@ def _compile_android( 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 @@ def _compile( 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 @@ def _singlejar( 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 _singlejar( 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 @@ def _run( 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 @@ def _run( 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 @@ java = struct( 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 @@ StarlarkAndroidResourcesInfo = provider( 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,7 +103,37 @@ AndroidLintRulesInfo = provider( ), ) +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( 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 @@ _VERSION_CODE = "versionCode" # 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 @@ _ResourcesProcessContextInfo = provider( _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 @@ _ResourcesPackageContextInfo = provider( _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 @@ def _package( """ _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 @@ def _package( 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 @@ def _package( 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 @@ def _package( ) 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 @@ def _package( ) 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 @@ def _package( 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 @@ def _process_starlark( 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 @@ def _process_starlark( 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 @@ def _process_starlark( _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 @@ def _process_starlark( 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 @@ def _process_starlark( 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 @@ def _process_starlark( 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 @@ def _process_starlark( 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 @@ def _process_starlark( ) _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 @@ def _process_starlark( ) 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 @@ def _process_starlark( ) _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 @@ def _process_starlark( 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 @@ def _process_starlark( # 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 @@ def _process_starlark( 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 @@ def _process_starlark( 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 @@ def _process( 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 @@ def _process( 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 @@ load( "//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 @@ load( 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 @@ def _expand_make_vars(ctx, vals): 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 @@ utils = struct( 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 > $@ <