1# Copyright 2020 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Implementation.""" 16 17load("//rules:acls.bzl", "acls") 18load("//rules:baseline_profiles.bzl", _baseline_profiles = "baseline_profiles") 19load("//rules:common.bzl", "common") 20load("//rules:data_binding.bzl", "data_binding") 21load("//rules:desugar.bzl", _desugar = "desugar") 22load("//rules:dex.bzl", _dex = "dex") 23load("//rules:dex_desugar_aspect.bzl", _get_dex_desugar_aspect_deps = "get_aspect_deps") 24load("//rules:java.bzl", "java") 25load( 26 "//rules:native_deps.bzl", 27 _process_native_deps = "process", 28) 29load( 30 "//rules:processing_pipeline.bzl", 31 "ProviderInfo", 32 "processing_pipeline", 33) 34load("//rules:proguard.bzl", "proguard") 35load("//rules:providers.bzl", "StarlarkAndroidDexInfo", "StarlarkApkInfo") 36load("//rules:resources.bzl", _resources = "resources") 37load( 38 "//rules:utils.bzl", 39 "ANDROID_TOOLCHAIN_TYPE", 40 "compilation_mode", 41 "get_android_sdk", 42 "get_android_toolchain", 43 "utils", 44) 45load(":r8.bzl", "process_r8", "process_resource_shrinking_r8") 46 47def _base_validations_processor(ctx, **_unused_ctxs): 48 if ctx.attr.min_sdk_version != 0 and not acls.in_android_binary_min_sdk_version_attribute_allowlist(str(ctx.label)): 49 fail("Target %s is not allowed to set a min_sdk_version value." % str(ctx.label)) 50 51def _process_manifest(ctx, **unused_ctxs): 52 manifest_ctx = _resources.bump_min_sdk( 53 ctx, 54 manifest = ctx.file.manifest, 55 manifest_values = ctx.attr.manifest_values, 56 floor = acls.get_min_sdk_floor(str(ctx.label)) if _is_test_binary(ctx) else 0, 57 enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, 58 ) 59 60 return ProviderInfo( 61 name = "manifest_ctx", 62 value = manifest_ctx, 63 ) 64 65def _process_resources(ctx, manifest_ctx, java_package, **unused_ctxs): 66 resource_apks = [] 67 for apk in utils.collect_providers(StarlarkApkInfo, ctx.attr.resource_apks): 68 resource_apks.append(apk.signed_apk) 69 70 packaged_resources_ctx = _resources.package( 71 ctx, 72 assets = ctx.files.assets, 73 assets_dir = ctx.attr.assets_dir, 74 resource_files = ctx.files.resource_files, 75 manifest = manifest_ctx.processed_manifest, 76 manifest_values = manifest_ctx.processed_manifest_values, 77 resource_configs = ctx.attr.resource_configuration_filters, 78 densities = ctx.attr.densities, 79 nocompress_extensions = ctx.attr.nocompress_extensions, 80 java_package = java_package, 81 compilation_mode = compilation_mode.get(ctx), 82 shrink_resources = ctx.attr.shrink_resources, 83 use_android_resource_shrinking = ctx.fragments.android.use_android_resource_shrinking, 84 use_android_resource_cycle_shrinking = ctx.fragments.android.use_android_resource_cycle_shrinking, 85 use_legacy_manifest_merger = use_legacy_manifest_merger(ctx), 86 should_throw_on_conflict = not acls.in_allow_resource_conflicts(str(ctx.label)), 87 enable_data_binding = ctx.attr.enable_data_binding, 88 enable_manifest_merging = ctx.attr._enable_manifest_merging, 89 deps = utils.dedupe_split_attr(ctx.split_attr.deps), 90 resource_apks = resource_apks, 91 instruments = ctx.attr.instruments, 92 aapt = get_android_toolchain(ctx).aapt2.files_to_run, 93 android_jar = get_android_sdk(ctx).android_jar, 94 legacy_merger = ctx.attr._android_manifest_merge_tool.files_to_run, 95 xsltproc = ctx.attr._xsltproc_tool.files_to_run, 96 instrument_xslt = ctx.file._add_g3itr_xslt, 97 busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, 98 host_javabase = ctx.attr._host_javabase, 99 # The AndroidApplicationResourceInfo will be added to the list of providers in finalize() 100 # if R8-based resource shrinking is not performed. 101 add_application_resource_info_to_providers = False, 102 ) 103 return ProviderInfo( 104 name = "packaged_resources_ctx", 105 value = packaged_resources_ctx, 106 ) 107 108def _validate_manifest(ctx, packaged_resources_ctx, **unused_ctxs): 109 manifest_validation_ctx = _resources.validate_min_sdk( 110 ctx, 111 manifest = packaged_resources_ctx.processed_manifest, 112 floor = acls.get_min_sdk_floor(str(ctx.label)), 113 enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, 114 ) 115 116 return ProviderInfo( 117 name = "manifest_validation_ctx", 118 value = manifest_validation_ctx, 119 ) 120 121def _process_native_libs(ctx, **_unusued_ctxs): 122 providers = [] 123 if acls.in_android_binary_starlark_split_transition(str(ctx.label)): 124 providers.append(_process_native_deps( 125 ctx, 126 filename = "nativedeps", 127 )) 128 return ProviderInfo( 129 name = "native_libs_ctx", 130 value = struct(providers = providers), 131 ) 132 133def _process_build_stamp(_unused_ctx, **_unused_ctxs): 134 return ProviderInfo( 135 name = "stamp_ctx", 136 value = struct( 137 resource_files = [], 138 deps = [], 139 java_info = None, 140 providers = [], 141 ), 142 ) 143 144def _process_proto(_unused_ctx, **_unused_ctxs): 145 return ProviderInfo( 146 name = "proto_ctx", 147 value = struct( 148 providers = [], 149 class_jar = None, 150 ), 151 ) 152 153def _process_data_binding(ctx, java_package, packaged_resources_ctx, **_unused_ctxs): 154 if ctx.attr.enable_data_binding and not acls.in_databinding_allowed(str(ctx.label)): 155 fail("This target is not allowed to use databinding and enable_data_binding is True.") 156 return ProviderInfo( 157 name = "db_ctx", 158 value = data_binding.process( 159 ctx, 160 defines_resources = True, 161 enable_data_binding = ctx.attr.enable_data_binding, 162 java_package = java_package, 163 layout_info = packaged_resources_ctx.data_binding_layout_info, 164 artifact_type = "APPLICATION", 165 deps = utils.collect_providers(DataBindingV2Info, utils.dedupe_split_attr(ctx.split_attr.deps)), 166 data_binding_exec = get_android_toolchain(ctx).data_binding_exec.files_to_run, 167 data_binding_annotation_processor = 168 get_android_toolchain(ctx).data_binding_annotation_processor[JavaPluginInfo], 169 data_binding_annotation_template = 170 utils.only(get_android_toolchain(ctx).data_binding_annotation_template.files.to_list()), 171 ), 172 ) 173 174def _process_jvm(ctx, db_ctx, packaged_resources_ctx, stamp_ctx, **_unused_ctxs): 175 native_name = ctx.label.name.removesuffix(common.PACKAGED_RESOURCES_SUFFIX) 176 java_info = java.compile_android( 177 ctx, 178 # Use the same format as the class jar from native android_binary. 179 # Some macros expect the class jar to be named like this. 180 ctx.actions.declare_file("%s/lib%s.jar" % (ctx.label.name, native_name)), 181 ctx.actions.declare_file(ctx.label.name + "-src.jar"), 182 srcs = ctx.files.srcs + db_ctx.java_srcs, 183 javac_opts = ctx.attr.javacopts + db_ctx.javac_opts, 184 r_java = packaged_resources_ctx.r_java, 185 enable_deps_without_srcs = True, 186 deps = utils.collect_providers(JavaInfo, utils.dedupe_split_attr(ctx.split_attr.deps) + stamp_ctx.deps), 187 plugins = 188 utils.collect_providers(JavaPluginInfo, ctx.attr.plugins) + 189 db_ctx.java_plugins, 190 annotation_processor_additional_outputs = 191 db_ctx.java_annotation_processor_additional_outputs, 192 annotation_processor_additional_inputs = 193 db_ctx.java_annotation_processor_additional_inputs, 194 strict_deps = "DEFAULT", 195 java_toolchain = common.get_java_toolchain(ctx), 196 ) 197 java_info = java_common.add_constraints( 198 java_info, 199 constraints = ["android"], 200 ) 201 202 providers = [] 203 if acls.in_android_binary_starlark_javac(str(ctx.label)): 204 providers.append(java_info) 205 206 return ProviderInfo( 207 name = "jvm_ctx", 208 value = struct( 209 java_info = java_info, 210 providers = providers, 211 ), 212 ) 213 214def _process_build_info(_unused_ctx, **unused_ctxs): 215 return ProviderInfo( 216 name = "build_info_ctx", 217 value = struct( 218 deploy_manifest_lines = [], 219 providers = [], 220 ), 221 ) 222 223def _process_dex(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, proto_ctx, deploy_ctx, bp_ctx, optimize_ctx, **_unused_ctxs): 224 providers = [] 225 classes_dex_zip = None 226 dex_info = None 227 final_classes_dex_zip = None 228 final_proguard_output_map = None 229 postprocessing_output_map = None 230 deploy_jar = deploy_ctx.deploy_jar 231 is_binary_optimized = len(ctx.attr.proguard_specs) > 0 232 main_dex_list = ctx.file.main_dex_list 233 multidex = ctx.attr.multidex 234 optimizing_dexer = ctx.attr._optimizing_dexer 235 java8_legacy_dex_map = None 236 237 if acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label)): 238 proguarded_jar = optimize_ctx.proguard_output.output_jar if is_binary_optimized else None 239 proguard_output_map = optimize_ctx.proguard_output.mapping if is_binary_optimized else None 240 binary_jar = proguarded_jar if proguarded_jar else deploy_jar 241 java_info = java_common.merge([jvm_ctx.java_info, stamp_ctx.java_info]) if stamp_ctx.java_info else jvm_ctx.java_info 242 runtime_jars = java_info.runtime_output_jars + [packaged_resources_ctx.class_jar] 243 if proto_ctx.class_jar: 244 runtime_jars.append(proto_ctx.class_jar) 245 forbidden_dexopts = ctx.fragments.android.get_target_dexopts_that_prevent_incremental_dexing 246 247 if (main_dex_list and multidex != "manual_main_dex") or \ 248 (not main_dex_list and multidex == "manual_main_dex"): 249 fail("Both \"main_dex_list\" and \"multidex='manual_main_dex'\" must be specified.") 250 251 # Multidex mode: generate classes.dex.zip, where the zip contains 252 # [classes.dex, classes2.dex, ... classesN.dex] 253 if ctx.attr.multidex == "legacy": 254 main_dex_list = _dex.generate_main_dex_list( 255 ctx, 256 jar = binary_jar, 257 android_jar = get_android_sdk(ctx).android_jar, 258 desugar_java8_libs = ctx.fragments.android.desugar_java8_libs, 259 legacy_apis = ctx.files._desugared_java8_legacy_apis, 260 main_dex_classes = get_android_sdk(ctx).main_dex_classes, 261 main_dex_list_opts = ctx.attr.main_dex_list_opts, 262 main_dex_proguard_spec = packaged_resources_ctx.main_dex_proguard_config, 263 proguard_specs = list(ctx.files.main_dex_proguard_specs), 264 shrinked_android_jar = get_android_sdk(ctx).shrinked_android_jar, 265 main_dex_list_creator = get_android_sdk(ctx).main_dex_list_creator, 266 legacy_main_dex_list_generator = 267 ctx.attr._legacy_main_dex_list_generator.files_to_run if ctx.attr._legacy_main_dex_list_generator else get_android_sdk(ctx).legacy_main_dex_list_generator, 268 proguard_tool = get_android_sdk(ctx).proguard, 269 ) 270 elif ctx.attr.multidex == "manual_main_dex": 271 main_dex_list = _dex.transform_dex_list_through_proguard_map( 272 ctx, 273 proguard_output_map = proguard_output_map, 274 main_dex_list = main_dex_list, 275 dex_list_obfuscator = get_android_toolchain(ctx).dex_list_obfuscator.files_to_run, 276 ) 277 278 # TODO(b/261110876): potentially add codepaths below to support rex (postprocessingRewritesMap) 279 if proguard_output_map: 280 # Proguard map from preprocessing will be merged with Proguard map for desugared 281 # library. 282 if optimizing_dexer and ctx.fragments.android.desugar_java8_libs: 283 postprocessing_output_map = _dex.get_dx_artifact(ctx, "_proguard_output_for_desugared_library.map") 284 final_proguard_output_map = _dex.get_dx_artifact(ctx, "_proguard.map") 285 286 elif optimizing_dexer: 287 # No desugared library, Proguard map from postprocessing is the final Proguard map. 288 postprocessing_output_map = _dex.get_dx_artifact(ctx, "_proguard.map") 289 final_proguard_output_map = postprocessing_output_map 290 291 elif ctx.fragments.android.desugar_java8_libs: 292 # No postprocessing, Proguard map from merging with the desugared library map is the 293 # final Proguard map. 294 postprocessing_output_map = proguard_output_map 295 final_proguard_output_map = _dex.get_dx_artifact(ctx, "_proguard.map") 296 297 else: 298 # No postprocessing, no desugared library, the final Proguard map is the Proguard map 299 # from shrinking 300 postprocessing_output_map = proguard_output_map 301 final_proguard_output_map = proguard_output_map 302 303 incremental_dexing = _dex.get_effective_incremental_dexing( 304 force_incremental_dexing = ctx.attr.incremental_dexing, 305 has_forbidden_dexopts = len([d for d in ctx.attr.dexopts if d in forbidden_dexopts]) > 0, 306 is_binary_optimized = is_binary_optimized, 307 incremental_dexing_after_proguard_by_default = ctx.fragments.android.incremental_dexing_after_proguard_by_default, 308 incremental_dexing_shards_after_proguard = ctx.fragments.android.incremental_dexing_shards_after_proguard, 309 use_incremental_dexing = ctx.fragments.android.use_incremental_dexing, 310 ) 311 312 classes_dex_zip = _dex.get_dx_artifact(ctx, "classes.dex.zip") 313 if optimizing_dexer and is_binary_optimized: 314 _dex.process_optimized_dexing( 315 ctx, 316 output = classes_dex_zip, 317 input = proguarded_jar, 318 proguard_output_map = proguard_output_map, 319 postprocessing_output_map = postprocessing_output_map, 320 dexopts = ctx.attr.dexopts, 321 native_multidex = multidex == "native", 322 min_sdk_version = ctx.attr.min_sdk_version, 323 main_dex_list = main_dex_list, 324 library_jar = optimize_ctx.proguard_output.library_jar, 325 startup_profile = bp_ctx.baseline_profile_output.startup_profile if bp_ctx.baseline_profile_output else None, 326 optimizing_dexer = optimizing_dexer.files_to_run, 327 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 328 ) 329 elif incremental_dexing: 330 _dex.process_incremental_dexing( 331 ctx, 332 output = classes_dex_zip, 333 deps = _get_dex_desugar_aspect_deps(ctx), 334 dexopts = ctx.attr.dexopts, 335 runtime_jars = runtime_jars, 336 main_dex_list = main_dex_list, 337 min_sdk_version = ctx.attr.min_sdk_version, 338 proguarded_jar = proguarded_jar, 339 java_info = java_info, 340 desugar_dict = deploy_ctx.desugar_dict, 341 shuffle_jars = get_android_toolchain(ctx).shuffle_jars.files_to_run, 342 dexbuilder = get_android_toolchain(ctx).dexbuilder.files_to_run, 343 dexbuilder_after_proguard = get_android_toolchain(ctx).dexbuilder_after_proguard.files_to_run, 344 dexmerger = get_android_toolchain(ctx).dexmerger.files_to_run, 345 dexsharder = get_android_toolchain(ctx).dexsharder.files_to_run, 346 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 347 ) 348 else: 349 _dex.process_monolithic_dexing( 350 ctx, 351 output = classes_dex_zip, 352 input = proguarded_jar, 353 dexopts = ctx.attr.dexopts, 354 min_sdk_version = ctx.attr.min_sdk_version, 355 main_dex_list = main_dex_list, 356 dexbuilder = get_android_sdk(ctx).dx, 357 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 358 ) 359 360 if ctx.fragments.android.desugar_java8_libs and classes_dex_zip.extension == "zip": 361 final_classes_dex_zip = _dex.get_dx_artifact(ctx, "final_classes_dex.zip") 362 363 java8_legacy_dex, java8_legacy_dex_map = _dex.get_java8_legacy_dex_and_map( 364 ctx, 365 android_jar = get_android_sdk(ctx).android_jar, 366 binary_jar = binary_jar, 367 build_customized_files = is_binary_optimized, 368 ) 369 370 if final_proguard_output_map: 371 proguard.merge_proguard_maps( 372 ctx, 373 output = final_proguard_output_map, 374 inputs = [java8_legacy_dex_map, postprocessing_output_map], 375 proguard_maps_merger = get_android_toolchain(ctx).proguard_maps_merger.files_to_run, 376 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 377 ) 378 379 _dex.append_java8_legacy_dex( 380 ctx, 381 output = final_classes_dex_zip, 382 input = classes_dex_zip, 383 java8_legacy_dex = java8_legacy_dex, 384 dex_zips_merger = get_android_toolchain(ctx).dex_zips_merger.files_to_run, 385 ) 386 else: 387 final_classes_dex_zip = classes_dex_zip 388 final_proguard_output_map = postprocessing_output_map if postprocessing_output_map else proguard_output_map 389 390 dex_info = AndroidDexInfo( 391 deploy_jar = deploy_jar, 392 filtered_deploy_jar = deploy_ctx.filtered_deploy_jar, 393 final_classes_dex_zip = final_classes_dex_zip, 394 final_proguard_output_map = final_proguard_output_map, 395 java_resource_jar = binary_jar if ctx.fragments.android.get_java_resources_from_optimized_jar else deploy_jar, 396 ) 397 providers.append(dex_info) 398 providers.append(AndroidPreDexJarInfo(binary_jar)) 399 400 if postprocessing_output_map: 401 providers.append(ProguardMappingInfo(postprocessing_output_map)) 402 403 return ProviderInfo( 404 name = "dex_ctx", 405 value = struct( 406 dex_info = dex_info, 407 java8_legacy_dex_map = java8_legacy_dex_map, 408 providers = providers, 409 ), 410 ) 411 412def _process_deploy_jar(ctx, stamp_ctx, packaged_resources_ctx, jvm_ctx, build_info_ctx, proto_ctx, **_unused_ctxs): 413 deploy_jar, filtered_deploy_jar, desugar_dict = None, None, {} 414 415 if acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label)): 416 java_toolchain = common.get_java_toolchain(ctx) 417 java_info = java_common.merge([jvm_ctx.java_info, stamp_ctx.java_info]) if stamp_ctx.java_info else jvm_ctx.java_info 418 info = _dex.merge_infos(utils.collect_providers(StarlarkAndroidDexInfo, _get_dex_desugar_aspect_deps(ctx))) 419 incremental_dexopts = _dex.filter_dexopts(ctx.attr.dexopts, ctx.fragments.android.get_dexopts_supported_in_incremental_dexing) 420 dex_archives = info.dex_archives_dict.get("".join(incremental_dexopts), depset()).to_list() 421 binary_runtime_jars = java_info.runtime_output_jars + [packaged_resources_ctx.class_jar] 422 if proto_ctx.class_jar: 423 binary_runtime_jars.append(proto_ctx.class_jar) 424 425 if ctx.fragments.android.desugar_java8: 426 desugared_jars = [] 427 desugar_dict = {d.jar: d.desugared_jar for d in dex_archives} 428 429 for jar in binary_runtime_jars: 430 desugared_jar = ctx.actions.declare_file(ctx.label.name + "/" + jar.basename + "_migrated_desugared.jar") 431 _desugar.desugar( 432 ctx, 433 input = jar, 434 output = desugared_jar, 435 classpath = java_info.transitive_compile_time_jars, 436 bootclasspath = java_toolchain[java_common.JavaToolchainInfo].bootclasspath.to_list(), 437 min_sdk_version = ctx.attr.min_sdk_version, 438 desugar_exec = get_android_toolchain(ctx).desugar.files_to_run, 439 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 440 ) 441 desugared_jars.append(desugared_jar) 442 desugar_dict[jar] = desugared_jar 443 444 for jar in java_info.transitive_runtime_jars.to_list(): 445 if jar in desugar_dict: 446 desugared_jars.append(desugar_dict[jar] if desugar_dict[jar] else jar) 447 448 runtime_jars = depset(desugared_jars) 449 else: 450 runtime_jars = depset(binary_runtime_jars, transitive = [java_info.transitive_runtime_jars]) 451 452 output = ctx.actions.declare_file(ctx.label.name + "_migrated_deploy.jar") 453 deploy_jar = java.create_deploy_jar( 454 ctx, 455 output = output, 456 runtime_jars = runtime_jars, 457 java_toolchain = java_toolchain, 458 build_target = ctx.label.name, 459 deploy_manifest_lines = build_info_ctx.deploy_manifest_lines, 460 ) 461 462 if _is_instrumentation(ctx): 463 filtered_deploy_jar = ctx.actions.declare_file(ctx.label.name + "_migrated_filtered.jar") 464 465 # TODO(b/303286042): Use AndroidPreDexInfo.pre_dex_jar to be the filter_jar 466 filter_jar = ctx.attr.instruments[ApkInfo].deploy_jar 467 common.filter_zip_exclude( 468 ctx, 469 output = filtered_deploy_jar, 470 input = deploy_jar, 471 filter_zips = [filter_jar], 472 filter_types = [".class"], 473 # These files are generated by databinding in both the target and the instrumentation 474 # app with different contents. We want to keep the one from the target app. 475 filters = ["/BR\\.class$", "/databinding/[^/]+Binding\\.class$"], 476 ) 477 deploy_jar = filtered_deploy_jar 478 479 return ProviderInfo( 480 name = "deploy_ctx", 481 value = struct( 482 deploy_jar = deploy_jar, 483 desugar_dict = desugar_dict, 484 filtered_deploy_jar = filtered_deploy_jar, 485 providers = [], 486 ), 487 ) 488 489def use_legacy_manifest_merger(ctx): 490 """Whether legacy manifest merging is enabled. 491 492 Args: 493 ctx: The context. 494 495 Returns: 496 Boolean indicating whether legacy manifest merging is enabled. 497 """ 498 manifest_merger = ctx.attr.manifest_merger 499 android_manifest_merger = ctx.fragments.android.manifest_merger 500 501 if android_manifest_merger == "force_android": 502 return False 503 if manifest_merger == "auto": 504 manifest_merger = android_manifest_merger 505 506 return manifest_merger == "legacy" 507 508def finalize( 509 _unused_ctx, 510 providers, 511 validation_outputs, 512 packaged_resources_ctx, 513 resource_shrinking_r8_ctx, 514 **_unused_ctxs): 515 """Final step of the android_binary_internal processor pipeline. 516 517 Args: 518 _unused_ctx: The context. 519 providers: The list of providers for the android_binary_internal rule. 520 validation_outputs: Validation outputs for the rule. 521 packaged_resources_ctx: The packaged resources from the resource processing step. 522 resource_shrinking_r8_ctx: The context from the R8 resource shrinking step. 523 **_unused_ctxs: Other contexts. 524 525 Returns: 526 The list of providers the android_binary_internal rule should return. 527 """ 528 providers.append( 529 OutputGroupInfo( 530 _validation = depset(validation_outputs), 531 ), 532 ) 533 534 # Add the AndroidApplicationResourceInfo provider from resource shrinking if it was performed. 535 # TODO(ahumesky): This can be cleaned up after the rules are fully migrated to Starlark. 536 # Packaging will be the final step in the pipeline, and that step can be responsible for picking 537 # between the two different contexts. Then this finalize can return back to its "simple" form. 538 if resource_shrinking_r8_ctx.android_application_resource_info_with_shrunk_resource_apk: 539 providers.append( 540 resource_shrinking_r8_ctx.android_application_resource_info_with_shrunk_resource_apk, 541 ) 542 else: 543 providers.append(packaged_resources_ctx.android_application_resource) 544 545 return providers 546 547def _is_test_binary(ctx): 548 """Whether this android_binary target is a test binary. 549 550 Args: 551 ctx: The context. 552 553 Returns: 554 Boolean indicating whether the target is a test target. 555 """ 556 return ctx.attr.testonly or _is_instrumentation(ctx) or str(ctx.label).find("/javatests/") >= 0 557 558def _is_instrumentation(ctx): 559 """Whether this android_binary target is an instrumentation binary. 560 561 Args: 562 ctx: The context. 563 564 Returns: 565 Boolean indicating whether the target is an instrumentation target. 566 567 """ 568 return bool(ctx.attr.instruments) 569 570def _process_baseline_profiles(ctx, deploy_ctx, **_unused_ctxs): 571 baseline_profile_output = None 572 if (ctx.attr.generate_art_profile and 573 acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label))): 574 enable_optimizer_integration = acls.in_baseline_profiles_optimizer_integration(str(ctx.label)) 575 has_proguard_specs = bool(ctx.files.proguard_specs) 576 577 if ctx.files.startup_profiles and not enable_optimizer_integration: 578 fail("Target %s is not allowed to set startup_profiles." % str(ctx.label)) 579 580 # Include startup profiles if the optimizer is disabled since profiles won't be merged 581 # in the optimizer. 582 transitive_profiles = depset( 583 ctx.files.startup_profiles if enable_optimizer_integration and not has_proguard_specs else [], 584 transitive = [ 585 profile_provider.files 586 for profile_provider in utils.collect_providers( 587 BaselineProfileProvider, 588 ctx.attr.deps, 589 ) 590 ], 591 ) 592 baseline_profile_output = _baseline_profiles.process( 593 ctx, 594 transitive_profiles = transitive_profiles, 595 startup_profiles = ctx.files.startup_profiles, 596 deploy_jar = deploy_ctx.deploy_jar, 597 has_proguard_specs = has_proguard_specs, 598 enable_optimizer_integration = enable_optimizer_integration, 599 merge_tool = get_android_toolchain(ctx).merge_baseline_profiles_tool.files_to_run, 600 profgen = get_android_toolchain(ctx).profgen.files_to_run, 601 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 602 ) 603 return ProviderInfo( 604 name = "bp_ctx", 605 value = struct( 606 baseline_profile_output = baseline_profile_output, 607 ), 608 ) 609 610def _process_art_profile(ctx, bp_ctx, dex_ctx, optimize_ctx, **_unused_ctxs): 611 providers = [] 612 if (ctx.attr.generate_art_profile and 613 acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label))): 614 merged_baseline_profile = bp_ctx.baseline_profile_output.baseline_profile 615 merged_baseline_profile_rewritten = \ 616 optimize_ctx.proguard_output.baseline_profile_rewritten if optimize_ctx.proguard_output else None 617 proguard_output_map = dex_ctx.dex_info.final_proguard_output_map 618 619 if acls.in_baseline_profiles_optimizer_integration(str(ctx.label)): 620 # Minified symbols are emitted when rewriting, so only use map for symbols which 621 # weren't passed to bytecode optimizer (if it exists). 622 proguard_output_map = dex_ctx.java8_legacy_dex_map 623 624 # At this point, either baseline profile here also contains startup-profiles, if any. 625 if merged_baseline_profile_rewritten: 626 merged_baseline_profile = merged_baseline_profile_rewritten 627 if merged_baseline_profile: 628 providers.append(_baseline_profiles.process_art_profile( 629 ctx, 630 final_classes_dex = dex_ctx.dex_info.final_classes_dex_zip, 631 merged_profile = merged_baseline_profile, 632 proguard_output_map = proguard_output_map, 633 profgen = get_android_toolchain(ctx).profgen.files_to_run, 634 zipper = get_android_toolchain(ctx).zipper.files_to_run, 635 toolchain_type = ANDROID_TOOLCHAIN_TYPE, 636 )) 637 return ProviderInfo( 638 name = "ap_ctx", 639 value = struct(providers = providers), 640 ) 641 642def _process_optimize(ctx, deploy_ctx, packaged_resources_ctx, bp_ctx, **_unused_ctxs): 643 if not acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label)): 644 return ProviderInfo( 645 name = "optimize_ctx", 646 value = struct(), 647 ) 648 649 # Validate attributes and lockdown lists 650 if ctx.file.proguard_apply_mapping and not acls.in_allow_proguard_apply_mapping(str(ctx.label)): 651 fail("proguard_apply_mapping is not supported") 652 if ctx.file.proguard_apply_mapping and not ctx.files.proguard_specs: 653 fail("proguard_apply_mapping can only be used when proguard_specs is set") 654 655 proguard_specs = proguard.get_proguard_specs( 656 ctx, 657 packaged_resources_ctx.resource_proguard_config, 658 proguard_specs_for_manifest = [packaged_resources_ctx.resource_minsdk_proguard_config] if packaged_resources_ctx.resource_minsdk_proguard_config else [], 659 ) 660 has_proguard_specs = bool(proguard_specs) 661 662 is_resource_shrinking_enabled = _resources.is_resource_shrinking_enabled( 663 ctx.attr.shrink_resources, 664 ctx.fragments.android.use_android_resource_shrinking, 665 ) 666 proguard_output_map = None 667 generate_proguard_map = ( 668 ctx.attr.proguard_generate_mapping or is_resource_shrinking_enabled 669 ) 670 desugar_java8_libs_generates_map = ctx.fragments.android.desugar_java8 671 optimizing_dexing = bool(ctx.attr._optimizing_dexer) 672 673 # TODO(b/261110876): potentially add codepaths below to support rex (postprocessingRewritesMap) 674 if generate_proguard_map: 675 # Determine the output of the Proguard map from shrinking the app. This depends on the 676 # additional steps which can process the map before the final Proguard map artifact is 677 # generated. 678 if not has_proguard_specs: 679 # When no shrinking happens a generating rule for the output map artifact is still needed. 680 proguard_output_map = proguard.get_proguard_output_map(ctx) 681 elif optimizing_dexing: 682 proguard_output_map = proguard.get_proguard_temp_artifact(ctx, "pre_dexing.map") 683 elif desugar_java8_libs_generates_map: 684 # Proguard map from shrinking will be merged with desugared library proguard map. 685 proguard_output_map = _dex.get_dx_artifact(ctx, "_proguard_output_for_desugared_library.map") 686 else: 687 # Proguard map from shrinking is the final output. 688 proguard_output_map = proguard.get_proguard_output_map(ctx) 689 690 proguard_output_jar = ctx.actions.declare_file(ctx.label.name + "_migrated_proguard.jar") 691 proguard_seeds = ctx.actions.declare_file(ctx.label.name + "_migrated_proguard.seeds") 692 proguard_usage = ctx.actions.declare_file(ctx.label.name + "_migrated_proguard.usage") 693 694 startup_profile = None 695 baseline_profile = None 696 if acls.in_baseline_profiles_optimizer_integration(str(ctx.label)) and bp_ctx.baseline_profile_output: 697 startup_profile = bp_ctx.baseline_profile_output.startup_profile 698 baseline_profile = bp_ctx.baseline_profile_output.baseline_profile 699 700 proguard_output = proguard.apply_proguard( 701 ctx, 702 input_jar = deploy_ctx.deploy_jar, 703 proguard_specs = proguard_specs, 704 proguard_optimization_passes = getattr(ctx.attr, "proguard_optimization_passes", None), 705 proguard_output_jar = proguard_output_jar, 706 proguard_mapping = ctx.file.proguard_apply_mapping, 707 proguard_output_map = proguard_output_map, 708 proguard_seeds = proguard_seeds, 709 proguard_usage = proguard_usage, 710 startup_profile = startup_profile, 711 baseline_profile = baseline_profile, 712 proguard_tool = get_android_sdk(ctx).proguard, 713 ) 714 715 use_resource_shrinking = is_resource_shrinking_enabled and has_proguard_specs 716 shrunk_resource_output = None 717 if use_resource_shrinking: 718 shrunk_resource_output = _resources.shrink( 719 ctx, 720 resources_zip = packaged_resources_ctx.validation_result, 721 aapt = get_android_toolchain(ctx).aapt2.files_to_run, 722 android_jar = get_android_sdk(ctx).android_jar, 723 r_txt = packaged_resources_ctx.r_txt, 724 shrunk_jar = proguard_output_jar, 725 proguard_mapping = proguard_output_map, 726 busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, 727 host_javabase = common.get_host_javabase(ctx), 728 ) 729 730 optimized_resource_output = _resources.optimize( 731 ctx, 732 resources_apk = shrunk_resource_output.resources_apk if use_resource_shrinking else packaged_resources_ctx.resources_apk, 733 resource_optimization_config = shrunk_resource_output.optimization_config if use_resource_shrinking else None, 734 is_resource_shrunk = use_resource_shrinking, 735 aapt = get_android_toolchain(ctx).aapt2.files_to_run, 736 busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, 737 host_javabase = common.get_host_javabase(ctx), 738 ) 739 740 providers = [] 741 providers.append( 742 AndroidOptimizationInfo( 743 optimized_jar = proguard_output.output_jar, 744 mapping = proguard_output.mapping, 745 seeds = proguard_output.seeds, 746 library_jar = proguard_output.library_jar, 747 config = proguard_output.config, 748 proto_mapping = proguard_output.proto_mapping, 749 rewritten_startup_profile = proguard_output.startup_profile_rewritten, 750 rewriten_merged_baseline_profile = proguard_output.baseline_profile_rewritten, 751 optimized_resource_apk = optimized_resource_output.resources_apk, 752 shrunk_resource_apk = shrunk_resource_output.resources_apk if shrunk_resource_output else None, 753 shrunk_resource_zip = shrunk_resource_output.resources_zip if shrunk_resource_output else None, 754 resource_shrinker_log = shrunk_resource_output.shrinker_log if shrunk_resource_output else None, 755 resource_optimization_config = shrunk_resource_output.optimization_config if shrunk_resource_output else None, 756 resource_path_shortening_map = optimized_resource_output.path_shortening_map, 757 ), 758 ) 759 760 return ProviderInfo( 761 name = "optimize_ctx", 762 value = struct( 763 proguard_output = proguard_output, 764 providers = providers, 765 ), 766 ) 767 768# Order dependent, as providers will not be available to downstream processors 769# that may depend on the provider. Iteration order for a dictionary is based on 770# insertion. 771# buildifier: leave-alone 772PROCESSORS = dict( 773 BaseValidationsProcessor = _base_validations_processor, 774 ManifestProcessor = _process_manifest, 775 StampProcessor = _process_build_stamp, 776 ResourceProcessor = _process_resources, 777 ValidateManifestProcessor = _validate_manifest, 778 NativeLibsProcessor = _process_native_libs, 779 DataBindingProcessor = _process_data_binding, 780 JvmProcessor = _process_jvm, 781 BuildInfoProcessor = _process_build_info, 782 ProtoProcessor = _process_proto, 783 DeployJarProcessor = _process_deploy_jar, 784 BaselineProfilesProcessor = _process_baseline_profiles, 785 OptimizeProcessor = _process_optimize, 786 DexProcessor = _process_dex, 787 ArtProfileProcessor = _process_art_profile, 788 R8Processor = process_r8, 789 ResourecShrinkerR8Processor = process_resource_shrinking_r8, 790) 791 792_PROCESSING_PIPELINE = processing_pipeline.make_processing_pipeline( 793 processors = PROCESSORS, 794 finalize = finalize, 795) 796 797def impl(ctx): 798 """The rule implementation. 799 800 Args: 801 ctx: The context. 802 803 Returns: 804 A list of providers. 805 """ 806 java_package = java.resolve_package_from_label(ctx.label, ctx.attr.custom_package) 807 return processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE) 808