diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-10 01:06:58 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-10 01:06:58 +0000 |
commit | 91f5a4960f3c73a5e59b27bcc2f8ee4c31b08fc8 (patch) | |
tree | a58049c9682d6fd38e8408479340bf3911b87515 | |
parent | bc67c32f96ccf8d0c503a88cbbf7b7ae91559be3 (diff) | |
parent | 9e965d6fece27a77de5377433c2f7e6999b8cc0b (diff) | |
download | bazelbuild-rules_android-91f5a4960f3c73a5e59b27bcc2f8ee4c31b08fc8.tar.gz |
Snap for 10923648 from 9e965d6fece27a77de5377433c2f7e6999b8cc0b to 24Q1-releaseandroid-14.0.0_r37android-14.0.0_r36android-14.0.0_r35android-14.0.0_r34android-14.0.0_r33android-14.0.0_r32android-14.0.0_r31android-14.0.0_r30android-14.0.0_r29android14-qpr2-s5-releaseandroid14-qpr2-s4-releaseandroid14-qpr2-s3-releaseandroid14-qpr2-s2-releaseandroid14-qpr2-s1-releaseandroid14-qpr2-release
Change-Id: Ic28eeddca3097c154d1283e0670dc1c497bfc08b
77 files changed, 1963 insertions, 331 deletions
@@ -12,7 +12,7 @@ third_party { type: GIT value: "https://github.com/bazelbuild/rules_android" } - version: "d1dca942348973d99c9e33247f17fb5f1ef92732" - last_upgrade_date { year: 2023 month: 7 day: 25 } + version: "b1ad8136600931878dba61dbb28068bde5d5ed84" + last_upgrade_date { year: 2023 month: 10 day: 6 } license_type: NOTICE } diff --git a/MODULE.bazel b/MODULE.bazel index 82c2a0d..2b38cc9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -13,7 +13,7 @@ use_repo(rules_java_toolchains, "remote_java_tools") bazel_dep(name = "protobuf", version = "3.19.0", repo_name = "com_google_protobuf") bazel_dep(name = "rules_jvm_external", version = "4.5") bazel_dep(name = "bazel_skylib", version = "1.0.3") -bazel_dep(name = "rules_robolectric", version = "4.10") +bazel_dep(name = "rules_robolectric", version = "4.10", repo_name = "robolectric") register_toolchains("//toolchains/android:all") @@ -32,6 +32,7 @@ go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//:go.mod") use_repo( go_deps, + "com_github_golang_glog", "com_github_google_go_cmp", "org_golang_google_protobuf", "org_golang_x_sync", @@ -19,12 +19,15 @@ maybe( android_sdk_supplemental_repository(name = "androidsdk-supplemental") load("prereqs.bzl", "rules_android_prereqs") -rules_android_prereqs() -load("defs.bzl", "rules_android_workspace") +rules_android_prereqs(dev_mode = True) + +load("defs_dev.bzl", "rules_android_workspace") rules_android_workspace() register_toolchains("//toolchains/android:all") + register_toolchains("//toolchains/android_sdk:all") + register_toolchains("//toolchains/emulator:all") @@ -16,11 +16,9 @@ load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") -load("@cgrindel_bazel_starlib//:deps.bzl", "bazel_starlib_dependencies") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@robolectric//bazel:robolectric.bzl", "robolectric_repositories") -load("@rules_bazel_integration_test//bazel_integration_test:defs.bzl", "bazel_binaries") load("@rules_java//java:repositories.bzl", "rules_java_dependencies", "rules_java_toolchains") load("@rules_jvm_external//:defs.bzl", "maven_install") load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") @@ -83,6 +81,13 @@ def rules_android_workspace(): version = "v0.0.0-20210220032951-036812b2e83c", ) + go_repository( + name = "com_github_golang_glog", + importpath = "github.com/golang/glog", + version = "v1.1.2", + sum = "h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=", + ) + robolectric_repositories() rules_java_dependencies() @@ -92,12 +97,3 @@ def rules_android_workspace(): rules_proto_toolchains() py_repositories() - - # Integration test setup - bazel_starlib_dependencies() - - bazel_binaries( - versions = [ - "last_green", - ], - ) diff --git a/defs_dev.bzl b/defs_dev.bzl new file mode 100644 index 0000000..7c31efe --- /dev/null +++ b/defs_dev.bzl @@ -0,0 +1,31 @@ +# Copyright 2023 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 development.""" + +load("@cgrindel_bazel_starlib//:deps.bzl", "bazel_starlib_dependencies") +load("@rules_bazel_integration_test//bazel_integration_test:defs.bzl", "bazel_binaries") +load(":defs.bzl", non_dev_workspace = "rules_android_workspace") + +def rules_android_workspace(): + non_dev_workspace() + + # Integration test setup + bazel_starlib_dependencies() + + bazel_binaries( + versions = [ + "last_green", + ], + ) @@ -1,9 +1,10 @@ module github.com/bazelbuild/rules_android -go 1.18 +go 1.19 require ( github.com/google/go-cmp v0.5.9 + github.com/golang/glog v1.1.2 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c google.golang.org/protobuf v1.28.1 ) @@ -1,3 +1,5 @@ +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= diff --git a/kokoro/presubmit/presubmit_main.sh b/kokoro/presubmit/presubmit_main.sh index ceb4bd9..c47237b 100644 --- a/kokoro/presubmit/presubmit_main.sh +++ b/kokoro/presubmit/presubmit_main.sh @@ -98,14 +98,18 @@ function main() { cd "${KOKORO_ARTIFACTS_DIR}/git/rules_android" # Fetch all external deps; should reveal any bugs related to external dep - # references. - "$bazel" aquery 'deps(...)' --noenable_bzlmod 2>&1 > /dev/null + # references. First run this query with bzlmod enabled to catch missing + # bzlmod deps. + "$bazel" aquery 'deps(...)' --enable_bzlmod > /dev/null + # Perform the same aquery with bzlmod disabled to sniff out WORKSPACE issues + "$bazel" aquery 'deps(...)' --noenable_bzlmod > /dev/null "$bazel" test "${COMMON_ARGS[@]}" //src/common/golang/... \ //src/tools/ak/... \ //src/tools/javatests/... \ //src/tools/jdeps/... \ //src/tools/java/... \ + //src/tools/mi/... \ //test/... # Go to basic app workspace in the source tree diff --git a/mobile_install/dependency_map.bzl b/mobile_install/dependency_map.bzl index 2769a90..7b90cd2 100644 --- a/mobile_install/dependency_map.bzl +++ b/mobile_install/dependency_map.bzl @@ -16,37 +16,37 @@ versioned_deps = struct( mi_shell_app = struct( - head = "//tools/android:fail", + head = "//tools/android:gen_fail", ), android_kit = struct( head = "//src/tools/ak", ), bootstraper = struct( - head = "//tools/android:fail", + head = "//tools/android:gen_fail", ), deploy = struct( - head = "//src/tools/mi/deployment:deploy_binary", + head = "//src/tools/mi/deployment_oss:deploy_binary", ), deploy_info = struct( - head = "//src/tools/mi/deploy_info:deploy_info", + head = "//tools/android:gen_fail", ), forwarder = struct( - head = "//tools/android:fail", + head = "//tools/android:gen_fail", ), jar_tool = struct( head = "@bazel_tools//tools/jdk:JavaBuilder_deploy.jar", ), make_sync = struct( - head = "//src/tools/mi/app_info:make_sync", + head = "//tools/android:gen_fail", ), merge_syncs = struct( - head = "//src/tools/mi/workspace:merge_syncs", + head = "//tools/android:gen_fail", ), pack_dexes = struct( - head = "//src/tools/mi/workspace:pack_dexes", + head = "//tools/android:gen_fail", ), pack_generic = struct( - head = "//src/tools/mi/workspace:pack_generic", + head = "//tools/android:gen_fail", ), res_v3_dummy_manifest = struct( head = "//rules:res_v3_dummy_AndroidManifest.xml", @@ -55,9 +55,9 @@ versioned_deps = struct( head = "//rules:res_v3_dummy_R.txt", ), resource_extractor = struct( - head = "//src/tools/resource_extractor:main", + head = "//tools/android:gen_fail", ), sync_merger = struct( - head = "//src/tools/mi/app_info:sync_merger", + head = "//tools/android:gen_fail", ), ) diff --git a/mobile_install/tools.bzl b/mobile_install/tools.bzl index 5086779..70c49c5 100644 --- a/mobile_install/tools.bzl +++ b/mobile_install/tools.bzl @@ -26,7 +26,7 @@ TOOL_ATTRS = dict( # use dummy libs. _android_sdk = attr.label( default = Label( - "@androidsdk//:sdk", + "//tools/android:android_jar", ), allow_files = True, cfg = "target", @@ -37,14 +37,14 @@ TOOL_ATTRS = dict( ), ), _studio_deployer = attr.label( - default = "@androidsdk//:fail", # TODO(#119): Studio deployer jar to be released + default = "//tools/android:gen_fail", # TODO(#119): Studio deployer jar to be released allow_single_file = True, cfg = "exec", executable = True, ), _mi_shell_dummy_native_libs = attr.label( default = Label( - "@androidsdk//:fail", # FIXME: Unused internally + "//tools/android:gen_fail", # FIXME: Unused internally ), allow_single_file = True, cfg = "target", @@ -91,7 +91,7 @@ TOOL_ATTRS = dict( executable = True, ), _d8 = attr.label( - default = Label("@bazel_tools//src/tools/android/java/com/google/devtools/build/android/r8:r8"), + default = Label("//tools/android:d8"), allow_files = True, cfg = "exec", executable = True, diff --git a/prereqs.bzl b/prereqs.bzl index 2c70587..893fb43 100644 --- a/prereqs.bzl +++ b/prereqs.bzl @@ -17,7 +17,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") -def rules_android_prereqs(): +def rules_android_prereqs(dev_mode = False): """Downloads prerequisite repositories for rules_android.""" maybe( http_archive, @@ -87,9 +87,9 @@ def rules_android_prereqs(): maybe( http_archive, name = "robolectric", - urls = ["https://github.com/robolectric/robolectric-bazel/archive/4.9.2.tar.gz"], - strip_prefix = "robolectric-bazel-4.9.2", - sha256 = "7e007fcfdca7b7228cb4de72707e8b317026ea95000f963e91d5ae365be52d0d", + urls = ["https://github.com/robolectric/robolectric-bazel/archive/4.10.3.tar.gz"], + strip_prefix = "robolectric-bazel-4.10.3", + sha256 = "1b199a932cbde4af728dd8275937091adbb89a4bf63d326de49e6d0a42e723bf", ) maybe( @@ -133,20 +133,21 @@ def rules_android_prereqs(): sha256 = "84aec9e21cc56fbc7f1335035a71c850d1b9b5cc6ff497306f84cced9a769841", ) - maybe( - http_archive, - name = "rules_bazel_integration_test", - sha256 = "d6dada79939533a8127000d2aafa125f29a4a97f720e01c050fdeb81b1080b08", - urls = [ - "https://github.com/bazel-contrib/rules_bazel_integration_test/releases/download/v0.17.0/rules_bazel_integration_test.v0.17.0.tar.gz", - ], - ) - - maybe( - http_archive, - name = "cgrindel_bazel_starlib", - sha256 = "a8d25340956b429b56302d3fd702bb3df8b3a67db248dd32b3084891ad497964", - urls = [ - "https://github.com/cgrindel/bazel-starlib/releases/download/v0.17.0/bazel-starlib.v0.17.0.tar.gz", - ], - ) + if dev_mode: + maybe( + http_archive, + name = "rules_bazel_integration_test", + sha256 = "d6dada79939533a8127000d2aafa125f29a4a97f720e01c050fdeb81b1080b08", + urls = [ + "https://github.com/bazel-contrib/rules_bazel_integration_test/releases/download/v0.17.0/rules_bazel_integration_test.v0.17.0.tar.gz", + ], + ) + + maybe( + http_archive, + name = "cgrindel_bazel_starlib", + sha256 = "a8d25340956b429b56302d3fd702bb3df8b3a67db248dd32b3084891ad497964", + urls = [ + "https://github.com/cgrindel/bazel-starlib/releases/download/v0.17.0/bazel-starlib.v0.17.0.tar.gz", + ], + ) diff --git a/rules/BUILD b/rules/BUILD index 467072b..d907612 100644 --- a/rules/BUILD +++ b/rules/BUILD @@ -33,6 +33,7 @@ bzl_library( "common.bzl", "data_binding.bzl", "idl.bzl", + "instrumented_app_info_aspect.bzl", "intellij.bzl", "java.bzl", "migration_tag_DONOTUSE.bzl", diff --git a/rules/aar_import/impl.bzl b/rules/aar_import/impl.bzl index 0b149bb..c80d618 100644 --- a/rules/aar_import/impl.bzl +++ b/rules/aar_import/impl.bzl @@ -475,7 +475,7 @@ def impl(ctx): manifest_ctx = _resources.bump_min_sdk( ctx, manifest = android_manifest, - floor = _resources.DEPOT_MIN_SDK_FLOOR if _acls.in_enforce_min_sdk_floor_rollout(str(ctx.label)) else 0, + floor = _acls.get_min_sdk_floor(str(ctx.label)), enforce_min_sdk_floor_tool = _get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, ) diff --git a/rules/acls.bzl b/rules/acls.bzl index 858ef07..edef667 100644 --- a/rules/acls.bzl +++ b/rules/acls.bzl @@ -33,56 +33,62 @@ load("//rules/acls:aar_import_exports_r_java.bzl", "AAR_IMPORT_EXPORTS_R_JAVA") load("//rules/acls:aar_propagate_resources.bzl", "AAR_PROPAGATE_RESOURCES_FALLBACK", "AAR_PROPAGATE_RESOURCES_ROLLOUT") load("//rules/acls:ait_install_snapshots.bzl", "APP_INSTALLATION_SNAPSHOT", "APP_INSTALLATION_SNAPSHOT_FALLBACK") load("//rules/acls:allow_resource_conflicts.bzl", "ALLOW_RESOURCE_CONFLICTS") +load("//rules/acls:android_apk_to_bundle_features_lockdown.bzl", "ANDROID_APK_TO_BUNDLE_FEATURES") load("//rules/acls:android_archive_dogfood.bzl", "ANDROID_ARCHIVE_DOGFOOD") load("//rules/acls:android_archive_duplicate_class_allowlist.bzl", "ANDROID_ARCHIVE_DUPLICATE_CLASS_ALLOWLIST") load("//rules/acls:android_archive_excluded_deps_denylist.bzl", "ANDROID_ARCHIVE_EXCLUDED_DEPS_DENYLIST") load("//rules/acls:android_archive_exposed_package_allowlist.bzl", "ANDROID_ARCHIVE_EXPOSED_PACKAGE_ALLOWLIST") -load("//rules/acls:android_test_lockdown.bzl", "ANDROID_TEST_LOCKDOWN_GENERATOR_FUNCTIONS", "ANDROID_TEST_LOCKDOWN_TARGETS") -load("//rules/acls:android_device_plugin_rollout.bzl", "ANDROID_DEVICE_PLUGIN_FALLBACK", "ANDROID_DEVICE_PLUGIN_ROLLOUT") -load("//rules/acls:android_instrumentation_binary_starlark_resources.bzl", "ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_FALLBACK", "ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_ROLLOUT") +load("//rules/acls:android_binary_min_sdk_version_attribute.bzl", "ANDROID_BINARY_MIN_SDK_VERSION_ATTRIBUTE_ALLOWLIST") +load("//rules/acls:android_binary_raw_access_to_resource_paths_allowlist.bzl", "ANDROID_BINARY_RAW_ACCESS_TO_RESOURCE_PATHS_ALLOWLIST") +load("//rules/acls:android_binary_resource_name_obfuscation_opt_out_allowlist.bzl", "ANDROID_BINARY_RESOURCE_NAME_OBFUSCATION_OPT_OUT_ALLOWLIST") +load("//rules/acls:android_binary_starlark_dex_desugar_proguard.bzl", "ANDROID_BINARY_STARLARK_DEX_DESUGAR_PROGUARD_FALLBACK", "ANDROID_BINARY_STARLARK_DEX_DESUGAR_PROGUARD_ROLLOUT") load("//rules/acls:android_binary_starlark_javac.bzl", "ANDROID_BINARY_STARLARK_JAVAC_FALLBACK", "ANDROID_BINARY_STARLARK_JAVAC_ROLLOUT") load("//rules/acls:android_binary_starlark_split_transition.bzl", "ANDROID_BINARY_STARLARK_SPLIT_TRANSITION_FALLBACK", "ANDROID_BINARY_STARLARK_SPLIT_TRANSITION_ROLLOUT") load("//rules/acls:android_binary_with_sandboxed_sdks_allowlist.bzl", "ANDROID_BINARY_WITH_SANDBOXED_SDKS_ALLOWLIST") +load("//rules/acls:android_build_stamping_rollout.bzl", "ANDROID_BUILD_STAMPING_FALLBACK", "ANDROID_BUILD_STAMPING_ROLLOUT") +load("//rules/acls:android_device_plugin_rollout.bzl", "ANDROID_DEVICE_PLUGIN_FALLBACK", "ANDROID_DEVICE_PLUGIN_ROLLOUT") load("//rules/acls:android_feature_splits_dogfood.bzl", "ANDROID_FEATURE_SPLITS_DOGFOOD") +load("//rules/acls:android_instrumentation_binary_starlark_resources.bzl", "ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_FALLBACK", "ANDROID_INSTRUMENTATION_BINARY_STARLARK_RESOURCES_ROLLOUT") +load("//rules/acls:android_instrumentation_test_manifest_check_rollout.bzl", "ANDROID_INSTRUMENTATION_TEST_MANIFEST_CHECK_FALLBACK", "ANDROID_INSTRUMENTATION_TEST_MANIFEST_CHECK_ROLLOUT") +load("//rules/acls:android_instrumentation_test_prebuilt_test_apk.bzl", "ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_FALLBACK", "ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_ROLLOUT") load("//rules/acls:android_library_resources_without_srcs.bzl", "ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS", "ANDROID_LIBRARY_RESOURCES_WITHOUT_SRCS_GENERATOR_FUNCTIONS") load("//rules/acls:android_library_starlark_resource_outputs.bzl", "ANDROID_LIBRARY_STARLARK_RESOURCE_OUTPUTS_FALLBACK", "ANDROID_LIBRARY_STARLARK_RESOURCE_OUTPUTS_ROLLOUT") load("//rules/acls:android_library_use_aosp_aidl_compiler.bzl", "ANDROID_LIBRARY_USE_AOSP_AIDL_COMPILER_ALLOWLIST") load("//rules/acls:android_lint_checks_rollout.bzl", "ANDROID_LINT_CHECKS_FALLBACK", "ANDROID_LINT_CHECKS_ROLLOUT") load("//rules/acls:android_lint_rollout.bzl", "ANDROID_LINT_FALLBACK", "ANDROID_LINT_ROLLOUT") -load("//rules/acls:lint_registry_rollout.bzl", "LINT_REGISTRY_FALLBACK", "LINT_REGISTRY_ROLLOUT") -load("//rules/acls:android_build_stamping_rollout.bzl", "ANDROID_BUILD_STAMPING_FALLBACK", "ANDROID_BUILD_STAMPING_ROLLOUT") +load("//rules/acls:android_local_test_jdk_sts_rollout.bzl", "ANDROID_LOCAL_TEST_JDK_STS_FALLBACK", "ANDROID_LOCAL_TEST_JDK_STS_ROLLOUT") +load("//rules/acls:android_test_lockdown.bzl", "ANDROID_TEST_LOCKDOWN_GENERATOR_FUNCTIONS", "ANDROID_TEST_LOCKDOWN_TARGETS") +load("//rules/acls:android_test_platform_rollout.bzl", "ANDROID_TEST_PLATFORM_FALLBACK", "ANDROID_TEST_PLATFORM_ROLLOUT") load("//rules/acls:b122039567.bzl", "B122039567") load("//rules/acls:b123854163.bzl", "B123854163") +load("//rules/acls:baseline_profiles_optimizer_integration.bzl", "BASELINE_PROFILES_OPTIMIZER_INTEGRATION") +load("//rules/acls:baseline_profiles_rollout.bzl", "BASELINE_PROFILES_ROLLOUT") load("//rules/acls:databinding.bzl", "DATABINDING_ALLOWED", "DATABINDING_DISALLOWED") load("//rules/acls:dex2oat_opts.bzl", "CAN_USE_DEX2OAT_OPTIONS") load("//rules/acls:fix_export_exporting_rollout.bzl", "FIX_EXPORT_EXPORTING_FALLBACK", "FIX_EXPORT_EXPORTING_ROLLOUT") load("//rules/acls:fix_resource_transitivity_rollout.bzl", "FIX_RESOURCE_TRANSITIVITY_FALLBACK", "FIX_RESOURCE_TRANSITIVITY_ROLLOUT") load("//rules/acls:host_dex2oat_rollout.bzl", "AIT_USE_HOST_DEX2OAT_ROLLOUT", "AIT_USE_HOST_DEX2OAT_ROLLOUT_FALLBACK") load("//rules/acls:install_apps_in_data.bzl", "INSTALL_APPS_IN_DATA") +load("//rules/acls:lint_registry_rollout.bzl", "LINT_REGISTRY_FALLBACK", "LINT_REGISTRY_ROLLOUT") load("//rules/acls:local_test_multi_proto.bzl", "LOCAL_TEST_MULTI_PROTO_PKG") load("//rules/acls:local_test_rollout.bzl", "LOCAL_TEST_FALLBACK", "LOCAL_TEST_ROLLOUT") load("//rules/acls:local_test_starlark_resources.bzl", "LOCAL_TEST_STARLARK_RESOURCES_FALLBACK", "LOCAL_TEST_STARLARK_RESOURCES_ROLLOUT") -load("//rules/acls:android_test_platform_rollout.bzl", "ANDROID_TEST_PLATFORM_FALLBACK", "ANDROID_TEST_PLATFORM_ROLLOUT") -load("//rules/acls:test_to_instrument_test_rollout.bzl", "TEST_TO_INSTRUMENT_TEST_FALLBACK", "TEST_TO_INSTRUMENT_TEST_ROLLOUT") +load("//rules/acls:min_sdk_floors.bzl", "MIN_SDK_FLOORS") load( "//rules/acls:partial_jetification_targets.bzl", "PARTIAL_JETIFICATION_TARGETS_FALLBACK", "PARTIAL_JETIFICATION_TARGETS_ROLLOUT", ) -load("//rules/acls:android_instrumentation_test_manifest_check_rollout.bzl", "ANDROID_INSTRUMENTATION_TEST_MANIFEST_CHECK_FALLBACK", "ANDROID_INSTRUMENTATION_TEST_MANIFEST_CHECK_ROLLOUT") -load("//rules/acls:android_instrumentation_test_prebuilt_test_apk.bzl", "ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_FALLBACK", "ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_ROLLOUT") -load("//rules/acls:baseline_profiles_rollout.bzl", "BASELINE_PROFILES_ROLLOUT") -load("//rules/acls:baseline_profiles_optimizer_integration.bzl", "BASELINE_PROFILES_OPTIMIZER_INTEGRATION") -load("//rules/acls:enforce_min_sdk_floor_rollout.bzl", "ENFORCE_MIN_SDK_FLOOR_FALLBACK", "ENFORCE_MIN_SDK_FLOOR_ROLLOUT") -load("//rules/acls:android_apk_to_bundle_features_lockdown.bzl", "ANDROID_APK_TO_BUNDLE_FEATURES") -load("//rules/acls:android_local_test_jdk_sts_rollout.bzl", "ANDROID_LOCAL_TEST_JDK_STS_FALLBACK", "ANDROID_LOCAL_TEST_JDK_STS_ROLLOUT") -load("//rules/acls:shared_library_resource_linking.bzl", "SHARED_LIBRARY_RESOURCE_LINKING_ALLOWLIST") -load("//rules/acls:android_binary_starlark_dex_desugar_proguard.bzl", "ANDROID_BINARY_STARLARK_DEX_DESUGAR_PROGUARD_FALLBACK", "ANDROID_BINARY_STARLARK_DEX_DESUGAR_PROGUARD_ROLLOUT") -load("//rules/acls:android_binary_min_sdk_version_attribute.bzl", "ANDROID_BINARY_MIN_SDK_VERSION_ATTRIBUTE_ALLOWLIST") -load("//rules/acls:android_binary_raw_access_to_resource_paths_allowlist.bzl", "ANDROID_BINARY_RAW_ACCESS_TO_RESOURCE_PATHS_ALLOWLIST") -load("//rules/acls:android_binary_resource_name_obfuscation_opt_out_allowlist.bzl", "ANDROID_BINARY_RESOURCE_NAME_OBFUSCATION_OPT_OUT_ALLOWLIST") load("//rules/acls:proguard_apply_mapping.bzl", "ALLOW_PROGUARD_APPLY_MAPPING") load("//rules/acls:r8.bzl", "USE_R8") +load("//rules/acls:shared_library_resource_linking.bzl", "SHARED_LIBRARY_RESOURCE_LINKING_ALLOWLIST") +load("//rules/acls:test_to_instrument_test_rollout.bzl", "TEST_TO_INSTRUMENT_TEST_FALLBACK", "TEST_TO_INSTRUMENT_TEST_ROLLOUT") + +def _get_min_sdk_floor(fqn): + for minsdk, package_dict in MIN_SDK_FLOORS_DICT.items(): + if matches(fqn, package_dict): + return minsdk + fail("No matching min_sdk_floor for %s" % fqn) def _in_aar_import_deps_checker(fqn): return not matches(fqn, AAR_IMPORT_DEPS_CHECKER_FALLBACK_DICT) and matches(fqn, AAR_IMPORT_DEPS_CHECKER_ROLLOUT_DICT) @@ -213,9 +219,6 @@ def _in_baseline_profiles_rollout(fqn): def _in_baseline_profiles_optimizer_integration(fqn): return matches(fqn, BASELINE_PROFILES_OPTIMIZER_INTEGRATION) -def _in_enforce_min_sdk_floor_rollout(fqn): - return not matches(fqn, ENFORCE_MIN_SDK_FLOOR_FALLBACK_DICT) and matches(fqn, ENFORCE_MIN_SDK_FLOOR_ROLLOUT_DICT) - def _in_android_apk_to_bundle_features(fqn): return matches(fqn, ANDROID_APK_TO_BUNDLE_FEATURES_DICT) @@ -250,6 +253,12 @@ def make_dict(lst): """Do not use this method outside of acls directory.""" return {t: True for t in lst} +def make_min_sdk_dict(dict_of_lists): + res = {} + for k in dict_of_lists.keys(): + res[k] = make_dict(dict_of_lists[k]) + return res + AAR_IMPORT_DEPS_CHECKER_FALLBACK_DICT = make_dict(AAR_IMPORT_DEPS_CHECKER_FALLBACK) 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) @@ -313,8 +322,7 @@ ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_ROLLOUT_DICT = make_dict(ANDROID_ ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_FALLBACK_DICT = make_dict(ANDROID_INSTRUMENTATION_TEST_PREBUILT_TEST_APK_FALLBACK) BASELINE_PROFILES_ROLLOUT_DICT = make_dict(BASELINE_PROFILES_ROLLOUT) BASELINE_PROFILES_OPTIMIZER_INTEGRATION_DICT = make_dict(BASELINE_PROFILES_OPTIMIZER_INTEGRATION) -ENFORCE_MIN_SDK_FLOOR_ROLLOUT_DICT = make_dict(ENFORCE_MIN_SDK_FLOOR_ROLLOUT) -ENFORCE_MIN_SDK_FLOOR_FALLBACK_DICT = make_dict(ENFORCE_MIN_SDK_FLOOR_FALLBACK) +MIN_SDK_FLOORS_DICT = make_min_sdk_dict(MIN_SDK_FLOORS) ANDROID_APK_TO_BUNDLE_FEATURES_DICT = make_dict(ANDROID_APK_TO_BUNDLE_FEATURES) ANDROID_LIBRARY_USE_AOSP_AIDL_COMPILER_ALLOWLIST_DICT = make_dict(ANDROID_LIBRARY_USE_AOSP_AIDL_COMPILER_ALLOWLIST) ANDROID_LOCAL_TEST_JDK_STS_FALLBACK_DICT = make_dict(ANDROID_LOCAL_TEST_JDK_STS_FALLBACK) @@ -371,6 +379,7 @@ def matches(fqn, dct): acls = struct( get_android_archive_duplicate_class_allowlist = _get_android_archive_duplicate_class_allowlist, get_android_archive_exposed_package_allowlist = _get_android_archive_exposed_package_allowlist, + get_min_sdk_floor = _get_min_sdk_floor, in_aar_import_deps_checker = _in_aar_import_deps_checker, in_aar_import_explicit_exports_manifest = _in_aar_import_explicit_exports_manifest, in_aar_import_exports_r_java = _in_aar_import_exports_r_java, @@ -412,7 +421,6 @@ acls = struct( in_android_instrumentation_test_prebuilt_test_apk = _in_android_instrumentation_test_prebuilt_test_apk, in_baseline_profiles_rollout = _in_baseline_profiles_rollout, in_baseline_profiles_optimizer_integration = _in_baseline_profiles_optimizer_integration, - in_enforce_min_sdk_floor_rollout = _in_enforce_min_sdk_floor_rollout, in_android_apk_to_bundle_features = _in_android_apk_to_bundle_features, in_android_local_test_jdk_sts_rollout = _in_android_local_test_jdk_sts_rollout, in_shared_library_resource_linking_allowlist = _in_shared_library_resource_linking_allowlist, diff --git a/rules/acls/enforce_min_sdk_floor_rollout.bzl b/rules/acls/min_sdk_floors.bzl index 94643eb..4dfe044 100644 --- a/rules/acls/enforce_min_sdk_floor_rollout.bzl +++ b/rules/acls/min_sdk_floors.bzl @@ -1,4 +1,4 @@ -# Copyright 2022 The Bazel Authors. All rights reserved. +# Copyright 2023 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. @@ -12,11 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Rollout list for enabling enforce min SDK floor.""" +"""Mapping of minSdkVersion floors to packages. -ENFORCE_MIN_SDK_FLOOR_ROLLOUT = [ - "//:__subpackages__", -] +Starlark dictionaries maintain insertion order. It is expected that the union of all lists will +cover the entire depot. +""" -ENFORCE_MIN_SDK_FLOOR_FALLBACK = [ -] +MIN_SDK_FLOORS = { + 19: [ + "//:__subpackages__", + ], + 14: [ + "//:__subpackages__", + ], +} diff --git a/rules/android_application/android_application_rule.bzl b/rules/android_application/android_application_rule.bzl index a2c9b70..d7c15c2 100644 --- a/rules/android_application/android_application_rule.bzl +++ b/rules/android_application/android_application_rule.bzl @@ -261,8 +261,8 @@ def _impl(ctx): 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, + bundletool_module_builder = + get_android_toolchain(ctx).bundletool_module_builder.files_to_run, ) metadata = dict() diff --git a/rules/android_binary_internal/attrs.bzl b/rules/android_binary_internal/attrs.bzl index 9a2df04..e09f3e1 100644 --- a/rules/android_binary_internal/attrs.bzl +++ b/rules/android_binary_internal/attrs.bzl @@ -14,16 +14,17 @@ """Attributes.""" +load("//rules:android_neverlink_aspect.bzl", "android_neverlink_aspect") load( "//rules:attrs.bzl", _attrs = "attrs", ) +load("//rules:dex_desugar_aspect.bzl", "dex_desugar_aspect") load( "//rules:native_deps.bzl", "split_config_aspect", ) load("//rules:providers.bzl", "StarlarkApkInfo") -load("//rules:dex_desugar_aspect.bzl", "dex_desugar_aspect") def make_deps(allow_rules, providers, aspects): return attr.label_list( @@ -51,6 +52,7 @@ DEPS_PROVIDERS = [ DEPS_ASPECTS = [ dex_desugar_aspect, + android_neverlink_aspect, ] ATTRS = _attrs.replace( diff --git a/rules/android_binary_internal/impl.bzl b/rules/android_binary_internal/impl.bzl index a1e42df..0c156de 100644 --- a/rules/android_binary_internal/impl.bzl +++ b/rules/android_binary_internal/impl.bzl @@ -31,7 +31,7 @@ load( "ProviderInfo", "processing_pipeline", ) -load("//rules:proguard.bzl", "proguard", proguard_testing = "testing") +load("//rules:proguard.bzl", "proguard") load("//rules:providers.bzl", "StarlarkAndroidDexInfo", "StarlarkApkInfo") load("//rules:resources.bzl", _resources = "resources") load( @@ -53,7 +53,7 @@ def _process_manifest(ctx, **unused_ctxs): ctx, manifest = ctx.file.manifest, manifest_values = ctx.attr.manifest_values, - floor = _resources.DEPOT_MIN_SDK_FLOOR if (_is_test_binary(ctx) and acls.in_enforce_min_sdk_floor_rollout(str(ctx.label))) else 0, + floor = acls.get_min_sdk_floor(str(ctx.label)) if _is_test_binary(ctx) else 0, enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, ) @@ -109,7 +109,7 @@ def _validate_manifest(ctx, packaged_resources_ctx, **unused_ctxs): manifest_validation_ctx = _resources.validate_min_sdk( ctx, manifest = packaged_resources_ctx.processed_manifest, - floor = _resources.DEPOT_MIN_SDK_FLOOR if acls.in_enforce_min_sdk_floor_rollout(str(ctx.label)) else 0, + floor = acls.get_min_sdk_floor(str(ctx.label)), enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, ) @@ -260,7 +260,7 @@ def _process_dex(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, proto_ctx, dep main_dex_classes = get_android_sdk(ctx).main_dex_classes, main_dex_list_opts = ctx.attr.main_dex_list_opts, main_dex_proguard_spec = packaged_resources_ctx.main_dex_proguard_config, - proguard_specs = list(ctx.attr.main_dex_proguard_specs), + proguard_specs = list(ctx.files.main_dex_proguard_specs), shrinked_android_jar = get_android_sdk(ctx).shrinked_android_jar, main_dex_list_creator = get_android_sdk(ctx).main_dex_list_creator, legacy_main_dex_list_generator = @@ -389,11 +389,16 @@ def _process_dex(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, proto_ctx, dep dex_info = AndroidDexInfo( deploy_jar = deploy_jar, + filtered_deploy_jar = deploy_ctx.filtered_deploy_jar, final_classes_dex_zip = final_classes_dex_zip, final_proguard_output_map = final_proguard_output_map, - java_resource_jar = deploy_jar, + java_resource_jar = binary_jar if ctx.fragments.android.get_java_resources_from_optimized_jar else deploy_jar, ) providers.append(dex_info) + providers.append(AndroidPreDexJarInfo(binary_jar)) + + if postprocessing_output_map: + providers.append(ProguardMappingInfo(postprocessing_output_map)) return ProviderInfo( name = "dex_ctx", @@ -405,7 +410,7 @@ def _process_dex(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, proto_ctx, dep ) def _process_deploy_jar(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, build_info_ctx, proto_ctx, **_unused_ctxs): - deploy_jar, desugar_dict = None, {} + deploy_jar, filtered_deploy_jar, desugar_dict = None, None, {} if acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label)): java_toolchain = common.get_java_toolchain(ctx) @@ -456,7 +461,9 @@ def _process_deploy_jar(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, build_i if _is_instrumentation(ctx): filtered_deploy_jar = ctx.actions.declare_file(ctx.label.name + "_migrated_filtered.jar") - filter_jar = ctx.attr.instruments[AndroidPreDexJarInfo].pre_dex_jar + + # TODO(b/303286042): Use AndroidPreDexInfo.pre_dex_jar to be the filter_jar + filter_jar = ctx.attr.instruments[ApkInfo].deploy_jar common.filter_zip_exclude( ctx, output = filtered_deploy_jar, @@ -474,6 +481,7 @@ def _process_deploy_jar(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, build_i value = struct( deploy_jar = deploy_jar, desugar_dict = desugar_dict, + filtered_deploy_jar = filtered_deploy_jar, providers = [], ), ) @@ -639,7 +647,7 @@ def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused ) # Validate attributes and lockdown lists - if ctx.file.proguard_apply_mapping and not acls.in_allow_proguard_apply_mapping(ctx.label): + if ctx.file.proguard_apply_mapping and not acls.in_allow_proguard_apply_mapping(str(ctx.label)): fail("proguard_apply_mapping is not supported") if ctx.file.proguard_apply_mapping and not ctx.files.proguard_specs: fail("proguard_apply_mapping can only be used when proguard_specs is set") @@ -650,7 +658,6 @@ def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused proguard_specs_for_manifest = [packaged_resources_ctx.resource_minsdk_proguard_config] if packaged_resources_ctx.resource_minsdk_proguard_config else [], ) has_proguard_specs = bool(proguard_specs) - proguard_output = struct() is_resource_shrinking_enabled = _resources.is_resource_shrinking_enabled( ctx.attr.shrink_resources, @@ -684,8 +691,11 @@ def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused proguard_seeds = ctx.actions.declare_file(ctx.label.name + "_migrated_proguard.seeds") proguard_usage = ctx.actions.declare_file(ctx.label.name + "_migrated_proguard.usage") - startup_profile = bp_ctx.baseline_profile_output.startup_profile if bp_ctx.baseline_profile_output else None - baseline_profile = bp_ctx.baseline_profile_output.baseline_profile if bp_ctx.baseline_profile_output else None + startup_profile = None + baseline_profile = None + if acls.in_baseline_profiles_optimizer_integration(str(ctx.label)) and bp_ctx.baseline_profile_output: + startup_profile = bp_ctx.baseline_profile_output.startup_profile + baseline_profile = bp_ctx.baseline_profile_output.baseline_profile proguard_output = proguard.apply_proguard( ctx, @@ -702,20 +712,6 @@ def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused proguard_tool = get_android_sdk(ctx).proguard, ) - providers = [] - if proguard_output: - providers.append(proguard_testing.ProguardOutputInfo( - input_jar = deploy_ctx.deploy_jar, - output_jar = proguard_output.output_jar, - mapping = proguard_output.mapping, - seeds = proguard_output.seeds, - usage = proguard_output.usage, - library_jar = proguard_output.library_jar, - config = proguard_output.config, - baseline_profile_rewritten = proguard_output.baseline_profile_rewritten, - startup_profile_rewritten = proguard_output.startup_profile_rewritten, - )) - use_resource_shrinking = is_resource_shrinking_enabled and has_proguard_specs shrunk_resource_output = None if use_resource_shrinking: @@ -730,7 +726,6 @@ def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, host_javabase = common.get_host_javabase(ctx), ) - providers.append(shrunk_resource_output) optimized_resource_output = _resources.optimize( ctx, @@ -741,7 +736,26 @@ def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, host_javabase = common.get_host_javabase(ctx), ) - providers.append(optimized_resource_output) + + providers = [] + providers.append( + AndroidOptimizationInfo( + optimized_jar = proguard_output.output_jar, + mapping = proguard_output.mapping, + seeds = proguard_output.seeds, + library_jar = proguard_output.library_jar, + config = proguard_output.config, + proto_mapping = proguard_output.proto_mapping, + rewritten_startup_profile = proguard_output.startup_profile_rewritten, + rewriten_merged_baseline_profile = proguard_output.baseline_profile_rewritten, + optimized_resource_apk = optimized_resource_output.resources_apk, + shrunk_resource_apk = shrunk_resource_output.resources_apk if shrunk_resource_output else None, + shrunk_resource_zip = shrunk_resource_output.resources_zip if shrunk_resource_output else None, + resource_shrinker_log = shrunk_resource_output.shrinker_log if shrunk_resource_output else None, + resource_optimization_config = shrunk_resource_output.optimization_config if shrunk_resource_output else None, + resource_path_shortening_map = optimized_resource_output.path_shortening_map, + ), + ) return ProviderInfo( name = "optimize_ctx", diff --git a/rules/android_binary_internal/r8.bzl b/rules/android_binary_internal/r8.bzl index 90c91c3..0ace549 100644 --- a/rules/android_binary_internal/r8.bzl +++ b/rules/android_binary_internal/r8.bzl @@ -92,6 +92,7 @@ def process_r8(ctx, jvm_ctx, packaged_resources_ctx, build_info_ctx, **_unused_c inputs = [android_jar, deploy_jar] + proguard_specs, outputs = [dexes_zip], mnemonic = "AndroidR8", + jvm_flags = ["-Xmx8G"], progress_message = "R8 Optimizing, Desugaring, and Dexing %{label}", ) diff --git a/rules/android_library/impl.bzl b/rules/android_library/impl.bzl index 5fd5af5..6ccc5a5 100644 --- a/rules/android_library/impl.bzl +++ b/rules/android_library/impl.bzl @@ -133,7 +133,7 @@ def _process_manifest(ctx, **unused_ctxs): manifest_ctx = _resources.bump_min_sdk( ctx, manifest = ctx.file.manifest, - floor = _resources.DEPOT_MIN_SDK_FLOOR if acls.in_enforce_min_sdk_floor_rollout(str(ctx.label)) else 0, + floor = acls.get_min_sdk_floor(str(ctx.label)), enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, ) diff --git a/rules/android_library/rule.bzl b/rules/android_library/rule.bzl index e36bdd3..cd7af67 100644 --- a/rules/android_library/rule.bzl +++ b/rules/android_library/rule.bzl @@ -140,7 +140,8 @@ def make_rule( attrs = _ATTRS, implementation = _impl, outputs = _outputs, - additional_toolchains = []): + additional_toolchains = [], + additional_providers = []): """Makes the rule. Args: @@ -148,6 +149,7 @@ def make_rule( implementation: A function. The rule's implementation method. outputs: A dict, function, or None. The rule's outputs. additional_toolchains: A list. Additional toolchains passed to pass to rule(toolchains). + additional_providers: A list. Additional providers passed to pass to rule(providers). Returns: A rule. @@ -167,7 +169,7 @@ def make_rule( AndroidLibraryResourceClassJarProvider, AndroidNativeLibsInfo, JavaInfo, - ], + ] + additional_providers, outputs = outputs, toolchains = [ "//toolchains/android:toolchain_type", diff --git a/rules/android_local_test/impl.bzl b/rules/android_local_test/impl.bzl index 1606e18..3a6221f 100644 --- a/rules/android_local_test/impl.bzl +++ b/rules/android_local_test/impl.bzl @@ -61,7 +61,7 @@ def _process_manifest(ctx, java_package, **_unused_sub_ctxs): manifest_values = resources.process_manifest_values( ctx, ctx.attr.manifest_values, - resources.DEPOT_MIN_SDK_FLOOR, + acls.get_min_sdk_floor(str(ctx.label)), ) if ctx.file.manifest == None: # No manifest provided, generate one @@ -70,7 +70,7 @@ def _process_manifest(ctx, java_package, **_unused_sub_ctxs): ctx, out_manifest = manifest, java_package = java_package, - min_sdk_version = manifest_values.get("minSdkVersion", 16), # minsdk supported by robolectric framework + min_sdk_version = int(manifest_values.get("minSdkVersion", 16)), # minsdk supported by robolectric framework ) manifest_ctx = struct(processed_manifest = manifest, processed_manifest_values = manifest_values) else: @@ -78,7 +78,7 @@ def _process_manifest(ctx, java_package, **_unused_sub_ctxs): ctx, manifest = ctx.file.manifest, manifest_values = ctx.attr.manifest_values, - floor = resources.DEPOT_MIN_SDK_FLOOR if acls.in_enforce_min_sdk_floor_rollout(str(ctx.label)) else 0, + floor = acls.get_min_sdk_floor(str(ctx.label)), enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, ) diff --git a/rules/android_neverlink_aspect.bzl b/rules/android_neverlink_aspect.bzl index 1dab304..672bd3a 100644 --- a/rules/android_neverlink_aspect.bzl +++ b/rules/android_neverlink_aspect.bzl @@ -18,6 +18,7 @@ Used for determining the -libraryjars argument for Proguard. The compile-time cl unsufficient here as those are ijars. """ +load("//rules:acls.bzl", "acls") load( "//rules:utils.bzl", "utils", @@ -33,6 +34,9 @@ StarlarkAndroidNeverlinkInfo = provider( _ATTRS = ["deps", "exports", "runtime_deps", "binary_under_test", "$instrumentation_test_runner"] def _android_neverlink_aspect_impl(target, ctx): + if not acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label)): + return [] + # Only run on Android targets if "android" not in getattr(ctx.rule.attr, "constraints", "") and not ctx.rule.kind.startswith("android_"): return [] diff --git a/rules/android_sandboxed_sdk/android_binary_with_sandboxed_sdks_macro.bzl b/rules/android_sandboxed_sdk/android_binary_with_sandboxed_sdks_macro.bzl index 95b8b80..1499e98 100644 --- a/rules/android_sandboxed_sdk/android_binary_with_sandboxed_sdks_macro.bzl +++ b/rules/android_sandboxed_sdk/android_binary_with_sandboxed_sdks_macro.bzl @@ -14,19 +14,20 @@ """Bazel rule for defining an Android binary that depends on sandboxed SDKs.""" -load(":providers.bzl", "AndroidSandboxedSdkBundleInfo") load("//rules:acls.bzl", "acls") load("//rules:bundletool.bzl", _bundletool = "bundletool") load("//rules:common.bzl", _common = "common") -load( - "//rules:utils.bzl", - _get_android_toolchain = "get_android_toolchain", -) load("//rules:java.bzl", _java = "java") load( "//rules:sandboxed_sdk_toolbox.bzl", _sandboxed_sdk_toolbox = "sandboxed_sdk_toolbox", ) +load( + "//rules:utils.bzl", + "utils", + _get_android_toolchain = "get_android_toolchain", +) +load(":providers.bzl", "AndroidArchivedSandboxedSdkInfo", "AndroidSandboxedSdkBundleInfo") def _gen_sdk_dependencies_manifest_impl(ctx): manifest = ctx.actions.declare_file(ctx.label.name + "_sdk_dep_manifest.xml") @@ -34,12 +35,17 @@ def _gen_sdk_dependencies_manifest_impl(ctx): bundle[AndroidSandboxedSdkBundleInfo].sdk_info.sdk_module_config for bundle in ctx.attr.sdk_bundles ] + sdk_archives = [ + archive[AndroidArchivedSandboxedSdkInfo].asar + for archive in ctx.attr.sdk_archives + ] _sandboxed_sdk_toolbox.generate_sdk_dependencies_manifest( ctx, output = manifest, manifest_package = ctx.attr.package, sdk_module_configs = module_configs, + sdk_archives = sdk_archives, debug_key = ctx.file.debug_key, sandboxed_sdk_toolbox = _get_android_toolchain(ctx).sandboxed_sdk_toolbox.files_to_run, host_javabase = _common.get_host_javabase(ctx), @@ -59,6 +65,11 @@ _gen_sdk_dependencies_manifest = rule( [AndroidSandboxedSdkBundleInfo], ], ), + sdk_archives = attr.label_list( + providers = [ + [AndroidArchivedSandboxedSdkInfo], + ], + ), debug_key = attr.label( allow_single_file = True, default = Label("//tools/android:debug_keystore"), @@ -78,8 +89,34 @@ _gen_sdk_dependencies_manifest = rule( def _android_binary_with_sandboxed_sdks_impl(ctx): sdk_apks = [] + for idx, sdk_archive in enumerate(ctx.attr.sdk_archives): + # Bundletool is rejecting ASARs when creating APKs, but since the formats are similar enough + # for this command we can just rename the file. + # TODO b/294970460) -- Remove this extra copy once Bundletool is updated with ASAR support + # in build_sdk_apks. Their work is being tracked in b/228176834. + renamed_sdk_archive = ctx.actions.declare_file("%s/renamed_sdk_archive/%s.asb" % ( + ctx.label.name, + idx, + )) + utils.copy_file(ctx, sdk_archive[AndroidArchivedSandboxedSdkInfo].asar, renamed_sdk_archive) + + apk_out = ctx.actions.declare_file("%s/sdk_archive_dep_apks/%s.apk" % ( + ctx.label.name, + idx, + )) + _bundletool.build_sdk_apks( + ctx, + out = apk_out, + aapt2 = _get_android_toolchain(ctx).aapt2.files_to_run, + sdk_bundle = renamed_sdk_archive, + debug_key = ctx.file.debug_key, + bundletool = _get_android_toolchain(ctx).bundletool.files_to_run, + host_javabase = _common.get_host_javabase(ctx), + ) + sdk_apks.append(apk_out) + for idx, sdk_bundle_target in enumerate(ctx.attr.sdk_bundles): - apk_out = ctx.actions.declare_file("%s/sdk_dep_apks/%s.apk" % ( + apk_out = ctx.actions.declare_file("%s/sdk_bundle_dep_apks/%s.apk" % ( ctx.label.name, idx, )) @@ -137,6 +174,11 @@ _android_binary_with_sandboxed_sdks = rule( [AndroidSandboxedSdkBundleInfo], ], ), + sdk_archives = attr.label_list( + providers = [ + [AndroidArchivedSandboxedSdkInfo], + ], + ), _install_script_template = attr.label( allow_single_file = True, default = ":install_script.sh_template", @@ -150,6 +192,7 @@ _android_binary_with_sandboxed_sdks = rule( implementation = _android_binary_with_sandboxed_sdks_impl, toolchains = [ "//toolchains/android:toolchain_type", + "@bazel_tools//tools/jdk:toolchain_type", ], ) @@ -171,7 +214,8 @@ def android_binary_with_sandboxed_sdks_macro( fail("%s is not allowed to use the android_binary_with_sandboxed_sdks macro." % fully_qualified_name) - sdk_bundles = attrs.pop("sdk_bundles", None) + sdk_bundles = attrs.pop("sdk_bundles", []) + sdk_archives = attrs.pop("sdk_archives", []) debug_keystore = getattr(attrs, "debug_keystore", None) bin_package = _java.resolve_package_from_label( @@ -185,6 +229,10 @@ def android_binary_with_sandboxed_sdks_macro( name = sdk_dependencies_manifest_name, package = "%s.internalsdkdependencies" % bin_package, sdk_bundles = sdk_bundles, + sdk_archives = sdk_archives, + testonly = attrs.get("testonly", False), + tags = attrs.get("tags", []), + visibility = attrs.get("visibility", None), ) # Use the manifest in a normal android_library. This will later be added as a dependency to the @@ -194,6 +242,10 @@ def android_binary_with_sandboxed_sdks_macro( name = sdk_dependencies_lib_name, exports_manifest = 1, manifest = ":%s" % sdk_dependencies_manifest_name, + testonly = attrs.get("testonly", False), + tags = attrs.get("tags", []), + transitive_configs = attrs.get("transitive_configs", []), + visibility = attrs.get("visibility", None), ) deps = attrs.pop("deps", []) deps.append(":%s" % sdk_dependencies_lib_name) @@ -210,6 +262,10 @@ def android_binary_with_sandboxed_sdks_macro( _android_binary_with_sandboxed_sdks( name = name, sdk_bundles = sdk_bundles, + sdk_archives = sdk_archives, debug_key = debug_keystore, internal_android_binary = bin_label, + testonly = attrs.get("testonly", False), + tags = attrs.get("tags", []), + visibility = attrs.get("visibility", None), ) diff --git a/rules/android_sdk_repository/helper.bzl b/rules/android_sdk_repository/helper.bzl index 43f715f..3a2eba4 100644 --- a/rules/android_sdk_repository/helper.bzl +++ b/rules/android_sdk_repository/helper.bzl @@ -235,6 +235,8 @@ def create_android_sdk_rules( ], ) + create_dummy_sdk_toolchain() + native.alias( name = "org_apache_http_legacy", actual = ":org_apache_http_legacy-%d" % default_api_level, @@ -504,4 +506,45 @@ def create_system_images_filegroups(system_image_dirs): native.filegroup( name = "%s_qemu2_extra" % name, srcs = [], - ) + ) # buildifier: disable=unnamed-macro + +# This is a dummy sdk toolchain that matches any platform. It will +# fail if actually resolved to and used. +# buildifier: disable=unnamed-macro +def create_dummy_sdk_toolchain(): + "Create a dummy SDK for fallback builds" + + native.toolchain( + name = "sdk-dummy-toolchain", + toolchain = ":sdk-dummy", + toolchain_type = "@bazel_tools//tools/android:sdk_toolchain_type", + ) + + native.filegroup(name = "jar-filegroup", srcs = ["dummy.jar"]) + + native.genrule( + name = "genrule", + srcs = [], + outs = ["empty.sh"], + cmd = "echo '' >> \"$@\"", + executable = 1, + ) + + native.sh_binary(name = "empty-binary", srcs = [":genrule"]) + + native.android_sdk( + name = "sdk-dummy", + aapt = ":empty-binary", + adb = ":empty-binary", + aidl = ":empty-binary", + android_jar = ":jar-filegroup", + apksigner = ":empty-binary", + dx = ":empty-binary", + framework_aidl = "dummy.jar", + main_dex_classes = "dummy.jar", + main_dex_list_creator = ":empty-binary", + proguard = ":empty-binary", + shrinked_android_jar = "dummy.jar", + tags = ["__ANDROID_RULES_MIGRATION__"], + zipalign = ":empty-binary", + ) diff --git a/rules/attrs.bzl b/rules/attrs.bzl index 6a03d2d..a72fd4f 100644 --- a/rules/attrs.bzl +++ b/rules/attrs.bzl @@ -267,6 +267,12 @@ ANDROID_SDK_ATTRS = dict( mandatory = True, ), build_tools_version = attr.string(), + dexdump = attr.label( + allow_files = True, + cfg = "exec", + executable = True, + mandatory = False, + ), dx = attr.label( allow_files = True, cfg = "exec", diff --git a/rules/bundletool.bzl b/rules/bundletool.bzl index b0651ec..a933211 100644 --- a/rules/bundletool.bzl +++ b/rules/bundletool.bzl @@ -322,71 +322,17 @@ def _proto_apk_to_module( ctx, out = None, proto_apk = None, - zip = None, - unzip = None): - # TODO(timpeut): migrate this to Bundletool module builder. - 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}" -Drq0 . -""" % ( - unzip.executable.path, - zip.executable.path, - proto_apk.path, - out.path, - ), - tools = [zip, unzip], - arguments = [], + bundletool_module_builder = None): + args = ctx.actions.args() + args.add("--internal_apk_path", proto_apk) + args.add("--output_module_path", out) + ctx.actions.run( inputs = [proto_apk], outputs = [out], - mnemonic = "Rebundle", - progress_message = "Rebundle to %s" % out.short_path, + executable = bundletool_module_builder, + arguments = [args], + mnemonic = "BuildAppModule", + progress_message = "Building AAB zip module %s" % out.short_path, toolchain = ANDROID_TOOLCHAIN_TYPE, ) diff --git a/rules/busybox.bzl b/rules/busybox.bzl index ce36d52..bcbb880 100644 --- a/rules/busybox.bzl +++ b/rules/busybox.bzl @@ -1150,8 +1150,8 @@ def _optimize( host_javabase: Target. The host javabase. """ - output_files = [] - input_files = [] + output_files = [out_apk] + input_files = [in_apk] args = ctx.actions.args() args.use_param_file("@%s") @@ -1168,7 +1168,6 @@ def _optimize( args.add("--resources-config-path", resource_optimization_config) input_files.append(resource_optimization_config) args.add("-o", out_apk) - output_files.append(out_apk) args.add(in_apk) _java.run( diff --git a/rules/dex.bzl b/rules/dex.bzl index 4ab7704..a3e2620 100644 --- a/rules/dex.bzl +++ b/rules/dex.bzl @@ -50,12 +50,7 @@ def _process_incremental_dexing( incremental_dexopts = _filter_dexopts(dexopts, ctx.fragments.android.get_dexopts_supported_in_incremental_dexing) inclusion_filter_jar = proguarded_jar if not proguarded_jar: - dex_archives_list = info.dex_archives_dict.get("".join(incremental_dexopts), depset()).to_list() - dex_archives = _to_dexed_classpath( - dex_archives_dict = {d.jar: d.dex for d in dex_archives_list}, - classpath = _filter(java_info.transitive_runtime_jars.to_list(), excludes = _get_library_r_jars(deps)), - runtime_jars = runtime_jars, - ) + dex_archives = [] for jar in runtime_jars: dex_archive = _get_dx_artifact(ctx, jar.basename + ".dex.zip") _dex( @@ -68,6 +63,11 @@ def _process_incremental_dexing( toolchain_type = toolchain_type, ) dex_archives.append(dex_archive) + dex_archives += _to_dexed_classpath( + dex_archives_dict = {d.jar: d.dex for d in info.dex_archives_dict.get("".join(incremental_dexopts), depset()).to_list()}, + classpath = _filter(java_info.transitive_runtime_jars.to_list(), excludes = _get_library_r_jars(deps)), + runtime_jars = runtime_jars, + ) else: java_resource_jar = ctx.actions.declare_file(ctx.label.name + "_files/java_resources.jar") if ctx.fragments.android.incremental_dexing_shards_after_proguard > 1: @@ -332,7 +332,7 @@ def _shard_dexes( outputs = [output], inputs = inputs, arguments = [args], - mnemonic = "ShardsForMultiDex", + mnemonic = "ShardForMultidex", progress_message = "Assembling dex files for " + ctx.label.name, use_default_shell_env = True, toolchain = toolchain_type, @@ -396,6 +396,8 @@ def _dex( dex_exec: File. The executable dex builder file. """ args = ctx.actions.args() + args.use_param_file("@%s", use_always = True) # Required for workers. + args.set_param_file_format("multiline") args.add("--input_jar", input) args.add("--output_zip", output) diff --git a/rules/dex_desugar_aspect.bzl b/rules/dex_desugar_aspect.bzl index 9d692d3..066ad1a 100644 --- a/rules/dex_desugar_aspect.bzl +++ b/rules/dex_desugar_aspect.bzl @@ -14,7 +14,7 @@ """Aspect that transitively build .dex archives and desugar jars.""" -load(":utils.bzl", _utils = "utils") +load(":utils.bzl", _get_android_sdk = "get_android_sdk", _utils = "utils") load(":dex.bzl", _dex = "dex") load(":desugar.bzl", _desugar = "desugar") load(":providers.bzl", "StarlarkAndroidDexInfo") @@ -193,8 +193,10 @@ def _get_boot_classpath(target, ctx): compilation_info = target[JavaInfo].compilation_info if compilation_info and compilation_info.boot_classpath: return compilation_info.boot_classpath - if ctx.attr._android_sdk and ctx.attr._android_sdk[AndroidSdkInfo].android_jar: - return [ctx.attr._android_sdk[AndroidSdkInfo].android_jar] + + android_jar = _get_android_sdk(ctx).android_jar + if android_jar: + return [android_jar] # This shouldn't ever be reached, but if it is, we should be clear about the error. fail("No compilation info or android jar!") @@ -249,5 +251,6 @@ dex_desugar_aspect = aspect( _attrs.ANDROID_SDK, ), fragments = ["android"], + toolchains = ["//toolchains/android_sdk:toolchain_type"], required_aspect_providers = [[JavaInfo]], ) diff --git a/rules/instrumented_app_info_aspect.bzl b/rules/instrumented_app_info_aspect.bzl new file mode 100644 index 0000000..0d457c6 --- /dev/null +++ b/rules/instrumented_app_info_aspect.bzl @@ -0,0 +1,26 @@ +# 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. + +"""This aspect is used to collect providers from an instrumented android_binary.""" + +load("//rules:providers.bzl", "InstrumentedAppInfo") + +def _impl(unused_target, ctx): + if hasattr(ctx.rule.attr, "instruments") and ctx.rule.attr.instruments and AndroidIdeInfo in ctx.rule.attr.instruments: + return [InstrumentedAppInfo(android_ide_info = ctx.rule.attr.instruments[AndroidIdeInfo])] + return [] + +instrumented_app_info_aspect = aspect( + implementation = _impl, +) diff --git a/rules/native_deps.bzl b/rules/native_deps.bzl index d503389..1500c47 100644 --- a/rules/native_deps.bzl +++ b/rules/native_deps.bzl @@ -179,7 +179,7 @@ def _filter_unique_shared_libs(linked_libs, cc_info): "Each library in the transitive closure must have a " + "unique basename to avoid name collisions when packaged into " + "an apk, but two libraries have the basename '" + basename + - "': " + artifact + " and " + old_artifact + ( + "': " + str(artifact) + " and " + str(old_artifact) + ( " (the library already seen by this target)" if old_artifact in linked_libs else "" ), ) @@ -237,8 +237,16 @@ def _is_shared_library(lib_artifact): return True return False -def _get_build_info(ctx): - return cc_common.get_build_info(ctx) +def _is_stamping_enabled(ctx): + if ctx.configuration.is_tool_configuration(): + return 0 + return getattr(ctx.attr, "stamp", 0) + +def _get_build_info(ctx, cc_toolchain): + if _is_stamping_enabled(ctx): + return cc_toolchain.build_info_files().non_redacted_build_info_files.to_list() + else: + return cc_toolchain.build_info_files().redacted_build_info_files.to_list() def _get_shared_native_deps_path( linker_inputs, @@ -294,14 +302,19 @@ def _link_native_deps_if_present(ctx, cc_info, cc_toolchain, build_config, actua build_config.bin_dir, ) - link_opts = cc_info.linking_context.user_link_flags + linker_inputs = cc_info.linking_context.linker_inputs.to_list() + + link_opts = [] + for linker_input in linker_inputs: + for flag in linker_input.user_link_flags: + link_opts.append(flag) linkstamps = [] - for input in cc_info.linking_context.linker_inputs.to_list(): - linkstamps.extend(input.linkstamps) + for linker_input in linker_inputs: + linkstamps.extend(linker_input.linkstamps) linkstamps_dict = {linkstamp: None for linkstamp in linkstamps} - build_info_artifacts = _get_build_info(ctx) if linkstamps_dict else [] + build_info_artifacts = _get_build_info(ctx, cc_toolchain) if linkstamps_dict else [] requested_features = ["static_linking_mode", "native_deps_link"] requested_features.extend(ctx.features) if not "legacy_whole_archive" in ctx.disabled_features: diff --git a/rules/proguard.bzl b/rules/proguard.bzl index d5caabb..9599658 100644 --- a/rules/proguard.bzl +++ b/rules/proguard.bzl @@ -30,23 +30,6 @@ _ProguardSpecContextInfo = provider( ), ) -_ProguardOutputInfo = provider( - doc = "Temporary provider to hold all proguard outputs. Will be replaced by a native " + - "provider. Useful for testing.", - fields = dict( - input_jar = "The input program jar, unoptimized", - output_jar = "The optimized output jar", - mapping = "Output proguard map", - proto_mapping = "Output proto mapping", - seeds = "Output seeds", - usage = "Output usage", - library_jar = "Merged library jar", - config = "Output config", - baseline_profile_rewritten = "Optimized baseline profile", - startup_profile_rewritten = "Optimized startup profile", - ), -) - def _validate_proguard_spec( ctx, out_validated_proguard_spec, @@ -369,20 +352,32 @@ def _apply_proguard( proguard_tool: FilesToRun. The proguard executable. Returns: - A struct of proguard outputs, corresponding to the fields in ProguardOutputInfo. + A struct of proguard outputs. """ if not proguard_specs: + outputs = _get_proguard_output( + ctx, + proguard_output_jar = proguard_output_jar, + proguard_seeds = None, + proguard_usage = None, + proguard_output_map = proguard_output_map, + combined_library_jar = None, + startup_profile_rewritten = None, + baseline_profile_rewritten = None, + ) + # Fail at execution time if these artifacts are requested, to avoid issue where outputs are # declared without having any proguard specs. This can happen if specs is a select() that # resolves to an empty list. _fail_action( ctx, - proguard_output_jar, - proguard_output_map, + outputs.output_jar, + outputs.mapping, + outputs.config, proguard_seeds, proguard_usage, ) - return None + return outputs library_jar_list = [get_android_sdk(ctx).android_jar] if ctx.fragments.android.desugar_java8: @@ -416,11 +411,19 @@ def _get_proguard_output( startup_profile_rewritten, baseline_profile_rewritten): """Helper method to get a struct of all proguard outputs.""" + + # Proto Output Map is currently empty from ProGuard. + proguard_output_proto_map = None + if proguard_output_map: + proguard_output_proto_map = _get_proguard_temp_artifact(ctx, "_proguard.pbmap") + ctx.actions.write(proguard_output_proto_map, content = "") + config_output = _get_proguard_temp_artifact(ctx, "_proguard.config") return struct( output_jar = proguard_output_jar, mapping = proguard_output_map, + proto_mapping = proguard_output_proto_map, seeds = proguard_seeds, usage = proguard_usage, library_jar = combined_library_jar, @@ -575,7 +578,7 @@ def _create_optimization_actions( proguard_specs, proguard_mapping, i, - "_ACTION_%s_OF_%s_" % (j, bytecode_optimization_pass_actions), + "_ACTION_%s_OF_%s" % (j, bytecode_optimization_pass_actions), mnemonic, last_stage_output, optimizer_target, @@ -678,5 +681,4 @@ testing = struct( collect_transitive_proguard_specs = _collect_transitive_proguard_specs, optimization_action = _optimization_action, ProguardSpecContextInfo = _ProguardSpecContextInfo, - ProguardOutputInfo = _ProguardOutputInfo, ) diff --git a/rules/resources.bzl b/rules/resources.bzl index 3f745b9..2ceecc0 100644 --- a/rules/resources.bzl +++ b/rules/resources.bzl @@ -32,9 +32,6 @@ load( _log = "log", ) -# Depot-wide min SDK floor -_DEPOT_MIN_SDK_FLOOR = 14 - _RESOURCE_FOLDER_TYPES = [ "anim", "animator", @@ -195,12 +192,12 @@ def _generate_dummy_manifest( ctx, out_manifest = None, java_package = None, - min_sdk_version = _DEPOT_MIN_SDK_FLOOR): + min_sdk_version = 0): content = """<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="%s">""" % (java_package or "com.default") - min_sdk_version = max(min_sdk_version, _DEPOT_MIN_SDK_FLOOR) + min_sdk_version = max(min_sdk_version, acls.get_min_sdk_floor(str(ctx.label))) content = content + """ <uses-sdk android:minSdkVersion="%s" />""" % min_sdk_version @@ -1080,7 +1077,7 @@ def _validate_resources(resource_files = None): if res_type not in _RESOURCE_FOLDER_TYPES: fail(_INCORRECT_RESOURCE_LAYOUT_ERROR % resource_file) -def _process_manifest_values(ctx, manifest_values, min_sdk_floor = _DEPOT_MIN_SDK_FLOOR): +def _process_manifest_values(ctx, manifest_values, min_sdk_floor): expanded_manifest_values = utils.expand_make_vars(ctx, manifest_values) if _MIN_SDK_VERSION in expanded_manifest_values and min_sdk_floor > 0: expanded_manifest_values[_MIN_SDK_VERSION] = str( @@ -1092,7 +1089,7 @@ def _bump_min_sdk( ctx, manifest = None, manifest_values = None, - floor = _DEPOT_MIN_SDK_FLOOR, + floor = None, enforce_min_sdk_floor_tool = None): """Bumps the min SDK attribute of AndroidManifest to the floor. @@ -1109,6 +1106,9 @@ def _bump_min_sdk( """ manifest_ctx = {} + if floor == None: + fail("Missing required `floor` in bump_min_sdk") + if manifest_values != None: manifest_ctx[_PROCESSED_MANIFEST_VALUES] = _process_manifest_values( ctx, @@ -1453,7 +1453,7 @@ def _process_starlark( ctx, out_manifest = generated_manifest, java_package = java_package if java_package else ctx.label.package.replace("/", "."), - min_sdk_version = _DEPOT_MIN_SDK_FLOOR, + min_sdk_version = acls.get_min_sdk_floor(str(ctx.label)), ) r_txt = ctx.actions.declare_file( "_migrated/" + ctx.label.name + "_symbols/R.txt", @@ -2101,9 +2101,6 @@ resources = struct( validate_min_sdk = _validate_min_sdk, shrink = _shrink, optimize = _optimize, - - # Exposed for android_library, aar_import, and android_binary - DEPOT_MIN_SDK_FLOOR = _DEPOT_MIN_SDK_FLOOR, ) testing = struct( diff --git a/rules/sandboxed_sdk_toolbox.bzl b/rules/sandboxed_sdk_toolbox.bzl index 1c1a5dd..933212d 100644 --- a/rules/sandboxed_sdk_toolbox.bzl +++ b/rules/sandboxed_sdk_toolbox.bzl @@ -128,6 +128,7 @@ def _generate_sdk_dependencies_manifest( output = None, manifest_package = None, sdk_module_configs = None, + sdk_archives = None, debug_key = None, sandboxed_sdk_toolbox = None, host_javabase = None): @@ -141,14 +142,21 @@ def _generate_sdk_dependencies_manifest( output: File where the final manifest will be written. manifest_package: The package used in the manifest. sdk_module_configs: List of SDK Module config JSON files with SDK packages and versions. - debug_key: Keystore that will later be used to sign the SDK APKs. It's expected to be a + sdk_archives: List of SDK archives, as ASAR files. They will also be listed as dependencies. + debug_key: Debug keystore that will later be used to sign the SDK APKs. sandboxed_sdk_toolbox: Toolbox executable files. host_javabase: Javabase used to run the toolbox. """ + inputs = [debug_key] args = ctx.actions.args() args.add("generate-sdk-dependencies-manifest") args.add("--manifest-package", manifest_package) - args.add("--sdk-module-configs", ",".join([config.path for config in sdk_module_configs])) + if sdk_module_configs: + args.add("--sdk-module-configs", ",".join([config.path for config in sdk_module_configs])) + inputs.extend(sdk_module_configs) + if sdk_archives: + args.add("--sdk-archives", ",".join([archive.path for archive in sdk_archives])) + inputs.extend(sdk_archives) args.add("--debug-keystore", debug_key) args.add("--debug-keystore-pass", "android") args.add("--debug-keystore-alias", "androiddebugkey") @@ -158,7 +166,7 @@ def _generate_sdk_dependencies_manifest( host_javabase = host_javabase, executable = sandboxed_sdk_toolbox, arguments = [args], - inputs = sdk_module_configs + [debug_key], + inputs = inputs, outputs = [output], mnemonic = "GenSdkDepManifest", progress_message = "Generate SDK dependencies manifest %s" % output.short_path, diff --git a/src/tools/ak/rjar/rjar.go b/src/tools/ak/rjar/rjar.go index c95dea8..fca8c76 100644 --- a/src/tools/ak/rjar/rjar.go +++ b/src/tools/ak/rjar/rjar.go @@ -240,6 +240,11 @@ func compileRJar(srcs []string, rjar, jdk, jartool string, targetLabel string) e "--output", rjar, }...) if len(targetLabel) > 0 { + // Deal with "@//"-prefixed labels (in Bazel) + if strings.HasPrefix(targetLabel, "@//") { + targetLabel = strings.Replace(targetLabel, "@//", "//", 1) + } + args = append(args, []string{ "--target_label", targetLabel, }...) diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/config/SdkModulesConfigUtils.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/config/SdkModulesConfigUtils.java deleted file mode 100644 index e023096..0000000 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/config/SdkModulesConfigUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2023 The Bazel Authors. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.devtools.build.android.sandboxedsdktoolbox.config; - -import com.android.bundle.SdkModulesConfigOuterClass.SdkModulesConfig; -import com.android.tools.build.bundletool.model.RuntimeEnabledSdkVersionEncoder; -import com.google.protobuf.util.JsonFormat; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; - -/** Utilities for creating and extracting information from {@link SdkModulesConfig} messages. */ -public final class SdkModulesConfigUtils { - - public static SdkModulesConfig readFromJsonFile(Path configPath) { - SdkModulesConfig.Builder builder = SdkModulesConfig.newBuilder(); - try { - JsonFormat.parser().merge(Files.newBufferedReader(configPath), builder); - return builder.build(); - } catch (IOException e) { - throw new UncheckedIOException("Failed to parse SDK Module Config.", e); - } - } - - public static long getVersionMajor(SdkModulesConfig config) { - return RuntimeEnabledSdkVersionEncoder.encodeSdkMajorAndMinorVersion( - config.getSdkVersion().getMajor(), config.getSdkVersion().getMinor()); - } - - private SdkModulesConfigUtils() {} -} diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/config/BUILD b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/BUILD index cbc3f38..4f8e336 100644 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/config/BUILD +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/BUILD @@ -1,4 +1,4 @@ -# Utilities for SDK module config proto message. +# Utilities for extracting information from SDK archives and Bundle metadata. package( default_applicable_licenses = ["//:license"], @@ -8,10 +8,11 @@ package( licenses(["notice"]) java_library( - name = "config", + name = "info", srcs = glob(["*.java"]), deps = [ "@rules_android_maven//:com_android_tools_build_bundletool", + "@rules_android_maven//:com_google_protobuf_protobuf_java", "@rules_android_maven//:com_google_protobuf_protobuf_java_util", ], ) diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/SdkInfo.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/SdkInfo.java new file mode 100644 index 0000000..867e55d --- /dev/null +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/SdkInfo.java @@ -0,0 +1,61 @@ +/* + * Copyright 2023 The Bazel Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.devtools.build.android.sandboxedsdktoolbox.info; + +import java.util.Objects; + +/** + * Information about a Sandboxed SDK. Used to define an SDK dependency and read from an SDK archive + * or bundle config. + */ +public final class SdkInfo { + + private final String packageName; + private final long versionMajor; + + SdkInfo(String packageName, long versionMajor) { + this.packageName = packageName; + this.versionMajor = versionMajor; + } + + /** The SDK unique package name. */ + public String getPackageName() { + return packageName; + } + + /** + * The SDK versionMajor. This value is constructed from the full SDK version description and it + * represents the actual version of the SDK as used by the package manager later. The major and + * minor versions are merged and the patch version is ignored. + */ + public long getVersionMajor() { + return versionMajor; + } + + @Override + public boolean equals(Object object) { + if (object instanceof SdkInfo) { + SdkInfo that = (SdkInfo) object; + return this.packageName.equals(that.packageName) && this.versionMajor == that.versionMajor; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(packageName, versionMajor); + } +} diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/SdkInfoReader.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/SdkInfoReader.java new file mode 100644 index 0000000..7efef66 --- /dev/null +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info/SdkInfoReader.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023 The Bazel Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.devtools.build.android.sandboxedsdktoolbox.info; + +import com.android.bundle.SdkMetadataOuterClass.SdkMetadata; +import com.android.bundle.SdkModulesConfigOuterClass.RuntimeEnabledSdkVersion; +import com.android.bundle.SdkModulesConfigOuterClass.SdkModulesConfig; +import com.android.tools.build.bundletool.model.RuntimeEnabledSdkVersionEncoder; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; + +/** Reads SDK information SDK archives and Bundle metadata files. */ +public final class SdkInfoReader { + + // SDK metadata proto sits at the top level of an ASAR. + private static final String SDK_METADATA_ENTRY_PATH = "SdkMetadata.pb"; + + public static SdkInfo readFromSdkModuleJsonFile(Path sdkModulesConfigPath) { + SdkModulesConfig.Builder modulesConfig = SdkModulesConfig.newBuilder(); + try { + JsonFormat.parser().merge(Files.newBufferedReader(sdkModulesConfigPath), modulesConfig); + return new SdkInfo( + modulesConfig.getSdkPackageName(), getVersionMajor(modulesConfig.getSdkVersion())); + } catch (IOException e) { + throw new UncheckedIOException("Failed to parse SDK Module Config.", e); + } + } + + public static SdkInfo readFromSdkArchive(Path sdkArchivePath) { + URI uri = URI.create("jar:" + sdkArchivePath.toUri()); + try (FileSystem zipfs = FileSystems.newFileSystem(uri, new HashMap<String, String>())) { + Path metadataInAsar = zipfs.getPath(SDK_METADATA_ENTRY_PATH); + if (!Files.exists(metadataInAsar)) { + throw new IllegalStateException( + String.format("Could not find %s in %s", SDK_METADATA_ENTRY_PATH, sdkArchivePath)); + } + SdkMetadata metadata = + SdkMetadata.parseFrom( + Files.readAllBytes(metadataInAsar), ExtensionRegistry.getEmptyRegistry()); + return new SdkInfo(metadata.getPackageName(), getVersionMajor(metadata.getSdkVersion())); + } catch (IOException e) { + throw new UncheckedIOException("Failed to extract SDK API descriptors.", e); + } + } + + private static long getVersionMajor(RuntimeEnabledSdkVersion version) { + return RuntimeEnabledSdkVersionEncoder.encodeSdkMajorAndMinorVersion( + version.getMajor(), version.getMinor()); + } + + private SdkInfoReader() {} +} diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/AndroidManifestWriter.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/AndroidManifestWriter.java index f840c5f..67ce730 100644 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/AndroidManifestWriter.java +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/AndroidManifestWriter.java @@ -15,10 +15,8 @@ */ package com.google.devtools.build.android.sandboxedsdktoolbox.sdkdependenciesmanifest; -import static com.google.devtools.build.android.sandboxedsdktoolbox.config.SdkModulesConfigUtils.getVersionMajor; - -import com.android.bundle.SdkModulesConfigOuterClass.SdkModulesConfig; import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.android.sandboxedsdktoolbox.info.SdkInfo; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -50,7 +48,7 @@ final class AndroidManifestWriter { static void writeManifest( String packageName, String certificateDigest, - ImmutableSet<SdkModulesConfig> configs, + ImmutableSet<SdkInfo> infoSet, Path outputPath) { Document root = newEmptyDocument(); @@ -62,11 +60,11 @@ final class AndroidManifestWriter { Element applicationNode = root.createElement(APPLICATION_ELEMENT_NAME); manifestNode.appendChild(applicationNode); - for (SdkModulesConfig config : configs) { + for (SdkInfo sdkInfo : infoSet) { Element sdkDependencyElement = root.createElement(SDK_DEPENDENCY_ELEMENT_NAME); - sdkDependencyElement.setAttribute(ANDROID_NAME_ATTRIBUTE, config.getSdkPackageName()); + sdkDependencyElement.setAttribute(ANDROID_NAME_ATTRIBUTE, sdkInfo.getPackageName()); sdkDependencyElement.setAttribute( - ANDROID_VERSION_MAJOR_ATTRIBUTE, Long.toString(getVersionMajor(config))); + ANDROID_VERSION_MAJOR_ATTRIBUTE, Long.toString(sdkInfo.getVersionMajor())); sdkDependencyElement.setAttribute(ANDROID_CERTIFICATE_DIGEST_ATTRIBUTE, certificateDigest); applicationNode.appendChild(sdkDependencyElement); } diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD index b2584b2..12a7a1b 100644 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD @@ -11,7 +11,7 @@ java_library( name = "sdkdependenciesmanifest", srcs = glob(["*.java"]), deps = [ - "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/config", + "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info", "@rules_android_maven//:com_android_tools_build_bundletool", "@rules_android_maven//:com_google_guava_guava", "@rules_android_maven//:info_picocli_picocli", diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommand.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommand.java index c390f27..354f8fe 100644 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommand.java +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommand.java @@ -18,12 +18,14 @@ package com.google.devtools.build.android.sandboxedsdktoolbox.sdkdependenciesman import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.devtools.build.android.sandboxedsdktoolbox.sdkdependenciesmanifest.AndroidManifestWriter.writeManifest; import static com.google.devtools.build.android.sandboxedsdktoolbox.sdkdependenciesmanifest.CertificateDigestGenerator.generateCertificateDigest; -import static java.util.Arrays.stream; -import com.android.bundle.SdkModulesConfigOuterClass.SdkModulesConfig; import com.google.common.collect.ImmutableSet; -import com.google.devtools.build.android.sandboxedsdktoolbox.config.SdkModulesConfigUtils; +import com.google.devtools.build.android.sandboxedsdktoolbox.info.SdkInfo; +import com.google.devtools.build.android.sandboxedsdktoolbox.info.SdkInfoReader; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -31,15 +33,18 @@ import picocli.CommandLine.Option; @Command( name = "generate-sdk-dependencies-manifest", description = - "Generates an Android manifest with the <uses-sdk-library> tags from the given " - + "SDK bundles.") + "Generates an Android manifest with <uses-sdk-library> tags from the given SDK bundles " + + "or archives.") public final class GenerateSdkDependenciesManifestCommand implements Runnable { @Option(names = "--manifest-package", required = true) String manifestPackage; - @Option(names = "--sdk-module-configs", split = ",", required = true) - Path[] sdkModuleConfigPaths; + @Option(names = "--sdk-module-configs", split = ",", required = false) + List<Path> sdkModuleConfigPaths = new ArrayList<>(); + + @Option(names = "--sdk-archives", split = ",", required = false) + List<Path> sdkArchivePaths = new ArrayList<>(); @Option(names = "--debug-keystore", required = true) Path debugKeystorePath; @@ -55,9 +60,15 @@ public final class GenerateSdkDependenciesManifestCommand implements Runnable { @Override public void run() { - ImmutableSet<SdkModulesConfig> configSet = - stream(sdkModuleConfigPaths) - .map(SdkModulesConfigUtils::readFromJsonFile) + if (sdkModuleConfigPaths.isEmpty() && sdkArchivePaths.isEmpty()) { + throw new IllegalArgumentException( + "At least one of --sdk-module-configs or --sdk-archives must be specified."); + } + + ImmutableSet<SdkInfo> configSet = + Stream.concat( + sdkModuleConfigPaths.stream().map(SdkInfoReader::readFromSdkModuleJsonFile), + sdkArchivePaths.stream().map(SdkInfoReader::readFromSdkArchive)) .collect(toImmutableSet()); String certificateDigest = diff --git a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD index c2b38d1..84d1663 100644 --- a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD +++ b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/BUILD @@ -11,16 +11,12 @@ java_test( name = "GenerateSdkDependenciesManifestCommandTest", size = "small", srcs = ["GenerateSdkDependenciesManifestCommandTest.java"], - data = [ - "testdata/com.example.firstsdkconfig.json", - "testdata/com.example.secondsdkconfig.json", - "testdata/expected_manifest_multiple_sdks.xml", - "testdata/expected_manifest_single_sdk.xml", - "testdata/test_key", - ], + data = glob(["testdata/*"]), deps = [ "//src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/utils", - "@rules_android_maven//:junit_junit", + "@rules_android_maven//:com_android_tools_build_bundletool", + "@rules_android_maven//:com_google_protobuf_protobuf_java_util", "@rules_android_maven//:com_google_truth_truth", + "@rules_android_maven//:junit_junit", ], ) diff --git a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommandTest.java b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommandTest.java index 7dc04e7..749320e 100644 --- a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommandTest.java +++ b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/GenerateSdkDependenciesManifestCommandTest.java @@ -19,8 +19,13 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.devtools.build.android.sandboxedsdktoolbox.utils.Runner.runCommand; import static com.google.devtools.build.android.sandboxedsdktoolbox.utils.TestData.JAVATESTS_DIR; import static com.google.devtools.build.android.sandboxedsdktoolbox.utils.TestData.readFromAbsolutePath; +import static com.google.devtools.build.android.sandboxedsdktoolbox.utils.Zip.createZipWithSingleEntry; +import com.android.bundle.SdkMetadataOuterClass.SdkMetadata; import com.google.devtools.build.android.sandboxedsdktoolbox.utils.CommandResult; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import org.junit.Rule; import org.junit.Test; @@ -42,6 +47,9 @@ public final class GenerateSdkDependenciesManifestCommandTest { TEST_DATA_DIR.resolve("com.example.firstsdkconfig.json"); private static final Path SECOND_SDK_CONFIG_JSON_PATH = TEST_DATA_DIR.resolve("com.example.secondsdkconfig.json"); + private static final Path ARCHIVE_CONFIG_JSON_PATH = + TEST_DATA_DIR.resolve("com.example.archivedsdkmetadata.json"); + /* The test key was generated with this command, its password is "android" keytool -genkeypair \ @@ -109,4 +117,43 @@ public final class GenerateSdkDependenciesManifestCommandTest { .isEqualTo( readFromAbsolutePath(TEST_DATA_DIR.resolve("expected_manifest_multiple_sdks.xml"))); } + + @Test + public void generateManifest_forSdksAndArchives_success() throws Exception { + String manifestPackage = "com.example.generatedmanifest"; + // Create a zip with a single file containing the SdkMetadata proto message, serialized. + Path archiveConfigPath = testFolder.getRoot().toPath().resolve("sdk.asar"); + createZipWithSingleEntry(archiveConfigPath, "SdkMetadata.pb", readSdkMetadata().toByteArray()); + Path outputFile = testFolder.newFile().toPath(); + + CommandResult result = + runCommand( + "generate-sdk-dependencies-manifest", + "--manifest-package", + manifestPackage, + "--sdk-module-configs", + FIRST_SDK_CONFIG_JSON_PATH.toString(), + "--sdk-archives", + archiveConfigPath.toString(), + "--debug-keystore", + TEST_KEY_PATH.toString(), + "--debug-keystore-pass", + "android", + "--debug-keystore-alias", + "androiddebugkey", + "--output-manifest", + outputFile.toString()); + + assertThat(result.getStatusCode()).isEqualTo(0); + assertThat(result.getOutput()).isEmpty(); + assertThat(readFromAbsolutePath(outputFile)) + .isEqualTo( + readFromAbsolutePath(TEST_DATA_DIR.resolve("expected_manifest_with_archived_sdk.xml"))); + } + + private static SdkMetadata readSdkMetadata() throws IOException { + SdkMetadata.Builder metadata = SdkMetadata.newBuilder(); + JsonFormat.parser().merge(Files.newBufferedReader(ARCHIVE_CONFIG_JSON_PATH), metadata); + return metadata.build(); + } } diff --git a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/testdata/com.example.archivedsdkmetadata.json b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/testdata/com.example.archivedsdkmetadata.json new file mode 100644 index 0000000..d3be443 --- /dev/null +++ b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/testdata/com.example.archivedsdkmetadata.json @@ -0,0 +1,11 @@ +{ + "package_name": "com.example.archivedsdk", + "sdk_version": { + "major": 33, + "minor": 2, + "patch": 1 + }, + + // We always use the debug key digest instead of the one provided in the ASAR. + "certificate_digest": "fake digest that should be ignored." +}
\ No newline at end of file diff --git a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/testdata/expected_manifest_with_archived_sdk.xml b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/testdata/expected_manifest_with_archived_sdk.xml new file mode 100644 index 0000000..e3bab8f --- /dev/null +++ b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest/testdata/expected_manifest_with_archived_sdk.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.generatedmanifest"> + <application> + <uses-sdk-library android:certDigest="91:8E:A3:7D:7D:D0:E0:A0:14:9F:21:28:83:95:8A:F0:80:E6:F9:7B:4D:5A:39:01:76:02:E8:2D:7D:FF:A9:10" android:name="com.example.firstsdkconfig" android:versionMajor="20003"/> + <uses-sdk-library android:certDigest="91:8E:A3:7D:7D:D0:E0:A0:14:9F:21:28:83:95:8A:F0:80:E6:F9:7B:4D:5A:39:01:76:02:E8:2D:7D:FF:A9:10" android:name="com.example.archivedsdk" android:versionMajor="330002"/> + </application> +</manifest>
\ No newline at end of file diff --git a/src/tools/mi/deployment_oss/BUILD b/src/tools/mi/deployment_oss/BUILD new file mode 100644 index 0000000..b078ff2 --- /dev/null +++ b/src/tools/mi/deployment_oss/BUILD @@ -0,0 +1,36 @@ +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//src/tools/mi/deployment_oss:__pkg__"], +) + +go_binary( + name = "deploy_binary", + srcs = ["deploy_binary.go"], + visibility = ["//visibility:public"], + deps = [ + "//src/common/golang:flagfile", + "//src/common/golang:flags", + "//src/common/golang:pprint", + "//src/tools/mi/deployment_oss:deployment", + "@com_github_golang_glog//:glog", + ], +) + +go_library( + name = "deployment", + importpath = "src/tools/mi/deployment_oss/deployment", + + srcs = [ + "deploy.go", + ], + visibility = ["//src/tools/mi:__subpackages__"], + deps = ["//src/common/golang:pprint"], +) + +build_test( + name = "deploy_binary_build_test", + targets = [":deploy_binary"] +)
\ No newline at end of file diff --git a/src/tools/mi/deployment_oss/deploy.go b/src/tools/mi/deployment_oss/deploy.go new file mode 100644 index 0000000..1446e58 --- /dev/null +++ b/src/tools/mi/deployment_oss/deploy.go @@ -0,0 +1,64 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package deployment has utilities to sync mobile-install build outputs with a device. +package deployment + +import ( + "context" + "fmt" + "os" + "os/exec" + "strconv" + + "src/common/golang/pprint" +) + +// AndroidStudioSync calls to the Studio deployer with splits. +func AndroidStudioSync(ctx context.Context, deviceSerial, port, pkg string, splits []string, deployer, adbPath, jdk string, optimisticInstall bool, studioVerboseLog bool, userID int, useADBRoot bool) error { + args := []string{"-jar", deployer, "install", pkg} + if deviceSerial != "" { + args = append(args, fmt.Sprintf("--device=%s", deviceSerial)) + } + args = append(args, "--skip-post-install", "--no-jdwp-client-support") + if optimisticInstall { + args = append(args, "--optimistic-install") + } + if useADBRoot { + args = append(args, "--use-root-push-install") + } + if studioVerboseLog { + args = append(args, "--log-level=VERBOSE") + } + if adbPath != "" { + args = append(args, fmt.Sprintf("--adb=%s", adbPath)) + } + if userID != 0 { + args = append(args, fmt.Sprintf("--user=%s", strconv.Itoa(userID))) + } + args = append(args, splits...) + cmd := exec.Command(jdk, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if port != "" { + cmd.Env = append(os.Environ(), fmt.Sprintf("ANDROID_ADB_SERVER_PORT=%s", port)) + } + if studioVerboseLog { + pprint.Info("device: %s", deviceSerial) + pprint.Info("port: %s", port) + pprint.Info("Env: %s", cmd.Env) + pprint.Info("Cmd: %s", cmd.String()) + } + return cmd.Run() +} diff --git a/src/tools/mi/deployment_oss/deploy_binary.go b/src/tools/mi/deployment_oss/deploy_binary.go new file mode 100644 index 0000000..503c81a --- /dev/null +++ b/src/tools/mi/deployment_oss/deploy_binary.go @@ -0,0 +1,217 @@ +// 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. + +// The deploy_binary command unpacks a workspace and deploys it to a device. +package main + +import ( + "context" + "flag" + "io/ioutil" + "log" + "os" + "os/exec" + "strings" + "time" + + glog "github.com/golang/glog" + + _ "src/common/golang/flagfile" + "src/common/golang/flags" + "src/common/golang/pprint" + "src/tools/mi/deployment_oss/deployment" +) + +var ( + adbArgs = flags.NewStringList("adb_arg", "Options for the adb binary.") + adbPath = flag.String("adb", "/usr/bin/adb", "Path to the adb binary to use with mobile-install.") + device = flag.String("device", "", "The adb device serial number.") + javaHome = flag.String("java_home", "", "Path to JDK.") + launchActivity = flag.String("launch_activity", "", "Activity to launch via am start -n package/.activity_to_launch.") + appPackagePath = flag.String("manifest_package_name_path", "", "Path to file containing the manifest package name.") + splits = flags.NewStringList("splits", "The list of split apk paths.") + start = flag.String("start", "", "start_type from mobile-install.") + startType = flag.String("start_type", "", "start_type (deprecated, use --start).") + useADBRoot = flag.Bool("use_adb_root", true, "whether (true) or not (false) to use root permissions.") + userID = flag.Int("user", 0, "User id to install the app for.") + + // Studio deployer args + studioDeployerPath = flag.String("studio_deployer", "", "Path to the Android Studio deployer.") + optimisticInstall = flag.Bool("optimistic-install", false, "If true, try to push changes to the device without installing.") + studioVerboseLog = flag.Bool("studio-verbose-log", false, "If true, enable verbose logging for the Android Studio deployer") + + // Need to double up on launch_app due as the built-in flag module does not support noXX for bool flags. + // Some users are using --nolaunch_app, so we need to explicitly declare this flag + launchApp = flag.Bool("launch_app", true, "Launch the app after the sync is done.") + noLaunchApp = flag.Bool("nolaunch_app", false, "Don't launch the app after the sync is done.") + noDeploy = flag.Bool("nodeploy", false, "Don't deploy or launch the app, useful for testing.") + + // Unused flags: Relevant only for Google-internal use cases, but need to exist in the flag parser + buildID = flag.String("build_id", "", "The id of the build. Set by Bazel, the user should not use this flag.") +) + +func resolveDeviceSerialAndPort(ctx context.Context, device string) (deviceSerialFlag, port string) { + switch { + case strings.Contains(device, ":tcp:"): + parts := strings.SplitN(device, ":tcp:", 2) + deviceSerialFlag = parts[0] + port = parts[1] + case strings.HasPrefix(device, "tcp:"): + port = strings.TrimPrefix(device, "tcp:") + default: + deviceSerialFlag = device + } + return deviceSerialFlag, port +} + +func determineDeviceSerial(deviceSerialFlag, deviceSerialEnv, deviceSerialADBArg string) string { + var deviceSerial string + switch { + case deviceSerialFlag != "": + deviceSerial = deviceSerialFlag + case deviceSerialEnv != "": + deviceSerial = deviceSerialEnv + case deviceSerialADBArg != "": + deviceSerial = deviceSerialADBArg + } + return deviceSerial +} + +// ReadFile reads file from a given path +func readFile(path string) []byte { + data, err := ioutil.ReadFile(path) + if err != nil { + log.Fatalf("Error reading file %q: %v", path, err) + } + return data +} + +func parseRepeatedFlag(n string, a *flags.StringList) { + var l []string + for _, f := range os.Args { + if strings.HasPrefix(f, n) { + l = append(l, strings.TrimPrefix(f, n)) + } + } + if len(l) > 1 { + *a = l + } +} + +// Flush all the metrics to Streamz before the program exits. +func flushAndExitf(ctx context.Context, unused1, unused2, unused3, unused4, format string, args ...any) { + glog.Exitf(format, args...) +} + +func main() { + ctx := context.Background() + + flag.Parse() + + pprint.Info("Deploying using OSS mobile-install!") + + if *noDeploy { + pprint.Warning("--nodeploy set, not deploying application.") + return + } + + // Override --launch_app if --nolaunch_app is passed + if *noLaunchApp { + *launchApp = false + } + + if *appPackagePath == "" { + glog.Exitf("--manifest_package_name is required") + } + + // Resolve the device serial and port. + var deviceSerialFlag, port string + if *device != "" { + deviceSerialFlag, port = resolveDeviceSerialAndPort(ctx, *device) + } + deviceSerialEnv := os.Getenv("ANDROID_SERIAL") + + // TODO(b/66490815): Remove once adb_arg flag is deprecated. + // Check for a device serial in adb_arg. If deviceSerial has not been specified, the value + // found here will become the deviceSerial. If the deviceSerial has been specified the value + // found here will be ignored but we will notify the user the device chosen. + var deviceSerialADBArg string + for i, arg := range *adbArgs { + if strings.TrimSpace(arg) == "-s" && len(*adbArgs) > i+1 { + deviceSerialADBArg = (*adbArgs)[i+1] + } + } + + // TODO(timpeut): Delete after the next blaze release + // Ignore the device passed by --adb_arg if it matches the device passed by --device. + if deviceSerialADBArg == *device { + deviceSerialADBArg = "" + } + + // Determine which value to use as the deviceSerial. + deviceSerial := determineDeviceSerial(deviceSerialFlag, deviceSerialEnv, deviceSerialADBArg) + + // Warn user of the multiple device serial specification, that is not equal to the first. + if (deviceSerialEnv != "" && deviceSerialEnv != deviceSerial) || + (deviceSerialADBArg != "" && deviceSerialADBArg != deviceSerial) { + pprint.Warning("A device serial was specified more than once with --device, $ANDROID_SERIAL or --adb_arg, using %s.", deviceSerial) + } + + appPackage := strings.TrimSpace(string(readFile(*appPackagePath))) + + startTime := time.Now() + + pprint.Info("Installing application using the Android Studio deployer ...") + if err := deployment.AndroidStudioSync(ctx, deviceSerial, port, appPackage, *splits, *studioDeployerPath, *adbPath, *javaHome, *optimisticInstall, *studioVerboseLog, *userID, *useADBRoot); err != nil { + flushAndExitf(ctx, "", "", "", "", "Got error installing using the Android Studio deployer: %v", err) + } + + deploymentTime := time.Since(startTime) + pprint.Info("Took %.2f seconds to sync changes", deploymentTime.Seconds()) + + if *startType != "" { + *start = *startType + } + + // Wait for the debugger if debug mode selected + if *start == "DEBUG" { + waitCmd := exec.Command(*adbPath, "shell", "am", "set-debug-app", "-w", appPackage) + if err := waitCmd.Wait(); err != nil { + pprint.Error("Unable to wait for debugger: %s", err.Error()) + } + } + + if *launchApp { + pprint.Info("Finished deploying changes. Launching app") + var launchCmd *exec.Cmd + if *launchActivity != "" { + launchCmd = exec.Command(*adbPath, "shell", "am", "start", "-a", "android.intent.action.MAIN", "-n", appPackage+"/"+*launchActivity) + } else { + launchCmd = exec.Command(*adbPath, "shell", "monkey", "-p", appPackage, "1") + pprint.Warning( + "No or multiple main activities found, falling back to Monkey launcher. Specify the activity you want with `-- --launch_activity` or `-- --nolaunch_app` to launch nothing.") + } + + if err := launchCmd.Run(); err != nil { + pprint.Warning("Unable to launch app. Specify an activity with --launch_activity.") + pprint.Warning("Original error: %s", err.Error()) + } + } else { + // Always stop the app since classloader needs to be reloaded. + stopCmd := exec.Command(*adbPath, "shell", "am", "force-stop", appPackage) + if err := stopCmd.Run(); err != nil { + pprint.Error("Unable to stop app: %s", err.Error()) + } + } +} diff --git a/test/rules/android_binary_internal/r8_integration/java/com/basicapp/BUILD b/test/rules/android_binary_internal/r8_integration/java/com/basicapp/BUILD index 4727887..a164ae6 100644 --- a/test/rules/android_binary_internal/r8_integration/java/com/basicapp/BUILD +++ b/test/rules/android_binary_internal/r8_integration/java/com/basicapp/BUILD @@ -4,8 +4,15 @@ load("//rules:rules.bzl", "android_binary", "android_library") android_binary( name = name, srcs = ["BasicActivity.java"], + # Work around --java_runtime_version=17 and --java_language_version=11 + # set in the presubmit tests. + javacopts = [ + "-target", + "8", + "-source", + "8", + ], manifest = "AndroidManifest.xml", - min_sdk_version = 27, proguard_specs = specs, resource_files = glob(["res/**"]), shrink_resources = shrink, @@ -14,9 +21,6 @@ load("//rules:rules.bzl", "android_binary", "android_library") ":basic_lib", ":lib_with_specs", ], - # Work around --java_runtime_version=17 and --java_language_version=11 - # set in the presubmit tests. - javacopts = ["-target", "8", "-source", "8"], ) for name, specs, shrink in [ ( diff --git a/test/rules/android_library_extensibility/BUILD b/test/rules/android_library_extensibility/BUILD new file mode 100644 index 0000000..99706ce --- /dev/null +++ b/test/rules/android_library_extensibility/BUILD @@ -0,0 +1,28 @@ +load(":custom_android_library.bzl", "custom_android_library") +load(":test.bzl", "custom_android_library_test") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = + ["//:__subpackages__"], +) + +licenses(["notice"]) + +custom_android_library( + name = "custom_android_library", + testonly = True, + key = "test_key", +) + +custom_android_library_test( + name = "custom_android_library_test", + lib = ":custom_android_library", +) + +test_suite( + name = "integration_tests", + tests = [ + ":custom_android_library_test", + ], +) diff --git a/test/rules/android_library_extensibility/custom_android_library.bzl b/test/rules/android_library_extensibility/custom_android_library.bzl new file mode 100644 index 0000000..a58fd1e --- /dev/null +++ b/test/rules/android_library_extensibility/custom_android_library.bzl @@ -0,0 +1,86 @@ +# Copyright 2023 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. + +"""Custom android_library for use in test.bzl""" + +load( + "//rules:attrs.bzl", + _attrs = "attrs", +) +load( + "//rules:java.bzl", + _java = "java", +) +load( + "//rules:processing_pipeline.bzl", + _ProviderInfo = "ProviderInfo", + _processing_pipeline = "processing_pipeline", +) +load( + "//rules/android_library:attrs.bzl", + _BASE_ATTRS = "ATTRS", +) +load( + "//rules/android_library:impl.bzl", + _BASE_PROCESSORS = "PROCESSORS", + _finalize = "finalize", +) +load( + "//rules/android_library:rule.bzl", + _make_rule = "make_rule", +) + +CustomProviderInfo = provider( + doc = "Custom provider to provide", + fields = dict( + key = "Some key to provide", + ), +) + +def _process_custom_provider(ctx, **_unused_sub_ctxs): + return _ProviderInfo( + name = "custom_provider_ctx", + value = struct( + providers = [ + CustomProviderInfo( + key = ctx.attr.key, + ), + ], + ), + ) + +PROCESSORS = _processing_pipeline.append( + _BASE_PROCESSORS, + CustomProviderInfoProcessor = _process_custom_provider, +) + +_PROCESSING_PIPELINE = _processing_pipeline.make_processing_pipeline( + processors = PROCESSORS, + finalize = _finalize, +) + +def _impl(ctx): + java_package = _java.resolve_package_from_label(ctx.label, ctx.attr.custom_package) + return _processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE) + +custom_android_library = _make_rule( + implementation = _impl, + attrs = _attrs.add(_BASE_ATTRS, dict( + # Custom attribute to wrap in a provider + key = attr.string(), + )), + additional_providers = [ + CustomProviderInfo, + ], +) diff --git a/test/rules/android_library_extensibility/test.bzl b/test/rules/android_library_extensibility/test.bzl new file mode 100644 index 0000000..78aa9c1 --- /dev/null +++ b/test/rules/android_library_extensibility/test.bzl @@ -0,0 +1,41 @@ +# Copyright 2023 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. + +"""Tests for the extensibility functionality of android_library.""" + +load( + "//test/utils:lib.bzl", + "asserts", + "unittest", +) +load( + ":custom_android_library.bzl", + "CustomProviderInfo", +) + +def custom_android_library_test_impl(ctx): + env = unittest.begin(ctx) + + # Assert that the custom provider exists + asserts.true(env, CustomProviderInfo in ctx.attr.lib) + asserts.equals(env, ctx.attr.lib[CustomProviderInfo].key, "test_key") + + return unittest.end(env) + +custom_android_library_test = unittest.make( + impl = custom_android_library_test_impl, + attrs = { + "lib": attr.label(providers = [CustomProviderInfo]), + }, +) diff --git a/test/rules/android_local_test/BUILD b/test/rules/android_local_test/BUILD new file mode 100644 index 0000000..590a523 --- /dev/null +++ b/test/rules/android_local_test/BUILD @@ -0,0 +1,69 @@ +load("//rules:rules.bzl", "android_local_test") +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load(":java_launcher_integration_test.bzl", "android_local_test_launcher_integration_test_suite") +load(":java_launcher_test.bzl", "android_local_test_launcher_test_suite") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +licenses(["notice"]) + +exports_files([ + "EmptyTest.java", + "integration_test_stub_script.sh", +]) + +bzl_library( + name = "bzl", + srcs = glob(["*.bzl"]), + visibility = ["//visibility:private"], +) + +android_local_test( + name = "sample_test_default_launcher", + srcs = ["EmptyTest.java"], + custom_package = "com.google.android.emptytest", + test_class = "com.google.android.emptytest.EmptyTest", + deps = [ + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + ], +) + +android_local_test( + name = "sample_test_default_launcher_integration", + srcs = ["EmptyTest.java"], + custom_package = "com.google.android.emptytest", + test_class = "com.google.android.emptytest.EmptyTest", + deps = [ + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + ], +) + +config_setting( + name = "jdk17", + values = { + "java_runtime_version": "17", + }, +) + +android_local_test_launcher_test_suite( + name = "android_local_test_launcher_tests", + expected_executable = select({ + ":jdk17": "../remotejdk17_linux/bin/java", + "//conditions:default": "third_party/java/jdk/jdk-sts-k8/bin/java", + }), +) + +android_local_test_launcher_integration_test_suite( + name = "android_local_test_launcher_integration_tests", + expected_executable = select({ + ":jdk17": "rules_android/../remotejdk17_linux/bin/java", + "//conditions:default": "rules_android/third_party/java/jdk/jdk-sts-k8/bin/java", + }), +) diff --git a/test/rules/android_local_test/EmptyTest.java b/test/rules/android_local_test/EmptyTest.java new file mode 100644 index 0000000..8f85825 --- /dev/null +++ b/test/rules/android_local_test/EmptyTest.java @@ -0,0 +1,25 @@ +/** + * Copyright 2021 The Bazel Authors. All rights reserved. + * + * <p>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 + * + * <p>http://www.apache.org/licenses/LICENSE-2.0 + * + * <p>Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.emptytest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class EmptyTest { + @Test + public void emptyTest() { + } +} diff --git a/test/rules/android_local_test/integration_test_stub_script.sh b/test/rules/android_local_test/integration_test_stub_script.sh new file mode 100644 index 0000000..9f836f2 --- /dev/null +++ b/test/rules/android_local_test/integration_test_stub_script.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# 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. + +exit_with_error() { + echo "Expected to find JAVABIN=\${JAVABIN:-\${JAVA_RUNFILES}/%expected_executable% but was" + echo $reference + exit 1 +} + +executable="%executable%" +reference=`grep -o 'JAVABIN=\\${JAVABIN:-\\${JAVA_RUNFILES}/.*}' $executable` +grep -c "JAVABIN:-\${JAVA_RUNFILES}/%expected_executable%" $executable >> /dev/null || exit_with_error diff --git a/test/rules/android_local_test/java/com/starlark_resources/AndroidManifest.xml b/test/rules/android_local_test/java/com/starlark_resources/AndroidManifest.xml new file mode 100644 index 0000000..978e2c8 --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/AndroidManifest.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.starlark_resources"> + <uses-sdk + android:minSdkVersion="21" + android:targetSdkVersion="24" /> +</manifest> diff --git a/test/rules/android_local_test/java/com/starlark_resources/BUILD b/test/rules/android_local_test/java/com/starlark_resources/BUILD new file mode 100644 index 0000000..f5824cd --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/BUILD @@ -0,0 +1,177 @@ +# Tests that run on head android_local_test rule to verify Starlark resource processing pipeline. + +load( + "//rules:rules.bzl", + "android_library", + "android_local_test", +) +load( + "//test/rules/android_local_test:test.bzl", + "rule_test", +) + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:private"], +) + +licenses(["notice"]) + +android_local_test( + name = "no_deps_with_resources", + srcs = ["SampleTest.java"], + manifest = "AndroidManifest.xml", + resource_files = glob(["res/**"]), + test_class = "com.starlark_resources.SampleTest", + deps = [ + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +rule_test( + name = "no_deps_with_resources_rule_test", + target_under_test = ":no_deps_with_resources", +) + +# TODO(b/161179595): Add test to exercise resource_configuration_filter wiring. + +# TODO(aarmin): Add test to exercise densities and manifest_values wiring. + +android_library( + name = "resource_processing", + assets = ["assets/bar.txt"], + assets_dir = "assets", + manifest = "AndroidManifest.xml", + resource_files = glob(["res/**"]), +) + +android_local_test( + name = "single_resource_dep_without_manifest", + srcs = ["SampleTest.java"], + test_class = "com.starlark_resources.SampleTest", + deps = [ + ":resource_processing", + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +rule_test( + name = "single_resource_dep_without_manifest_rule_test", + target_under_test = ":single_resource_dep_without_manifest", +) + +android_local_test( + name = "single_resource_dep", + srcs = ["SampleTest.java"], + manifest = "AndroidManifest.xml", + test_class = "com.starlark_resources.SampleTest", + deps = [ + ":resource_processing", + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +rule_test( + name = "single_resource_dep_rule_test", + target_under_test = ":single_resource_dep", +) + +android_library( + name = "resources_with_dep_with_res", + assets = ["assets/foo.txt"], + assets_dir = "assets", + manifest = "AndroidManifest.xml", + resource_files = glob(["another_res/**"]), + deps = [":resource_processing"], +) + +android_local_test( + name = "multiple_resource_deps", + srcs = ["SampleTestMultipleDeps.java"], + manifest = "AndroidManifest.xml", + test_class = "com.starlark_resources.SampleTestMultipleDeps", + deps = [ + ":resources_with_dep_with_res", + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +rule_test( + name = "multiple_resource_deps_rule_test", + target_under_test = ":multiple_resource_deps", +) + +android_library( + name = "resource_processing_with_neverlink", + manifest = "AndroidManifest.xml", + neverlink = True, + resource_files = glob(["res/**"]), +) + +android_local_test( + name = "depends_on_neverlink_lib", + srcs = ["SampleTestNeverlinkDep.java"], + manifest = "AndroidManifest.xml", + test_class = "com.starlark_resources.SampleTestNeverlinkDep", + deps = [ + ":resource_processing_with_neverlink", + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +rule_test( + name = "depends_on_neverlink_lib_rule_test", + expect_resources = False, + target_under_test = ":depends_on_neverlink_lib", +) + +android_local_test( + name = "manifest_values_low_minsdk", + srcs = ["SampleTest.java"], + manifest = "AndroidManifest.xml", + manifest_values = {"minSdkVersion": "15"}, + resource_files = glob(["res/**"]), + test_class = "com.starlark_resources.SampleTest", + deps = [ + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +android_local_test( + name = "manifest_values_low_minsdk_no_manifest", + srcs = ["SampleTest.java"], + manifest_values = {"minSdkVersion": "15"}, + resource_files = glob(["res/**"]), + test_class = "com.starlark_resources.SampleTest", + deps = [ + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) diff --git a/test/rules/android_local_test/java/com/starlark_resources/SampleTest.java b/test/rules/android_local_test/java/com/starlark_resources/SampleTest.java new file mode 100644 index 0000000..32529df --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/SampleTest.java @@ -0,0 +1,43 @@ +/** + * Copyright 2021 The Bazel Authors. All rights reserved. + * + * <p>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 + * + * <p>http://www.apache.org/licenses/LICENSE-2.0 + * + * <p>Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.starlark_resources; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.content.res.Resources; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SampleTest { + private Context targetContext; + private Resources resources; + + @Before + public void setup() throws Exception { + targetContext = ApplicationProvider.getApplicationContext(); + resources = targetContext.getResources(); + } + + @Test + public void test() throws Exception { + assertEquals("Check package name", "com.starlark_resources", targetContext.getPackageName()); + assertEquals( + "Check resource `a_string`", "Hello World!", resources.getString(R.string.a_string)); + } +} diff --git a/test/rules/android_local_test/java/com/starlark_resources/SampleTestMultipleDeps.java b/test/rules/android_local_test/java/com/starlark_resources/SampleTestMultipleDeps.java new file mode 100644 index 0000000..7091594 --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/SampleTestMultipleDeps.java @@ -0,0 +1,45 @@ +/** + * Copyright 2021 The Bazel Authors. All rights reserved. + * + * <p>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 + * + * <p>http://www.apache.org/licenses/LICENSE-2.0 + * + * <p>Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.starlark_resources; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.content.res.Resources; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SampleTestMultipleDeps { + private Context targetContext; + private Resources resources; + + @Before + public void setup() throws Exception { + targetContext = ApplicationProvider.getApplicationContext(); + resources = targetContext.getResources(); + } + + @Test + public void test() throws Exception { + assertEquals("Check package name", "com.starlark_resources", targetContext.getPackageName()); + assertEquals( + "Check resource `a_string`", "Hello World!", resources.getString(R.string.a_string)); + assertEquals( + "Check resource `another_res`", "Another Res!", resources.getString(R.string.another_res)); + } +} diff --git a/test/rules/android_local_test/java/com/starlark_resources/SampleTestNeverlinkDep.java b/test/rules/android_local_test/java/com/starlark_resources/SampleTestNeverlinkDep.java new file mode 100644 index 0000000..3da5dca --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/SampleTestNeverlinkDep.java @@ -0,0 +1,51 @@ +/** + * Copyright 2021 The Bazel Authors. All rights reserved. + * + * <p>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 + * + * <p>http://www.apache.org/licenses/LICENSE-2.0 + * + * <p>Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.starlark_resources; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.content.res.Resources; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SampleTestNeverlinkDep { + private Context targetContext; + private Resources resources; + + @Before + public void setup() throws Exception { + targetContext = ApplicationProvider.getApplicationContext(); + resources = targetContext.getResources(); + } + + @Test + public void test() throws Exception { + assertEquals("Check package name", "com.starlark_resources", targetContext.getPackageName()); + try { + // This line should throw an exception since there are no resources inherited from + // neverlink deps. + assertEquals( + "Check resource `a_string`", "Hello World!", resources.getString(R.string.a_string)); + } catch(NoClassDefFoundError e) { + return; + } + fail("Expected NoClassDefFoundError exception"); + } +} diff --git a/test/rules/android_local_test/java/com/starlark_resources/another_res/values/strings.xml b/test/rules/android_local_test/java/com/starlark_resources/another_res/values/strings.xml new file mode 100644 index 0000000..554ea5e --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/another_res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="another_res">Another Res!</string> +</resources> diff --git a/test/rules/android_local_test/java/com/starlark_resources/assets/bar.txt b/test/rules/android_local_test/java/com/starlark_resources/assets/bar.txt new file mode 100644 index 0000000..5716ca5 --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/assets/bar.txt @@ -0,0 +1 @@ +bar diff --git a/test/rules/android_local_test/java/com/starlark_resources/assets/foo.txt b/test/rules/android_local_test/java/com/starlark_resources/assets/foo.txt new file mode 100644 index 0000000..257cc56 --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/assets/foo.txt @@ -0,0 +1 @@ +foo diff --git a/test/rules/android_local_test/java/com/starlark_resources/res/values/strings.xml b/test/rules/android_local_test/java/com/starlark_resources/res/values/strings.xml new file mode 100644 index 0000000..2686d09 --- /dev/null +++ b/test/rules/android_local_test/java/com/starlark_resources/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="a_string">Hello World!</string> +</resources> diff --git a/test/rules/android_local_test/java_launcher_integration_test.bzl b/test/rules/android_local_test/java_launcher_integration_test.bzl new file mode 100644 index 0000000..a09a566 --- /dev/null +++ b/test/rules/android_local_test/java_launcher_integration_test.bzl @@ -0,0 +1,64 @@ +# 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. + +""" Bazel rules that test the Android Local Test rule. + +launcher_test: Asserts that the executable is populated correctly in the target script. +""" + +def _android_local_test_launcher_integration(ctx): + substitutions = { + "%executable%": ctx.attr.target[DefaultInfo].files_to_run.executable.short_path, + "%expected_executable%": ctx.attr.expected_executable, + } + runner = ctx.actions.declare_file(ctx.label.name + "_runner.sh") + ctx.actions.expand_template( + template = ctx.file._test_stub_script, + substitutions = substitutions, + output = runner, + ) + return [ + DefaultInfo( + executable = runner, + runfiles = ctx.runfiles( + files = [ctx.attr.target[DefaultInfo].files_to_run.executable], + ), + ), + ] + +integration_test = rule( + attrs = dict( + target = attr.label(), + _test_stub_script = attr.label( + cfg = "exec", + default = ":integration_test_stub_script.sh", + allow_single_file = True, + ), + expected_executable = attr.string(), + ), + test = True, + implementation = _android_local_test_launcher_integration, +) + +def android_local_test_launcher_integration_test_suite(name, expected_executable): + integration_test( + name = "android_local_test_default_launcher_integration", + target = ":sample_test_default_launcher_integration", + expected_executable = expected_executable, + ) + + native.test_suite( + name = name, + tests = [":android_local_test_default_launcher_integration"], + ) diff --git a/test/rules/android_local_test/java_launcher_test.bzl b/test/rules/android_local_test/java_launcher_test.bzl new file mode 100644 index 0000000..36d90fe --- /dev/null +++ b/test/rules/android_local_test/java_launcher_test.bzl @@ -0,0 +1,50 @@ +# 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. + +""" Bazel rules that test the Android Local Test rule. + +launcher_test: Asserts that the executable is contained in the target's runfiles. +""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@bazel_skylib//lib:sets.bzl", "sets") + +def _android_local_test_default_launcher(ctx): + env = analysistest.begin(ctx) + target_under_test = analysistest.target_under_test(env) + expected_runfile = getattr(env.ctx.attr, "expected_runfile") + + runfiles = sets.make([f.short_path for f in target_under_test[DefaultInfo].default_runfiles.files.to_list()]) + asserts.true(env, sets.contains(runfiles, expected_runfile), "Expect runfiles to contains {0}".format(expected_runfile)) + + return analysistest.end(env) + +android_local_test_default_launcher_test = analysistest.make( + _android_local_test_default_launcher, + attrs = { + "expected_runfile": attr.string(), + }, +) + +def android_local_test_launcher_test_suite(name, expected_executable): + android_local_test_default_launcher_test( + name = "android_local_test_default_launcher", + target_under_test = ":sample_test_default_launcher", + expected_runfile = expected_executable, + ) + + native.test_suite( + name = name, + tests = [":android_local_test_default_launcher"], + ) diff --git a/test/rules/android_local_test/non_java/AndroidManifest.xml b/test/rules/android_local_test/non_java/AndroidManifest.xml new file mode 100644 index 0000000..978e2c8 --- /dev/null +++ b/test/rules/android_local_test/non_java/AndroidManifest.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.starlark_resources"> + <uses-sdk + android:minSdkVersion="21" + android:targetSdkVersion="24" /> +</manifest> diff --git a/test/rules/android_local_test/non_java/BUILD b/test/rules/android_local_test/non_java/BUILD new file mode 100644 index 0000000..e3f10b7 --- /dev/null +++ b/test/rules/android_local_test/non_java/BUILD @@ -0,0 +1,51 @@ +# Tests that run on head android_local_test rule to verify Starlark resource processing pipeline. + +load( + "//rules:rules.bzl", + "android_library", + "android_local_test", +) +load( + "//test/rules/android_local_test:test.bzl", + "rule_test", +) + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:private"], +) + +licenses(["notice"]) + +android_library( + name = "resource_processing", + assets = ["assets/bar.txt"], + assets_dir = "assets", + custom_package = "com.starlark_resources", + manifest = "AndroidManifest.xml", + resource_files = glob(["res/**"]), +) + +# A custom package is necessary when an android_local_test is under a non-java directory. +android_local_test( + name = "with_custom_package", + srcs = ["SampleTest.java"], + custom_package = "com.starlark_resources", + manifest = "AndroidManifest.xml", + test_class = "com.starlark_resources.SampleTest", + deps = [ + ":resource_processing", + "@robolectric//bazel:android-all", + "@rules_android_maven//:androidx_test_core", + "@rules_android_maven//:androidx_test_ext_junit", + "@rules_android_maven//:junit_junit", + "@rules_android_maven//:org_robolectric_robolectric", + ], +) + +rule_test( + name = "with_custom_package_rule_test", + target_under_test = ":with_custom_package", +) + +# TODO(b/161359429): Create failure test for missing custom package under a non-java directory. diff --git a/test/rules/android_local_test/non_java/SampleTest.java b/test/rules/android_local_test/non_java/SampleTest.java new file mode 100644 index 0000000..32529df --- /dev/null +++ b/test/rules/android_local_test/non_java/SampleTest.java @@ -0,0 +1,43 @@ +/** + * Copyright 2021 The Bazel Authors. All rights reserved. + * + * <p>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 + * + * <p>http://www.apache.org/licenses/LICENSE-2.0 + * + * <p>Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.starlark_resources; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.content.res.Resources; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SampleTest { + private Context targetContext; + private Resources resources; + + @Before + public void setup() throws Exception { + targetContext = ApplicationProvider.getApplicationContext(); + resources = targetContext.getResources(); + } + + @Test + public void test() throws Exception { + assertEquals("Check package name", "com.starlark_resources", targetContext.getPackageName()); + assertEquals( + "Check resource `a_string`", "Hello World!", resources.getString(R.string.a_string)); + } +} diff --git a/test/rules/android_local_test/non_java/assets/bar.txt b/test/rules/android_local_test/non_java/assets/bar.txt new file mode 100644 index 0000000..5716ca5 --- /dev/null +++ b/test/rules/android_local_test/non_java/assets/bar.txt @@ -0,0 +1 @@ +bar diff --git a/test/rules/android_local_test/non_java/res/values/strings.xml b/test/rules/android_local_test/non_java/res/values/strings.xml new file mode 100644 index 0000000..2686d09 --- /dev/null +++ b/test/rules/android_local_test/non_java/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="a_string">Hello World!</string> +</resources> diff --git a/test/rules/android_local_test/test.bzl b/test/rules/android_local_test/test.bzl new file mode 100644 index 0000000..5b1677e --- /dev/null +++ b/test/rules/android_local_test/test.bzl @@ -0,0 +1,117 @@ +# 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. + +"""Bazel rules that test the Android Local Test rule. + +rule_test: Inspect and assert on rule providers. +""" + +load("//rules:providers.bzl", "AndroidFilteredJdepsInfo") +load("//test/utils:asserts.bzl", "asserts") + +VALIDATION = "_validation" + +def _rule_test_impl(ctx): + # Assert on expected providers + if not JavaInfo in ctx.attr.target_under_test: + fail("Missing JavaInfo provider") + if not AndroidFilteredJdepsInfo in ctx.attr.target_under_test: + fail("Missing AndroidFilteredJdepsInfo provider") + + # Collecting validation outputs from deps + transitive_validation_outputs = [] + for dep in ctx.attr.deps: + if hasattr(dep[OutputGroupInfo], VALIDATION): + transitive_validation_outputs.append(dep[OutputGroupInfo]._validation) + + output_group_info = dict(ctx.attr.expected_output_group_info) + if VALIDATION in output_group_info: + output_group_info[VALIDATION] = ( + output_group_info[VALIDATION] + + [f.basename for f in depset(transitive = transitive_validation_outputs).to_list()] + ) + asserts.provider.output_group_info( + output_group_info, + ctx.attr.target_under_test[OutputGroupInfo], + ) + + # Create test script to assert on provider contents + args = dict( + jdeps_print_tool = ctx.executable._jdeps_print_tool.short_path, + jdeps = ctx.attr.target_under_test[JavaInfo].outputs.jdeps.short_path, + filtered_jdeps = ctx.attr.target_under_test[AndroidFilteredJdepsInfo].jdeps.short_path, + res_jar = ctx.attr.target_under_test.label.name + "_resources.jar", + expect_resources = str(ctx.attr.expect_resources), + ) + test_script = ctx.actions.declare_file("%s_script.sh" % ctx.label.name) + ctx.actions.write( + test_script, + """ +jdeps=`{jdeps_print_tool} --in {jdeps} | sed 's#_migrated/##g'` +filtered_jdeps=`{jdeps_print_tool} --in {filtered_jdeps} | sed 's#_migrated/##g'` + +entries=`echo "$jdeps" | wc -l` +matches=`echo "$jdeps" | grep '{res_jar}' | wc -l` +filtered_entries=`echo "$filtered_jdeps" | wc -l` +filtered_matches=`echo "$filtered_jdeps" | grep '{res_jar}' | wc -l` + +expected_matches=1 +expected_filtering_differences=1 +if [ {expect_resources} == "False" ]; then + expected_matches=0 + expected_filtering_differences=0 +fi + +if [ $matches -ne $expected_matches ]; then + echo "Expected one resource.jar in jdeps" + exit 1 +elif [ $filtered_matches -ne 0 ]; then + echo "Expected no resource.jar in filtered jdeps" + exit 1 +elif [ $(($entries-$filtered_entries)) -ne $expected_filtering_differences ]; then + echo "Expected to remove one item when filtering" + exit 1 +fi +""".format(**args), + is_executable = True, + ) + return [ + DefaultInfo( + runfiles = ctx.runfiles( + files = [ + test_script, + ctx.executable._jdeps_print_tool, + ctx.attr.target_under_test[JavaInfo].outputs.jdeps, + ctx.attr.target_under_test[AndroidFilteredJdepsInfo].jdeps, + ], + ), + executable = test_script, + ), + ] + +rule_test = rule( + attrs = dict( + asserts.provider.attrs.items(), + expect_resources = attr.bool(default = True), + target_under_test = attr.label(), + deps = attr.label_list(), + _jdeps_print_tool = attr.label( + cfg = "exec", + default = "//src/tools/jdeps:print_jdeps", + executable = True, + ), + ), + implementation = _rule_test_impl, + test = True, +) diff --git a/test/rules/android_sdk_repository/test_lib.sh b/test/rules/android_sdk_repository/test_lib.sh index 17d2485..a5abbba 100644 --- a/test/rules/android_sdk_repository/test_lib.sh +++ b/test/rules/android_sdk_repository/test_lib.sh @@ -33,6 +33,21 @@ source "$(rlocation rules_android/test/rules/android_sdk_repository/android_help # Actual tests for Android Sdk Repository +# Test that the dummy SDK exists. +function test_dummy_sdk() { + # Create android SDK + local sdk_path="$(create_android_sdk_basic)" + + cat >> WORKSPACE <<EOF +android_sdk_repository( + name = "androidsdk", + path = "${sdk_path}", +) +EOF + + "${BIT_BAZEL_BINARY}" query @androidsdk//:sdk-dummy >& $TEST_log || fail "Dummy SDK missing" +} + # Check that the empty BUILD file was created. function test_android_sdk_repository_no_path_or_android_home() { cat >> WORKSPACE <<EOF diff --git a/toolchains/android/toolchain.bzl b/toolchains/android/toolchain.bzl index 2d067ac..04e7608 100644 --- a/toolchains/android/toolchain.bzl +++ b/toolchains/android/toolchain.bzl @@ -17,6 +17,7 @@ _ATTRS = dict( aapt2 = attr.label( allow_files = True, + cfg = "exec", default = "@androidsdk//:aapt2_binary", ), aar_import_checks = attr.label( diff --git a/tools/android/BUILD b/tools/android/BUILD index 922e7e3..2d323aa 100644 --- a/tools/android/BUILD +++ b/tools/android/BUILD @@ -17,6 +17,7 @@ genrule( outs = ["fail.sh"], cmd = "echo 'exit 1' > $@", executable = 1, + visibility = ["//visibility:public"], ) sh_binary( @@ -43,7 +44,7 @@ java_plugin( alias( name = "java8_legacy_dex", - actual = "@bazel_tools//tools/android:java8_legacy_dex", + actual = ":gen_fail", visibility = ["//visibility:public"], ) @@ -55,11 +56,19 @@ alias( alias( name = "desugared_java8_legacy_apis", - actual = "@bazel_tools//tools/android:desugared_java8_legacy_apis", + actual = ":gen_fail", # TODO(#122): Fix library desugaring visibility = ["//visibility:public"], ) java_binary( + name = "d8", + main_class = "com.android.tools.r8.D8", + visibility = ["//visibility:public"], + runtime_deps = ["@android_gmaven_r8//jar"], +) + + +java_binary( name = "r8", main_class = "com.android.tools.r8.R8", visibility = ["//visibility:public"], |