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