xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/android_binary_internal/impl.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
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