1# Copyright 2018 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:attrs.bzl", _attrs = "attrs") 19load("//rules:common.bzl", _common = "common") 20load("//rules:data_binding.bzl", _data_binding = "data_binding") 21load("//rules:idl.bzl", _idl = "idl") 22load("//rules:intellij.bzl", _intellij = "intellij") 23load("//rules:java.bzl", _java = "java") 24load( 25 "//rules:processing_pipeline.bzl", 26 "ProviderInfo", 27 "processing_pipeline", 28) 29load("//rules:proguard.bzl", _proguard = "proguard") 30load("//rules:providers.bzl", "AndroidLintRulesInfo", "StarlarkApkInfo") 31load("//rules:resources.bzl", _resources = "resources") 32load("//rules:utils.bzl", "get_android_sdk", "get_android_toolchain", "log", "utils") 33load("//rules/flags:flags.bzl", _flags = "flags") 34 35_USES_DEPRECATED_IMPLICIT_EXPORT_ERROR = ( 36 "Use android_library.exports to explicitly specify the exported " + 37 "targets of %s." 38) 39 40_SRCS_CONTAIN_RESOURCE_LABEL_ERROR = ( 41 "The srcs attribute of an android_library rule should not contain label " + 42 "with resources %s" 43) 44 45_IDL_IMPORT_ROOT_SET_WITHOUT_SRCS_OR_PARCELABLES_ERROR = ( 46 "The 'idl_import_root' attribute of the android_library rule was set, " + 47 "but neither 'idl_srcs' nor 'idl_parcelables' were specified." 48) 49 50_IDL_SRC_FROM_DIFFERENT_PACKAGE_ERROR = ( 51 "Do not import '%s' directly. You should either move the file to this " + 52 "package or depend on an appropriate rule there." 53) 54 55_IDL_USES_AOSP_COMPILER_ERROR = ( 56 "Use of `idl_uses_aosp_compiler` is not allowed for %s." 57) 58 59_IDL_IDLOPTS_UNSUPPORTERD_ERROR = ( 60 "`idlopts` is supported only if `idl_uses_aosp_compiler` is set to true." 61) 62 63# Android library AAR context attributes. 64_PROVIDERS = "providers" 65_VALIDATION_OUTPUTS = "validation_outputs" 66 67_AARContextInfo = provider( 68 "Android library AAR context object", 69 fields = { 70 _PROVIDERS: "The list of all providers to propagate.", 71 _VALIDATION_OUTPUTS: "List of outputs given to OutputGroupInfo _validation group", 72 }, 73) 74 75def _has_srcs(ctx): 76 return ctx.files.srcs or ctx.files.idl_srcs or getattr(ctx.files, "common_srcs", False) 77 78def _uses_deprecated_implicit_export(ctx): 79 return (ctx.attr.deps and not (_has_srcs(ctx) or 80 ctx.attr._defined_assets or 81 ctx.files.resource_files or 82 ctx.attr.manifest or 83 ctx.attr.baseline_profiles)) 84 85def _uses_resources_and_deps_without_srcs(ctx): 86 return (ctx.attr.deps and 87 (ctx.attr._defined_assets or ctx.files.resource_files or ctx.attr.manifest) and 88 not _has_srcs(ctx)) 89 90def _check_deps_without_java_srcs(ctx): 91 if not ctx.attr.deps or _has_srcs(ctx): 92 return False 93 gfn = getattr(ctx.attr, "generator_function", "") 94 if _uses_deprecated_implicit_export(ctx): 95 log.error(_USES_DEPRECATED_IMPLICIT_EXPORT_ERROR % ctx.label) 96 if _uses_resources_and_deps_without_srcs(ctx): 97 if (acls.in_android_library_resources_without_srcs_generator_functions(gfn) or 98 acls.in_android_library_resources_without_srcs(str(ctx.label))): 99 return True 100 return False 101 102def _validate_rule_context(ctx): 103 # Verify that idl_import_root is specified with idl_src or idl_parcelables. 104 if (ctx.attr._defined_idl_import_root and 105 not (ctx.attr._defined_idl_srcs or ctx.attr._defined_idl_parcelables)): 106 log.error(_IDL_IMPORT_ROOT_SET_WITHOUT_SRCS_OR_PARCELABLES_ERROR) 107 108 # Verify that idl_srcs are not from another package. 109 for idl_src in ctx.attr.idl_srcs: 110 if ctx.label.package != idl_src.label.package: 111 log.error(_IDL_SRC_FROM_DIFFERENT_PACKAGE_ERROR % idl_src.label) 112 113 # Ensure that the AOSP AIDL compiler is used only in allowlisted packages 114 if (ctx.attr.idl_uses_aosp_compiler and 115 not acls.in_android_library_use_aosp_aidl_compiler_allowlist(str(ctx.label))): 116 log.error(_IDL_USES_AOSP_COMPILER_ERROR % ctx.label) 117 118 # Check if idlopts is with idl_uses_aosp_compiler 119 if ctx.attr.idlopts and not ctx.attr.idl_uses_aosp_compiler: 120 log.error(_IDL_IDLOPTS_UNSUPPORTERD_ERROR) 121 122 return struct( 123 enable_deps_without_srcs = _check_deps_without_java_srcs(ctx), 124 ) 125 126def _exceptions_processor(ctx, **unused_ctxs): 127 return ProviderInfo( 128 name = "exceptions_ctx", 129 value = _validate_rule_context(ctx), 130 ) 131 132def _process_manifest(ctx, **unused_ctxs): 133 manifest_ctx = _resources.bump_min_sdk( 134 ctx, 135 manifest = ctx.file.manifest, 136 floor = acls.get_min_sdk_floor(str(ctx.label)), 137 enforce_min_sdk_floor_tool = get_android_toolchain(ctx).enforce_min_sdk_floor_tool.files_to_run, 138 ) 139 140 return ProviderInfo( 141 name = "manifest_ctx", 142 value = manifest_ctx, 143 ) 144 145def _process_resources(ctx, java_package, manifest_ctx, **unused_ctxs): 146 # exports_manifest can be overridden by a bazel flag. 147 if ctx.attr.exports_manifest == _attrs.tristate.auto: 148 exports_manifest = ctx.fragments.android.get_exports_manifest_default 149 else: 150 exports_manifest = ctx.attr.exports_manifest == _attrs.tristate.yes 151 152 resource_apks = [] 153 for apk in utils.collect_providers(StarlarkApkInfo, ctx.attr.resource_apks): 154 resource_apks.append(apk.signed_apk) 155 156 # Process Android Resources 157 resources_ctx = _resources.process( 158 ctx, 159 manifest = manifest_ctx.processed_manifest, 160 resource_files = ctx.attr.resource_files, 161 defined_assets = ctx.attr._defined_assets, 162 assets = ctx.attr.assets, 163 defined_assets_dir = ctx.attr._defined_assets_dir, 164 assets_dir = ctx.attr.assets_dir, 165 exports_manifest = exports_manifest, 166 java_package = java_package, 167 custom_package = ctx.attr.custom_package, 168 neverlink = ctx.attr.neverlink, 169 enable_data_binding = ctx.attr.enable_data_binding, 170 deps = ctx.attr.deps, 171 resource_apks = resource_apks, 172 exports = ctx.attr.exports, 173 174 # Processing behavior changing flags. 175 enable_res_v3 = _flags.get(ctx).android_enable_res_v3, 176 # TODO(b/144163743): remove fix_resource_transitivity, which was only added to emulate 177 # misbehavior on the Java side. 178 fix_resource_transitivity = bool(ctx.attr.srcs), 179 fix_export_exporting = acls.in_fix_export_exporting_rollout(str(ctx.label)), 180 181 # Tool and Processing related inputs 182 aapt = get_android_toolchain(ctx).aapt2.files_to_run, 183 android_jar = get_android_sdk(ctx).android_jar, 184 android_kit = get_android_toolchain(ctx).android_kit.files_to_run, 185 busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, 186 java_toolchain = _common.get_java_toolchain(ctx), 187 host_javabase = _common.get_host_javabase(ctx), 188 instrument_xslt = utils.only(get_android_toolchain(ctx).add_g3itr_xslt.files.to_list()), 189 res_v3_dummy_manifest = utils.only( 190 get_android_toolchain(ctx).res_v3_dummy_manifest.files.to_list(), 191 ), 192 res_v3_dummy_r_txt = utils.only( 193 get_android_toolchain(ctx).res_v3_dummy_r_txt.files.to_list(), 194 ), 195 xsltproc = get_android_toolchain(ctx).xsltproc_tool.files_to_run, 196 zip_tool = get_android_toolchain(ctx).zip_tool.files_to_run, 197 ) 198 199 # TODO(b/139305816): Remove the ability for android_library to be added in 200 # the srcs attribute of another android_library. 201 if resources_ctx.defines_resources: 202 # Verify that srcs do no contain labels. 203 for src in ctx.attr.srcs: 204 if AndroidResourcesInfo in src: 205 log.error(_SRCS_CONTAIN_RESOURCE_LABEL_ERROR % 206 src[AndroidResourcesInfo].label) 207 208 return ProviderInfo( 209 name = "resources_ctx", 210 value = resources_ctx, 211 ) 212 213def _process_idl(ctx, **unused_sub_ctxs): 214 return ProviderInfo( 215 name = "idl_ctx", 216 value = _idl.process( 217 ctx, 218 idl_srcs = ctx.files.idl_srcs, 219 idl_parcelables = ctx.files.idl_parcelables, 220 idl_import_root = 221 ctx.attr.idl_import_root if ctx.attr._defined_idl_import_root else None, 222 idl_preprocessed = ctx.files.idl_preprocessed, 223 deps = utils.collect_providers(AndroidIdlInfo, ctx.attr.deps), 224 exports = utils.collect_providers(AndroidIdlInfo, ctx.attr.exports), 225 aidl = get_android_sdk(ctx).aidl, 226 aidl_lib = get_android_sdk(ctx).aidl_lib, 227 aidl_framework = get_android_sdk(ctx).framework_aidl, 228 uses_aosp_compiler = ctx.attr.idl_uses_aosp_compiler, 229 idlopts = ctx.attr.idlopts, 230 ), 231 ) 232 233def _process_data_binding(ctx, java_package, resources_ctx, **unused_sub_ctxs): 234 if ctx.attr.enable_data_binding and not acls.in_databinding_allowed(str(ctx.label)): 235 fail("This target is not allowed to use databinding and enable_data_binding is True.") 236 return ProviderInfo( 237 name = "db_ctx", 238 value = _data_binding.process( 239 ctx, 240 defines_resources = resources_ctx.defines_resources, 241 enable_data_binding = ctx.attr.enable_data_binding, 242 java_package = java_package, 243 layout_info = resources_ctx.data_binding_layout_info, 244 deps = utils.collect_providers(DataBindingV2Info, ctx.attr.deps), 245 exports = utils.collect_providers(DataBindingV2Info, ctx.attr.exports), 246 data_binding_exec = get_android_toolchain(ctx).data_binding_exec.files_to_run, 247 data_binding_annotation_processor = 248 get_android_toolchain(ctx).data_binding_annotation_processor, 249 data_binding_annotation_template = 250 utils.only(get_android_toolchain(ctx).data_binding_annotation_template.files.to_list()), 251 ), 252 ) 253 254def _process_proguard(ctx, idl_ctx, **unused_sub_ctxs): 255 return ProviderInfo( 256 name = "proguard_ctx", 257 value = _proguard.process_specs( 258 ctx, 259 proguard_configs = ctx.files.proguard_specs, 260 proguard_spec_providers = utils.collect_providers( 261 ProguardSpecProvider, 262 ctx.attr.deps, 263 ctx.attr.exports, 264 idl_ctx.idl_deps, 265 ), 266 proguard_allowlister = 267 get_android_toolchain(ctx).proguard_allowlister.files_to_run, 268 ), 269 ) 270 271def _process_jvm(ctx, exceptions_ctx, resources_ctx, idl_ctx, db_ctx, **unused_sub_ctxs): 272 java_info = _java.compile_android( 273 ctx, 274 ctx.outputs.lib_jar, 275 ctx.outputs.lib_src_jar, 276 srcs = ctx.files.srcs + idl_ctx.idl_java_srcs + db_ctx.java_srcs, 277 javac_opts = ctx.attr.javacopts + db_ctx.javac_opts, 278 r_java = resources_ctx.r_java, 279 deps = 280 utils.collect_providers(JavaInfo, ctx.attr.deps, idl_ctx.idl_deps), 281 exports = utils.collect_providers(JavaInfo, ctx.attr.exports), 282 plugins = utils.collect_providers(JavaPluginInfo, ctx.attr.plugins, db_ctx.java_plugins), 283 exported_plugins = utils.collect_providers( 284 JavaPluginInfo, 285 ctx.attr.exported_plugins, 286 ), 287 annotation_processor_additional_outputs = ( 288 db_ctx.java_annotation_processor_additional_outputs 289 ), 290 annotation_processor_additional_inputs = ( 291 db_ctx.java_annotation_processor_additional_inputs 292 ), 293 enable_deps_without_srcs = exceptions_ctx.enable_deps_without_srcs, 294 neverlink = ctx.attr.neverlink, 295 strict_deps = "DEFAULT", 296 java_toolchain = _common.get_java_toolchain(ctx), 297 ) 298 299 providers = [java_info] 300 301 # Propagate Lint rule Jars from any exported AARs (b/229993446) 302 android_lint_rules = [info.lint_jars for info in utils.collect_providers( 303 AndroidLintRulesInfo, 304 ctx.attr.exports, 305 )] 306 if android_lint_rules: 307 providers.append( 308 AndroidLintRulesInfo( 309 lint_jars = depset(transitive = android_lint_rules), 310 ), 311 ) 312 313 return ProviderInfo( 314 name = "jvm_ctx", 315 value = struct( 316 java_info = java_info, 317 providers = providers, 318 ), 319 ) 320 321def _process_aar(ctx, java_package, resources_ctx, proguard_ctx, **unused_ctx): 322 aar_ctx = { 323 _PROVIDERS: [], 324 _VALIDATION_OUTPUTS: [], 325 } 326 327 starlark_aar = _resources.make_aar( 328 ctx, 329 manifest = resources_ctx.starlark_processed_manifest, 330 assets = ctx.files.assets, 331 assets_dir = ctx.attr.assets_dir, 332 resource_files = resources_ctx.starlark_processed_resources if not ctx.attr.neverlink else [], 333 class_jar = ctx.outputs.lib_jar, 334 r_txt = resources_ctx.starlark_r_txt, 335 proguard_specs = proguard_ctx.proguard_configs, 336 busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run, 337 host_javabase = _common.get_host_javabase(ctx), 338 ) 339 340 # TODO(b/170409221): Clean this up once Starlark migration is complete. Create and propagate 341 # a native aar info provider with the Starlark artifacts to avoid breaking downstream 342 # targets. 343 if not ctx.attr.neverlink: 344 aar_ctx[_PROVIDERS].append(AndroidLibraryAarInfo( 345 aar = starlark_aar, 346 manifest = resources_ctx.starlark_processed_manifest, 347 aars_from_deps = utils.collect_providers( 348 AndroidLibraryAarInfo, 349 ctx.attr.deps, 350 ctx.attr.exports, 351 ), 352 defines_local_resources = resources_ctx.defines_resources, 353 )) 354 355 return ProviderInfo( 356 name = "aar_ctx", 357 value = _AARContextInfo(**aar_ctx), 358 ) 359 360def _process_native(ctx, idl_ctx, **unused_ctx): 361 return ProviderInfo( 362 name = "native_ctx", 363 value = struct( 364 providers = [ 365 AndroidNativeLibsInfo( 366 depset( 367 transitive = [ 368 p.native_libs 369 for p in utils.collect_providers( 370 AndroidNativeLibsInfo, 371 ctx.attr.deps, 372 ctx.attr.exports, 373 ) 374 ], 375 order = "preorder", 376 ), 377 ), 378 AndroidCcLinkParamsInfo( 379 cc_common.merge_cc_infos( 380 cc_infos = [ 381 info.cc_link_params_info 382 for info in utils.collect_providers( 383 JavaInfo, 384 ctx.attr.deps, 385 ctx.attr.exports, 386 idl_ctx.idl_deps, 387 ) 388 ] + 389 [ 390 info.link_params 391 for info in utils.collect_providers( 392 AndroidCcLinkParamsInfo, 393 ctx.attr.deps, 394 ctx.attr.exports, 395 idl_ctx.idl_deps, 396 ) 397 ] + 398 utils.collect_providers( 399 CcInfo, 400 ctx.attr.deps, 401 ctx.attr.exports, 402 idl_ctx.idl_deps, 403 ), 404 ), 405 ), 406 ], 407 ), 408 ) 409 410def _process_intellij(ctx, java_package, manifest_ctx, resources_ctx, idl_ctx, jvm_ctx, **unused_sub_ctxs): 411 android_ide_info = _intellij.make_android_ide_info( 412 ctx, 413 java_package = java_package, 414 manifest = manifest_ctx.processed_manifest, 415 defines_resources = resources_ctx.defines_resources, 416 merged_manifest = resources_ctx.merged_manifest, 417 resources_apk = resources_ctx.resources_apk, 418 r_jar = utils.only(resources_ctx.r_java.outputs.jars) if resources_ctx.r_java else None, 419 idl_import_root = idl_ctx.idl_import_root, 420 idl_srcs = idl_ctx.idl_srcs, 421 idl_java_srcs = idl_ctx.idl_java_srcs, 422 java_info = jvm_ctx.java_info, 423 signed_apk = None, # signed_apk, always empty for android_library. 424 aar = getattr(ctx.outputs, "aar", None), # Deprecate aar for android_library. 425 apks_under_test = [], # apks_under_test, always empty for android_library 426 native_libs = dict(), # nativelibs, always empty for android_library 427 idlclass = get_android_toolchain(ctx).idlclass.files_to_run, 428 host_javabase = _common.get_host_javabase(ctx), 429 ) 430 return ProviderInfo( 431 name = "intellij_ctx", 432 value = struct( 433 android_ide_info = android_ide_info, 434 providers = [android_ide_info], 435 ), 436 ) 437 438def _process_coverage(ctx, **unused_ctx): 439 return ProviderInfo( 440 name = "coverage_ctx", 441 value = struct( 442 providers = [ 443 coverage_common.instrumented_files_info( 444 ctx, 445 source_attributes = ["srcs"], 446 dependency_attributes = ["assets", "deps", "exports"], 447 ), 448 ], 449 ), 450 ) 451 452def _process_baseline_profiles(ctx, **unused_ctx): 453 return ProviderInfo( 454 name = "bp_ctx", 455 value = struct( 456 providers = [ 457 BaselineProfileProvider(depset( 458 ctx.files.baseline_profiles, 459 transitive = [bp.files for bp in utils.collect_providers(BaselineProfileProvider, ctx.attr.deps, ctx.attr.exports)], 460 )), 461 ], 462 ), 463 ) 464 465# Order dependent, as providers will not be available to downstream processors 466# that may depend on the provider. Iteration order for a dictionary is based on 467# insertion. 468PROCESSORS = dict( 469 ExceptionsProcessor = _exceptions_processor, 470 ManifestProcessor = _process_manifest, 471 ResourceProcessor = _process_resources, 472 IdlProcessor = _process_idl, 473 DataBindingProcessor = _process_data_binding, 474 JvmProcessor = _process_jvm, 475 ProguardProcessor = _process_proguard, 476 AarProcessor = _process_aar, 477 NativeProcessor = _process_native, 478 IntelliJProcessor = _process_intellij, 479 CoverageProcessor = _process_coverage, 480 BaselineProfilesProcessor = _process_baseline_profiles, 481) 482 483# TODO(b/119560471): Deprecate the usage of legacy providers. 484def _make_legacy_provider(intellij_ctx, jvm_ctx, providers): 485 return struct( 486 android = _intellij.make_legacy_android_provider(intellij_ctx.android_ide_info), 487 java = struct( 488 annotation_processing = jvm_ctx.java_info.annotation_processing, 489 outputs = jvm_ctx.java_info.outputs, 490 source_jars = depset(jvm_ctx.java_info.source_jars), 491 transitive_deps = jvm_ctx.java_info.transitive_compile_time_jars, 492 transitive_runtime_deps = jvm_ctx.java_info.transitive_runtime_jars, 493 transitive_source_jars = jvm_ctx.java_info.transitive_source_jars, 494 ), 495 providers = providers, 496 ) 497 498def finalize( 499 ctx, 500 resources_ctx, 501 intellij_ctx, 502 jvm_ctx, 503 proguard_ctx, 504 providers, 505 validation_outputs, 506 **unused_ctxs): 507 """Creates the DefaultInfo and OutputGroupInfo providers. 508 509 Args: 510 ctx: The context. 511 resources_ctx: ProviderInfo. The resources ctx. 512 intellij_ctx: ProviderInfo. The intellij ctx. 513 jvm_ctx: ProviderInfo. The jvm ctx. 514 proguard_ctx: ProviderInfo. The proguard ctx. 515 providers: sequence of providers. The providers to propagate. 516 validation_outputs: sequence of Files. The validation outputs. 517 **unused_ctxs: Unused ProviderInfo. 518 519 Returns: 520 A struct with Android and Java legacy providers and a list of providers. 521 """ 522 transitive_runfiles = [] 523 if not ctx.attr.neverlink: 524 for p in utils.collect_providers( 525 DefaultInfo, 526 ctx.attr.deps, 527 ctx.attr.exports, 528 ): 529 transitive_runfiles.append(p.data_runfiles.files) 530 transitive_runfiles.append(p.default_runfiles.files) 531 runfiles = ctx.runfiles( 532 files = ( 533 (resources_ctx.r_java.runtime_output_jars if resources_ctx.r_java and not ctx.attr.neverlink else []) + 534 ([ctx.outputs.lib_jar] if (ctx.attr.srcs or ctx.attr.idl_srcs) and not ctx.attr.neverlink else []) 535 ), 536 transitive_files = depset(transitive = transitive_runfiles), 537 collect_default = True, 538 ) 539 files = [ctx.outputs.lib_jar] 540 if getattr(ctx.outputs, "resources_src_jar", None): 541 files.append(ctx.outputs.resources_src_jar) 542 if getattr(ctx.outputs, "resources_jar", None): 543 files.append(ctx.outputs.resources_jar) 544 545 providers.extend([ 546 DefaultInfo( 547 files = depset(files), 548 runfiles = runfiles, 549 ), 550 OutputGroupInfo( 551 compilation_outputs = depset([ctx.outputs.lib_jar]), 552 _source_jars = depset( 553 [ctx.outputs.lib_src_jar], 554 transitive = [jvm_ctx.java_info.transitive_source_jars], 555 ), 556 _direct_source_jars = depset([ctx.outputs.lib_src_jar]), 557 _hidden_top_level_INTERNAL_ = depset( 558 resources_ctx.validation_results, 559 transitive = [ 560 info._hidden_top_level_INTERNAL_ 561 for info in utils.collect_providers( 562 OutputGroupInfo, 563 ctx.attr.deps, 564 ctx.attr.exports, 565 ) 566 ] + [proguard_ctx.transitive_proguard_configs], 567 ), 568 _validation = depset(validation_outputs), 569 ), 570 ]) 571 return _make_legacy_provider(intellij_ctx, jvm_ctx, providers) 572 573_PROCESSING_PIPELINE = processing_pipeline.make_processing_pipeline( 574 processors = PROCESSORS, 575 finalize = finalize, 576) 577 578def impl(ctx): 579 """The rule implementation. 580 581 Args: 582 ctx: The context. 583 584 Returns: 585 A legacy struct provider. 586 """ 587 java_package = _java.resolve_package_from_label(ctx.label, ctx.attr.custom_package) 588 return processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE) 589