xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/resources.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
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"""Bazel Android Resources."""
16
17load("//rules:acls.bzl", "acls")
18load(":attrs.bzl", _attrs = "attrs")
19load(":busybox.bzl", _busybox = "busybox")
20load(":common.bzl", _common = "common")
21load(":java.bzl", _java = "java")
22load(":path.bzl", _path = "path")
23load(
24    ":providers.bzl",
25    "ResourcesNodeInfo",
26    "StarlarkAndroidResourcesInfo",
27)
28load(
29    ":utils.bzl",
30    "utils",
31    _compilation_mode = "compilation_mode",
32    _log = "log",
33)
34
35_RESOURCE_FOLDER_TYPES = [
36    "anim",
37    "animator",
38    "color",
39    "drawable",
40    "font",
41    "interpolator",
42    "layout",
43    "menu",
44    "mipmap",
45    "navigation",
46    "values",
47    "xml",
48    "raw",
49    "transition",
50]
51
52_RESOURCE_QUALIFIER_SEP = "-"
53
54_MANIFEST_MISSING_ERROR = (
55    "In target %s, manifest attribute is required when resource_files, " +
56    "assets, or exports_manifest are specified."
57)
58
59_ASSET_DEFINITION_ERROR = (
60    "In target %s, the assets and assets_dir attributes should be either " +
61    "both empty or non-empty."
62)
63
64_INCORRECT_RESOURCE_LAYOUT_ERROR = (
65    "'%s' is not in the expected resource directory structure of " +
66    "<resource directory>/{%s}/<file>" % (",").join(_RESOURCE_FOLDER_TYPES)
67)
68
69# Keys for manifest_values
70_VERSION_NAME = "versionName"
71_VERSION_CODE = "versionCode"
72_MIN_SDK_VERSION = "minSdkVersion"
73
74# Resources context attributes.
75_ASSETS_PROVIDER = "assets_provider"
76_DATA_BINDING_LAYOUT_INFO = "data_binding_layout_info"
77_DEFINES_RESOURCES = "defines_resources"
78_DIRECT_ANDROID_RESOURCES = "direct_android_resources"
79_MAIN_DEX_PROGUARD_CONFIG = "main_dex_proguard_config"
80_MERGED_MANIFEST = "merged_manifest"
81_PROVIDERS = "providers"
82_R_JAVA = "r_java"
83_RESOURCES_APK = "resources_apk"
84_VALIDATION_RESULTS = "validation_results"
85_VALIDATION_OUTPUTS = "validation_outputs"
86_RESOURCES_PROVIDER = "resources_provider"
87_STARLARK_PROCESSED_MANIFEST = "starlark_processed_manifest"
88_STARLARK_R_TXT = "starlark_r_txt"
89_STARLARK_PROCESSED_RESOURCES = "starlark_processed_resources"
90
91_ResourcesProcessContextInfo = provider(
92    "Resources context object",
93    fields = {
94        _DEFINES_RESOURCES: "If local resources were defined.",
95        _DIRECT_ANDROID_RESOURCES: "Direct android resources.",
96        _MERGED_MANIFEST: "Merged manifest.",
97        _PROVIDERS: "The list of all providers to propagate.",
98        _R_JAVA: "JavaInfo for R.jar.",
99        _DATA_BINDING_LAYOUT_INFO: "Databinding layout info file.",
100        _RESOURCES_APK: "ResourcesApk.",
101        _VALIDATION_RESULTS: "List of validation results.",
102        _VALIDATION_OUTPUTS: "List of outputs given to OutputGroupInfo _validation group",
103
104        # TODO(djwhang): The android_library aar generation requires direct
105        # access to providers. Remove once aar is its own rule.
106        _ASSETS_PROVIDER: "AndroidAssetsInfo provider.",
107        _RESOURCES_PROVIDER: "AndroidResourcesInfo provider.",
108        _STARLARK_PROCESSED_MANIFEST: "The processed manifest from the starlark resource processing pipeline.",
109        _STARLARK_R_TXT: "The R.txt from the starlark resource processing pipeline.",
110        _STARLARK_PROCESSED_RESOURCES: "The processed resources from the starlark processing pipeline.",
111    },
112)
113
114# Packaged resources context attributes.
115_PACKAGED_FINAL_MANIFEST = "processed_manifest"
116_PACKAGED_RESOURCE_APK = "resources_apk"
117_PACKAGED_CLASS_JAR = "class_jar"
118_PACKAGED_VALIDATION_RESULT = "validation_result"
119_PACKAGED_R_TXT = "r_txt"
120_RESOURCE_MINSDK_PROGUARD_CONFIG = "resource_minsdk_proguard_config"
121_RESOURCE_PROGUARD_CONFIG = "resource_proguard_config"
122_ANDROID_APPLICATION_RESOURCE = "android_application_resource"
123
124_ResourcesPackageContextInfo = provider(
125    "Packaged resources context object",
126    fields = {
127        _PACKAGED_FINAL_MANIFEST: "Final processed manifest.",
128        _PACKAGED_RESOURCE_APK: "ResourceApk.",
129        _PACKAGED_CLASS_JAR: "R class jar.",
130        _PACKAGED_VALIDATION_RESULT: "Validation result.",
131        _PACKAGED_R_TXT: "R text file",
132        _R_JAVA: "JavaInfo for R.jar",
133        _DATA_BINDING_LAYOUT_INFO: "Databinding layout info file.",
134        _RESOURCE_MINSDK_PROGUARD_CONFIG: "Resource minSdkVersion proguard config",
135        _RESOURCE_PROGUARD_CONFIG: "Resource proguard config",
136        _MAIN_DEX_PROGUARD_CONFIG: "Main dex proguard config",
137        _PROVIDERS: "The list of all providers to propagate.",
138        _ANDROID_APPLICATION_RESOURCE: "The AndroidApplicationResourceInfo provider.",
139    },
140)
141
142# Manifest context attributes
143_PROCESSED_MANIFEST = "processed_manifest"
144_PROCESSED_MANIFEST_VALUES = "processed_manifest_values"
145
146_ManifestContextInfo = provider(
147    "Manifest context object",
148    fields = {
149        _PROCESSED_MANIFEST: "The manifest after the min SDK has been changed as necessary.",
150        _PROCESSED_MANIFEST_VALUES: "Optional, dict of manifest values that have been processed.",
151    },
152)
153
154_ManifestValidationContextInfo = provider(
155    "Manifest validation context object",
156    fields = {
157        _VALIDATION_OUTPUTS: "List of outputs given to OutputGroupInfo _validation group.",
158    },
159)
160
161_SHRUNK_RESOURCE_APK = "resources_apk"
162_SHRUNK_RESOURCE_ZIP = "resources_zip"
163_RESOURCE_SHRINKER_LOG = "shrinker_log"
164_RESOURCE_OPTIMIZATION_CONFIG = "optimization_config"
165
166_ResourcesShrinkContextInfo = provider(
167    "Shrunk resources context object",
168    fields = {
169        _SHRUNK_RESOURCE_APK: "Shrunk resource apk.",
170        _SHRUNK_RESOURCE_ZIP: "Shrunk resource zip.",
171        _RESOURCE_SHRINKER_LOG: "Shrinker log.",
172        _RESOURCE_OPTIMIZATION_CONFIG: "Resource optimization config.",
173    },
174)
175
176_RESOURCE_PATH_SHORTENING_MAP = "path_shortening_map"
177_OPTIMIZED_RESOURCE_APK = "resources_apk"
178
179_ResourcesOptimizeContextInfo = provider(
180    "Optimized resources context object",
181    fields = {
182        _OPTIMIZED_RESOURCE_APK: "Optimized resource apk",
183        _RESOURCE_PATH_SHORTENING_MAP: "Path shortening map.",
184    },
185)
186
187# Feature which would enable AAPT2's resource name obfuscation optimization for android_binary
188# rules with resource shrinking and ProGuard enabled.
189_FEATURE_RESOURCE_NAME_OBFUSCATION = "resource_name_obfuscation"
190
191def _generate_dummy_manifest(
192        ctx,
193        out_manifest = None,
194        java_package = None,
195        min_sdk_version = 0):
196    content = """<?xml version="1.0" encoding="utf-8"?>
197<manifest xmlns:android="http://schemas.android.com/apk/res/android"
198    package="%s">""" % (java_package or "com.default")
199
200    min_sdk_version = max(min_sdk_version, acls.get_min_sdk_floor(str(ctx.label)))
201    content = content + """
202    <uses-sdk android:minSdkVersion="%s" />""" % min_sdk_version
203
204    content = content + """
205    <application>
206    </application>
207</manifest>"""
208
209    ctx.actions.write(
210        output = out_manifest,
211        content = content,
212    )
213
214def _add_g3itr(
215        ctx,
216        manifest = None,
217        out_manifest = None,
218        xsltproc = None,
219        instrument_xslt = None):
220    """Adds Google3InstrumentationTestRunner instrumentation element to the manifest.
221
222    Element is only added if the manifest contains an instrumentation element with
223    name "android.test.InstrumentationTestRunner". The added element's name attr is
224    "com.google.android.apps.common.testing.testrunner.Google3InstrumentationTestRunner".
225
226    Args:
227      ctx: The context.
228      manifest: File. The AndroidManifest.xml file.
229      out_manifest: File. The transformed AndroidManifest.xml.
230      xsltproc: FilesToRunProvider. The xsltproc executable or
231        FilesToRunProvider.
232      instrument_xslt: File. The add_g3itr.xslt file describing the xslt
233        transformation to apply.
234    """
235    args = ctx.actions.args()
236    args.add("--nonet")
237    args.add("--novalid")
238    args.add("-o", out_manifest)
239    args.add(instrument_xslt)
240    args.add(manifest)
241
242    ctx.actions.run(
243        executable = xsltproc,
244        arguments = [args],
245        inputs = [manifest, instrument_xslt],
246        outputs = [out_manifest],
247        mnemonic = "AddG3ITRStarlark",
248        progress_message = "Adding G3ITR to test manifest for %s" % ctx.label,
249        toolchain = None,
250    )
251
252def _get_legacy_mergee_manifests(resources_infos):
253    all_dependencies = depset(
254        transitive = [
255            ri.direct_android_resources
256            for ri in resources_infos
257        ] + [
258            ri.transitive_android_resources
259            for ri in resources_infos
260        ],
261    )
262
263    mergee_manifests = []
264    for dep in all_dependencies.to_list():
265        if dep.to_provider.manifest.exports_manifest:
266            mergee_manifests.append(dep.to_provider.manifest.manifest)
267
268    return depset(mergee_manifests)
269
270def _legacy_mergee_manifest(manifest):
271    sort_key = manifest.short_path + "#"
272    return sort_key + "--mergee=" + manifest.path
273
274def _legacy_merge_manifests(
275        ctx,
276        out_merged_manifest = None,
277        manifest = None,
278        mergee_manifests = None,
279        legacy_merger = None):
280    """Merges manifests with the legacy manifest merger."
281
282    This should not be called with empty mergee_manifests.
283
284    Args:
285      ctx: The context.
286      out_merged_manifest: File. The merged AndroidManifest.xml.
287      manifest: File. The AndroidManifest.xml.
288      mergee_manifests: A sequence of Files. All transitive manifests to be merged.
289      legacy_merger: A FilesToRunProvider. The legacy manifest merger executable.
290    """
291    args = ctx.actions.args()
292    args.use_param_file("%s", use_always = True)
293    args.set_param_file_format("multiline")
294    args.add("--merger=%s" % manifest.path)
295    args.add("--exclude_permission=all")
296    args.add("--output=%s" % out_merged_manifest.path)
297
298    manifest_params = ctx.actions.declare_file(ctx.label.name + "/legacy_merger.params")
299    manifest_args = ctx.actions.args()
300    manifest_args.use_param_file("%s", use_always = True)
301    manifest_args.set_param_file_format("multiline")
302    manifest_args.add_joined(mergee_manifests, map_each = _legacy_mergee_manifest, join_with = "\n")
303    ctx.actions.run_shell(
304        command = """
305# Sorts the mergee manifests by path and combines with other busybox args.
306set -e
307SORTED=`sort $1 | sed 's/^.*#//'`
308cat $2 > $3
309echo "$SORTED" >> $3
310""",
311        arguments = [manifest_args, args, manifest_params.path],
312        outputs = [manifest_params],
313        toolchain = None,
314    )
315    args = ctx.actions.args()
316    args.add(manifest_params, format = "--flagfile=%s")
317
318    ctx.actions.run(
319        executable = legacy_merger,
320        arguments = [args],
321        inputs = depset([manifest, manifest_params], transitive = [mergee_manifests]),
322        outputs = [out_merged_manifest],
323        mnemonic = "StarlarkLegacyAndroidManifestMerger",
324        progress_message = "Merging Android Manifests",
325        toolchain = None,
326    )
327
328def _make_databinding_outputs(
329        ctx,
330        resource_files):
331    """Helper method to create arguments for the process_databinding busybox tool.
332
333    Declares databinding-processed resource files that are generated by the
334    PROCESS_DATABINDING busybox tool, which must be declared underneath an output
335    resources directory and namespaced by their paths. The busybox takes the
336    output directory exec path and generates the underlying resource files.
337
338    Args:
339      ctx: The context.
340      resource_files: List of Files. The android resource files to be processed by
341        _process_databinding.
342
343    Returns:
344      A tuple containing the list of declared databinding processed resource files and the
345        output resource directory path expected by the busybox. The path is a full path.
346    """
347
348    # TODO(b/160907203): Clean up databinding_rel_path. We capitalize "Databinding" here to avoid
349    # conflicting with native artifact file names. This is changed back to "databinding" during
350    # process_starlark so that compiled resources exactly match those of the native resource
351    # processing pipeline. Even a single character mismatch in the file names causes selected
352    # resources to differ in the final APK.
353    databinding_rel_path = _path.join(["Databinding-processed-resources", ctx.label.name])
354    databinding_processed_resources = [
355        ctx.actions.declare_file(_path.join([databinding_rel_path, f.path]))
356        for f in resource_files
357    ]
358    databinding_resources_dirname = _path.join([
359        ctx.bin_dir.path,
360        ctx.label.package,
361        databinding_rel_path,
362    ])
363    return databinding_processed_resources, databinding_resources_dirname
364
365def _fix_databinding_compiled_resources(
366        ctx,
367        out_compiled_resources = None,
368        compiled_resources = None,
369        zip_tool = None):
370    """Fix compiled resources to match those produced by the native pipeline.
371
372    Changes "Databinding" to "databinding" in each compiled resource .flat file name and header.
373
374    Args:
375      ctx: The context.
376      out_compiled_resources: File. The modified compiled_resources output.
377      compiled_resources: File. The compiled_resources zip.
378      zip_tool: FilesToRunProvider. The zip tool executable or FilesToRunProvider
379    """
380    ctx.actions.run_shell(
381        outputs = [out_compiled_resources],
382        inputs = [compiled_resources],
383        tools = [zip_tool],
384        arguments = [compiled_resources.path, out_compiled_resources.path, zip_tool.executable.path],
385        toolchain = None,
386        command = """#!/bin/bash
387set -e
388
389IN_DIR=$(mktemp -d)
390OUT_DIR=$(mktemp -d)
391CUR_PWD=$(pwd)
392
393if zipinfo -t "$1"; then
394    ORDERED_LIST=`(unzip -l "$1" | sed -e '1,3d' | head -n -2 | tr -s " " | cut -d " " -f5)`
395
396    unzip -q "$1" -d "$IN_DIR"
397
398    # Iterate through the ordered list, change "Databinding" to "databinding" in the file header
399    # and file name and zip the files with the right comment
400    for FILE in $ORDERED_LIST; do
401        cd "$IN_DIR"
402        if [ -f "$FILE" ]; then
403            sed -i 's/Databinding\\-processed\\-resources/databinding\\-processed\\-resources/g' "$FILE"
404            NEW_NAME=`echo "$FILE" | sed 's/Databinding\\-processed\\-resources/databinding\\-processed\\-resources/g' | sed 's#'"$IN_DIR"'/##g'`
405            mkdir -p `dirname "$OUT_DIR/$NEW_NAME"` && touch "$OUT_DIR/$NEW_NAME"
406            cp -p "$FILE" "$OUT_DIR/$NEW_NAME"
407
408            PATH_SEGMENTS=(`echo ${FILE} | tr '/' ' '`)
409            BASE_PATH_SEGMENT="${PATH_SEGMENTS[0]}"
410                COMMENT=
411            if [ "${BASE_PATH_SEGMENT}" == "generated" ]; then
412                COMMENT="generated"
413            elif [ "${BASE_PATH_SEGMENT}" == "default" ]; then
414                COMMENT="default"
415            fi
416
417            cd "$OUT_DIR"
418            "$CUR_PWD/$3" -jt -X -0 -q -r -c "$CUR_PWD/$2" $NEW_NAME <<EOM
419${COMMENT}
420EOM
421        fi
422    done
423
424    cd "$CUR_PWD"
425    touch -r "$1" "$2"
426else
427    cp -p "$1" "$2"
428fi
429        """,
430    )
431
432def _is_resource_shrinking_enabled(
433        shrink_resources,
434        use_android_resource_shrinking):
435    if shrink_resources == _attrs.tristate.auto:
436        return use_android_resource_shrinking
437    return shrink_resources == _attrs.tristate.yes
438
439def _should_shrink_resource_cycles(
440        use_android_resource_cycle_shrinking,
441        resource_shrinking_enabled,
442        has_local_proguard_specs):
443    return (use_android_resource_cycle_shrinking and
444            resource_shrinking_enabled and
445            has_local_proguard_specs)
446
447def _filter_multi_cpu_configuration_targets(
448        targets):
449    """Filter out duplicate split-configured targets.
450
451    This method simulates logic in the native rule where if a label_list attribute has
452    split-configuration but is requested in target mode, only targets from the first architecture
453    are returned. Without this filtering there are duplicate targets if multiple CPU configurations
454    are specified on the command line. This is the case with deps in the packaging step of
455    android_binary.
456
457    Args:
458      targets: A list of Target objects.
459
460    Returns:
461      A list of Target objects with duplicates removed.
462    """
463    seen_labels = {}
464    filtered_targets = []
465    for t in targets:
466        if t.label in seen_labels:
467            continue
468        seen_labels[t.label] = True
469        filtered_targets.append(t)
470    return filtered_targets
471
472def _package(
473        ctx,
474        assets = [],
475        assets_dir = None,
476        deps = [],
477        resource_apks = [],
478        manifest = None,
479        manifest_values = None,
480        instruments = None,
481        resource_configs = None,
482        densities = [],
483        resource_files = [],
484        nocompress_extensions = [],
485        java_package = None,
486        package_id = None,
487        compilation_mode = _compilation_mode.FASTBUILD,
488        shrink_resources = None,
489        use_android_resource_shrinking = None,
490        use_android_resource_cycle_shrinking = None,
491        use_legacy_manifest_merger = False,
492        should_throw_on_conflict = True,
493        enable_data_binding = False,
494        enable_manifest_merging = True,
495        should_compile_java_srcs = True,
496        minsdk_proguard_config = None,
497        aapt = None,
498        has_local_proguard_specs = False,
499        android_jar = None,
500        legacy_merger = None,
501        xsltproc = None,
502        instrument_xslt = None,
503        busybox = None,
504        host_javabase = None,
505        add_application_resource_info_to_providers = True):
506    """Package resources for top-level rules.
507
508    Args:
509      ctx: The context.
510      assets: sequence of Files. A list of assets to be packaged. All files be
511        under the assets_dir directory in the corresponding package.
512      assets_dir: String. A string giving the path to the files in assets. The
513        pair assets and assets_dir describe packaged assets and either both
514        parameters should be provided or none of them.
515      deps: sequence of Targets. The list of other libraries targets to link
516        against.
517      resource_apks: sequence of resource only apk files
518      manifest: File. The input top-level AndroidManifest.xml.
519      manifest_values: String dictionary. Manifest values to substitute.
520      instruments: Optional target. The value of the "instruments" attr if set.
521      resource_configs: sequence of Strings. A list of resource_configuration_filters
522        to apply.
523      densities: sequence of Strings. A list of densities to filter for when building
524        the apk.
525      resource_files: sequence of Files. A list of Android resource files
526        to be processed.
527      nocompress_extensions: sequence of Strings. File extension to leave uncompressed
528        in the apk.
529      java_package: String. Java package for which java sources will be
530        generated. By default the package is inferred from the directory where
531        the BUILD file containing the rule is.
532      package_id: An optional integer in [2,255]. This is the prefix byte for
533        all generated resource IDs, defaults to 0x7F (127). 1 is reserved by the
534        framework, and some builds are known to crash when given IDs > 127.
535        Shared libraries are also assigned monotonically increasing IDs in
536        [2,126], so care should be taken that there is room at the lower end.
537      compilation_mode: String. A string that represents compilation mode. The
538        list of expected values are as follows: dbg, fastbuild, opt.
539      shrink_resources: Tristate. Whether resource shrinking is enabled by the rule.
540      use_android_resource_shrinking: Bool. Flag that controls the default value for
541        shrink_resources if the tristate value is auto (-1).
542      use_android_resource_cycle_shrinking: Bool. Flag that enables more shrinking of
543        code and resources by instructing AAPT2 to emit conditional Proguard keep rules.
544      use_legacy_manifest_merger: A boolean. Whether to use the legacy manifest merger
545      instead of the android manifest merger.
546      should_throw_on_conflict: A boolean. Determines whether an error should be thrown
547        when a resource conflict occurs.
548      enable_data_binding: boolean. If true, processesing the data binding
549        expressions in layout resources included through the resource_files
550        parameter is enabled. Without this setting, data binding expressions
551        produce build failures.
552      enable_manifest_merging: boolean. If true, manifest merging will be performed.
553      should_compile_java_srcs: boolean. If native android_binary should perform java compilation.
554      minsdk_proguard_config: Optional file. Proguard config for the minSdkVersion to include in the
555        returned resource context.
556      aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
557      has_local_proguard_specs: If the target has proguard specs.
558      android_jar: File. The Android jar.
559      legacy_merger: FilesToRunProvider. The legacy manifest merger executable.
560      xsltproc: FilesToRunProvider. The xsltproc executable or
561        FilesToRunProvider.
562      instrument_xslt: File. The add_g3itr.xslt file describing the xslt
563        transformation to apply.
564      busybox: FilesToRunProvider. The ResourceBusyBox executable or
565        FilesToRunprovider
566      host_javabase: A Target. The host javabase.
567      add_application_resource_info_to_providers: boolean. Whether to add the
568          AndroidApplicationResourceInfo provider to the list of providers for this processor.
569
570    Returns:
571      A ResourcesPackageContextInfo containing packaged resource artifacts and
572        providers.
573    """
574    _validate_resources(resource_files)
575
576    packaged_resources_ctx = {
577        _PROVIDERS: [],
578    }
579
580    g3itr_manifest = manifest
581
582    if xsltproc or instrument_xslt:
583        g3itr_manifest = ctx.actions.declare_file(
584            "_migrated/" + ctx.label.name + "add_g3itr/AndroidManifest.xml",
585        )
586        _add_g3itr(
587            ctx,
588            out_manifest = g3itr_manifest,
589            manifest = manifest,
590            xsltproc = xsltproc,
591            instrument_xslt = instrument_xslt,
592        )
593
594    direct_resources_nodes = []
595    transitive_resources_nodes = []
596    transitive_assets = []
597    transitive_assets_symbols = []
598    transitive_compiled_assets = []
599    transitive_resource_files = []
600    transitive_compiled_resources = []
601    transitive_manifests = []
602    transitive_r_txts = []
603    packages_to_r_txts_depset = dict()
604    transitive_resource_apks = []
605
606    for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, deps):
607        direct_resources_nodes.append(dep.direct_resources_nodes)
608        transitive_resources_nodes.append(dep.transitive_resources_nodes)
609        transitive_assets.append(dep.transitive_assets)
610        transitive_assets_symbols.append(dep.transitive_assets_symbols)
611        transitive_compiled_assets.append(dep.transitive_compiled_assets)
612        transitive_resource_files.append(dep.transitive_resource_files)
613        transitive_compiled_resources.append(dep.transitive_compiled_resources)
614        transitive_manifests.append(dep.transitive_manifests)
615        transitive_r_txts.append(dep.transitive_r_txts)
616        for pkg, r_txts in dep.packages_to_r_txts.items():
617            packages_to_r_txts_depset.setdefault(pkg, []).append(r_txts)
618        transitive_resource_apks.append(dep.transitive_resource_apks)
619    mergee_manifests = depset([
620        node_info.manifest
621        for node_info in depset(transitive = transitive_resources_nodes + direct_resources_nodes).to_list()
622        if node_info.exports_manifest
623    ])
624
625    if not acls.in_shared_library_resource_linking_allowlist(str(ctx.label)):
626        # to_list() safe to use as we expect this to be an empty depset in the non-error case
627        all_res_apks = depset(
628            resource_apks,
629            transitive = transitive_resource_apks,
630            order = "preorder",
631        ).to_list()
632        if all_res_apks:
633            fail(
634                "%s has resource apks in the transitive closure without being allowlisted.\n%s" % (
635                    ctx.label,
636                    all_res_apks,
637                ),
638            )
639
640    # TODO(b/156763506): Add analysis tests to verify logic around when manifest merging is configured.
641    # TODO(b/154153771): Run the android merger if mergee_manifests or manifest values are present.
642    merged_manifest = g3itr_manifest
643    if enable_manifest_merging and (manifest_values or mergee_manifests):
644        if use_legacy_manifest_merger:
645            # Legacy manifest merger only runs if mergee manifests are present
646            if mergee_manifests:
647                merged_manifest = ctx.actions.declare_file(
648                    "_migrated/_merged/" + ctx.label.name + "/AndroidManifest.xml",
649                )
650                _legacy_merge_manifests(
651                    ctx,
652                    out_merged_manifest = merged_manifest,
653                    manifest = g3itr_manifest,
654                    mergee_manifests = mergee_manifests,
655                    legacy_merger = legacy_merger,
656                )
657        else:
658            merged_manifest = ctx.actions.declare_file(
659                "_migrated/_merged/" + ctx.label.name + "/AndroidManifest.xml",
660            )
661            _busybox.merge_manifests(
662                ctx,
663                out_file = merged_manifest,
664                out_log_file = ctx.actions.declare_file(
665                    "_migrated/_merged/" + ctx.label.name + "/manifest_merger_log.txt",
666                ),
667                manifest = g3itr_manifest,
668                mergee_manifests = mergee_manifests,
669                manifest_values = manifest_values,
670                merge_type = "APPLICATION",
671                java_package = java_package,
672                busybox = busybox,
673                host_javabase = host_javabase,
674            )
675
676    processed_resources = resource_files
677    data_binding_layout_info = None
678    if enable_data_binding:
679        data_binding_layout_info = ctx.actions.declare_file("_migrated/" + ctx.label.name + "/layout-info.zip")
680        processed_resources, resources_dirname = _make_databinding_outputs(
681            ctx,
682            resource_files,
683        )
684        _busybox.process_databinding(
685            ctx,
686            out_databinding_info = data_binding_layout_info,
687            out_databinding_processed_resources = processed_resources,
688            databinding_resources_dirname = resources_dirname,
689            resource_files = resource_files,
690            java_package = java_package,
691            busybox = busybox,
692            host_javabase = host_javabase,
693        )
694
695    resource_shrinking_enabled = _is_resource_shrinking_enabled(
696        shrink_resources,
697        use_android_resource_shrinking,
698    )
699    shrink_resource_cycles = _should_shrink_resource_cycles(
700        use_android_resource_cycle_shrinking,
701        resource_shrinking_enabled,
702        has_local_proguard_specs,
703    )
704
705    resource_apk = ctx.actions.declare_file(ctx.label.name + "_migrated/.ap_")
706    r_java = ctx.actions.declare_file("_migrated/" + ctx.label.name + ".srcjar")
707    r_txt = ctx.actions.declare_file(ctx.label.name + "_migrated/_symbols/R.txt")
708    processed_manifest = ctx.actions.declare_file(ctx.label.name + "_migrated/_processed_manifest/AndroidManifest.xml")
709    proguard_cfg = ctx.actions.declare_file(
710        "_migrated/proguard/%s/_%s_proguard.cfg" % (ctx.label.name, ctx.label.name),
711    )
712    main_dex_proguard_cfg = ctx.actions.declare_file(
713        "_migrated/proguard/%s/main_dex_%s_proguard.cfg" %
714        (ctx.label.name, ctx.label.name),
715    )
716    resource_files_zip = ctx.actions.declare_file(
717        "_migrated/" + ctx.label.name + "_files/resource_files.zip",
718    )
719    _busybox.package(
720        ctx,
721        out_file = resource_apk,
722        out_r_src_jar = r_java,
723        out_r_txt = r_txt,
724        out_symbols = ctx.actions.declare_file("_migrated/" + ctx.label.name + "_symbols/merged.bin"),
725        out_manifest = processed_manifest,
726        out_proguard_cfg = proguard_cfg,
727        out_main_dex_proguard_cfg = main_dex_proguard_cfg,
728        out_resource_files_zip = resource_files_zip,
729        application_id = manifest_values.get("applicationId", None),
730        package_id = package_id,
731        manifest = merged_manifest,
732        assets = assets,
733        assets_dir = assets_dir,
734        resource_files = processed_resources,
735        resource_apks = depset(resource_apks, transitive = transitive_resource_apks, order = "preorder"),
736        direct_resources_nodes =
737            depset(transitive = direct_resources_nodes, order = "preorder"),
738        transitive_resources_nodes =
739            depset(transitive = transitive_resources_nodes, order = "preorder"),
740        transitive_assets = transitive_assets,
741        transitive_compiled_assets = transitive_compiled_assets,
742        transitive_resource_files = transitive_resource_files,
743        transitive_compiled_resources = transitive_compiled_resources,
744        transitive_manifests = transitive_manifests,
745        transitive_r_txts = transitive_r_txts,
746        resource_configs = resource_configs,
747        densities = densities,
748        nocompress_extensions = nocompress_extensions,
749        java_package = java_package,
750        shrink_resource_cycles = shrink_resource_cycles,
751        version_name = manifest_values[_VERSION_NAME] if _VERSION_NAME in manifest_values else None,
752        version_code = manifest_values[_VERSION_CODE] if _VERSION_CODE in manifest_values else None,
753        android_jar = android_jar,
754        aapt = aapt,
755        busybox = busybox,
756        host_javabase = host_javabase,
757        debug = compilation_mode != _compilation_mode.OPT,
758        should_throw_on_conflict = should_throw_on_conflict,
759    )
760    packaged_resources_ctx[_PACKAGED_FINAL_MANIFEST] = processed_manifest
761    packaged_resources_ctx[_PACKAGED_RESOURCE_APK] = resource_apk
762    packaged_resources_ctx[_PACKAGED_VALIDATION_RESULT] = resource_files_zip
763    packaged_resources_ctx[_RESOURCE_PROGUARD_CONFIG] = proguard_cfg
764    packaged_resources_ctx[_RESOURCE_MINSDK_PROGUARD_CONFIG] = minsdk_proguard_config
765    packaged_resources_ctx[_MAIN_DEX_PROGUARD_CONFIG] = main_dex_proguard_cfg
766    packaged_resources_ctx[_PACKAGED_R_TXT] = r_txt
767
768    # Fix class jar name because some tests depend on {label_name}_resources.jar being the suffix of
769    # the path, with _common.PACKAGED_RESOURCES_SUFFIX removed from the label name.
770    class_jar_name = ctx.label.name + "_migrated/_resources.jar"
771    if ctx.label.name.endswith(_common.PACKAGED_RESOURCES_SUFFIX):
772        label_name = ctx.label.name.removesuffix(_common.PACKAGED_RESOURCES_SUFFIX)
773        class_jar_name = ctx.label.name + "_migrated/" + label_name + "_resources.jar"
774
775    class_jar = ctx.actions.declare_file(class_jar_name)
776    _busybox.generate_binary_r(
777        ctx,
778        out_class_jar = class_jar,
779        r_txt = r_txt,
780        manifest = processed_manifest,
781        package_for_r = java_package,
782        final_fields = not shrink_resource_cycles and not instruments,
783        resources_nodes = depset(transitive = direct_resources_nodes + transitive_resources_nodes),
784        transitive_r_txts = transitive_r_txts,
785        transitive_manifests = transitive_manifests,
786        busybox = busybox,
787        host_javabase = host_javabase,
788    )
789    packaged_resources_ctx[_PACKAGED_CLASS_JAR] = class_jar
790
791    java_info = JavaInfo(
792        output_jar = class_jar,
793        compile_jar = class_jar,
794        source_jar = r_java,
795    )
796
797    packaged_resources_ctx[_R_JAVA] = java_info
798    packaged_resources_ctx[_DATA_BINDING_LAYOUT_INFO] = data_binding_layout_info
799
800    packages_to_r_txts_depset.setdefault(java_package, []).append(depset([r_txt]))
801
802    packages_to_r_txts = dict()
803    for pkg, depsets in packages_to_r_txts_depset.items():
804        packages_to_r_txts[pkg] = depset(transitive = depsets)
805
806    # Adding empty depsets to unused fields of StarlarkAndroidResourcesInfo.
807    # Some root targets may depends on other root targets and try to access those fields.
808    packaged_resources_ctx[_PROVIDERS].append(StarlarkAndroidResourcesInfo(
809        direct_resources_nodes = depset(),
810        transitive_resources_nodes = depset(),
811        transitive_assets = depset(),
812        transitive_assets_symbols = depset(),
813        transitive_compiled_assets = depset(),
814        transitive_resource_files = depset(),
815        direct_compiled_resources = depset(),
816        transitive_compiled_resources = depset(),
817        transitive_manifests = depset(),
818        transitive_r_txts = depset(),
819        packages_to_r_txts = packages_to_r_txts,
820        transitive_resource_apks = depset(),
821    ))
822
823    android_application_resource_info = AndroidApplicationResourceInfo(
824        resource_apk = resource_apk,
825        resource_java_src_jar = r_java,
826        resource_java_class_jar = class_jar,
827        manifest = processed_manifest,
828        resource_proguard_config = proguard_cfg,
829        main_dex_proguard_config = main_dex_proguard_cfg,
830        r_txt = r_txt,
831        resources_zip = resource_files_zip,
832        databinding_info = data_binding_layout_info,
833        should_compile_java_srcs = should_compile_java_srcs,
834    )
835    packaged_resources_ctx[_ANDROID_APPLICATION_RESOURCE] = android_application_resource_info
836    if add_application_resource_info_to_providers:
837        packaged_resources_ctx[_PROVIDERS].append(android_application_resource_info)
838
839    return _ResourcesPackageContextInfo(**packaged_resources_ctx)
840
841def _liteparse(ctx, out_r_pb, resource_files, android_kit):
842    """Creates an R.pb which contains the resource ids gotten from a light parse.
843
844    Args:
845      ctx: The context.
846      out_r_pb: File. The R.pb output file.
847      resource_files: List of Files. The list of resource files.
848      android_kit: FilesToRunProvider. The Android Kit executable or
849        FilesToRunProvider.
850    """
851    args = ctx.actions.args()
852    args.use_param_file(param_file_arg = "--flagfile=%s", use_always = True)
853    args.set_param_file_format("multiline")
854    args.add_joined("--res_files", resource_files, join_with = ",")
855    args.add("--out", out_r_pb)
856
857    ctx.actions.run(
858        executable = android_kit,
859        arguments = ["liteparse", args],
860        inputs = resource_files,
861        outputs = [out_r_pb],
862        mnemonic = "ResLiteParse",
863        progress_message = "Lite parse Android Resources %s" % ctx.label,
864        toolchain = None,
865    )
866
867def _fastr(ctx, r_pbs, package, manifest, android_kit):
868    """Create R.srcjar from the given R.pb files in the transitive closure.
869
870    Args:
871      ctx: The context.
872      r_pbs: Transitive  set of resource pbs.
873      package: The package name of the compile-time R.java.
874      manifest: File. The AndroidManifest.xml file.
875      android_kit: FilesToRunProvider. The Android Kit executable or
876        FilesToRunProvider.
877
878    Returns:
879      The output R source jar artifact.
880    """
881    inputs = r_pbs
882    r_srcjar = ctx.actions.declare_file(ctx.label.name + "/resources/R-fastr.srcjar")
883    args = ctx.actions.args()
884    args.use_param_file(param_file_arg = "--flagfile=%s", use_always = True)
885    args.set_param_file_format("multiline")
886    args.add("-rJavaOutput", r_srcjar)
887    if package:
888        args.add("-packageForR", package)
889    else:
890        args.add("-manifest", manifest)
891        inputs = depset([manifest], transitive = [inputs])
892    args.add_joined("-resourcePbs", r_pbs, join_with = ",")
893
894    ctx.actions.run(
895        executable = android_kit,
896        arguments = ["rstub", args],
897        inputs = inputs,
898        outputs = [r_srcjar],
899        mnemonic = "CompileTimeR",
900        progress_message = "Generating compile-time R %s" % r_srcjar.short_path,
901    )
902    return r_srcjar
903
904def _compile(
905        ctx,
906        out_compiled_resources = None,
907        out_r_pb = None,
908        resource_files = [],
909        aapt = None,
910        android_kit = None,
911        busybox = None,
912        host_javabase = None):
913    """Compile Android Resources processing pipeline.
914
915    Args:
916      ctx: The context.
917      out_compiled_resources: File. The compiled resources output file.
918      out_r_pb: File. The R.pb output file.
919      resource_files: A list of Files. The resource files can be directories.
920      aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
921      android_kit: FilesToRunProvider. The android_kit executable or
922        FilesToRunProvider.
923      busybox: FilesToRunProvider. The ResourceBusyBox executable or
924        FilesToRunprovider
925      host_javabase: A Target. The host javabase.
926    """
927    _liteparse(ctx, out_r_pb, resource_files, android_kit)
928    _busybox.compile(
929        ctx,
930        out_file = out_compiled_resources,
931        resource_files = resource_files,
932        aapt = aapt,
933        busybox = busybox,
934        host_javabase = host_javabase,
935    )
936
937def _make_aar(
938        ctx,
939        assets = [],
940        assets_dir = None,
941        resource_files = [],
942        class_jar = None,
943        r_txt = None,
944        manifest = None,
945        proguard_specs = [],
946        busybox = None,
947        host_javabase = None):
948    """Generate an android archive file.
949
950    Args:
951      ctx: The context.
952      assets: sequence of Files. A list of Android assets files to be processed.
953      assets_dir: String. The name of the assets directory.
954      resource_files: A list of Files. The resource files.
955      class_jar: File. The class jar file.
956      r_txt: File. The resource IDs outputted by linking resources in text.
957      manifest: File. The primary AndroidManifest.xml.
958      proguard_specs: List of File. The proguard spec files.
959      busybox: FilesToRunProvider. The ResourceBusyBox executable or
960        FilesToRunprovider
961      host_javabase: A Target. The host javabase.
962
963    Returns:
964      The output aar artifact.
965    """
966    aar = ctx.actions.declare_file(ctx.label.name + ".aar")
967    _busybox.make_aar(
968        ctx,
969        out_aar = aar,
970        assets = assets,
971        assets_dir = assets_dir,
972        resource_files = resource_files,
973        class_jar = class_jar,
974        r_txt = r_txt,
975        manifest = manifest,
976        proguard_specs = proguard_specs,
977        busybox = busybox,
978        host_javabase = host_javabase,
979    )
980    return aar
981
982def _validate(ctx, manifest, defined_assets, defined_assets_dir):
983    if ((defined_assets and not defined_assets_dir) or
984        (not defined_assets and defined_assets_dir)):
985        _log.error(_ASSET_DEFINITION_ERROR % ctx.label)
986
987    if not manifest:
988        _log.error(_MANIFEST_MISSING_ERROR % ctx.label)
989
990def _make_direct_assets_transitive(assets_info):
991    return AndroidAssetsInfo(
992        assets_info.label,
993        assets_info.validation_result,
994        depset([]),  # direct_parsed_assets
995        depset(
996            transitive = [
997                assets_info.direct_parsed_assets,
998                assets_info.transitive_parsed_assets,
999            ],
1000            order = "preorder",
1001        ),
1002        assets_info.assets,
1003        assets_info.symbols,
1004        assets_info.compiled_symbols,
1005    )
1006
1007def _make_direct_resources_transitive(resources_info):
1008    return AndroidResourcesInfo(
1009        resources_info.label,
1010        resources_info.manifest,
1011        resources_info.compiletime_r_txt,
1012        # NB: the ordering of "direct" and "transitive" is inconsistent with that used for
1013        # AndroidAssetsInfo.
1014        depset(
1015            transitive = [
1016                # Ordering is inconsistent here too:
1017                # https://github.com/bazelbuild/bazel/blob/82c7f48b4628ebbec18123afdbed701bbaa605e2/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java#L158
1018                resources_info.transitive_android_resources,
1019                resources_info.direct_android_resources,
1020            ],
1021            order = "preorder",
1022        ),
1023        depset([]),  # direct_android_resources
1024        resources_info.transitive_resources,
1025        resources_info.transitive_manifests,
1026        resources_info.transitive_aapt2_r_txt,
1027        resources_info.transitive_symbols_bin,
1028        resources_info.transitive_compiled_symbols,
1029        resources_info.transitive_static_lib,
1030        resources_info.transitive_r_txt,
1031        validation_artifacts = resources_info.validation_artifacts,
1032    )
1033
1034def _export_assets(assets_info, exports):
1035    all_providers = [assets_info] + utils.collect_providers(AndroidAssetsInfo, exports)
1036    return AndroidAssetsInfo(
1037        assets_info.label,
1038        assets_info.validation_result,
1039        direct_parsed_assets = utils.join_depsets(all_providers, "direct_parsed_assets", order = "preorder"),
1040        transitive_parsed_assets = utils.join_depsets(all_providers, "transitive_parsed_assets", order = "preorder"),
1041        transitive_assets = utils.join_depsets(all_providers, "assets", order = "preorder"),
1042        transitive_symbols = utils.join_depsets(all_providers, "symbols", order = "preorder"),
1043        transitive_compiled_symbols = utils.join_depsets(all_providers, "compiled_symbols", order = "preorder"),
1044    )
1045
1046def _export_resources(resources_info, exports):
1047    all_providers = [resources_info] + utils.collect_providers(AndroidResourcesInfo, exports)
1048    return AndroidResourcesInfo(
1049        resources_info.label,
1050        resources_info.manifest,
1051        resources_info.compiletime_r_txt,
1052        **{attr: utils.join_depsets(all_providers, attr, order = "preorder") for attr in [
1053            "transitive_android_resources",
1054            "direct_android_resources",
1055            "transitive_resources",
1056            "transitive_manifests",
1057            "transitive_aapt2_r_txt",
1058            "transitive_symbols_bin",
1059            "transitive_compiled_symbols",
1060            "transitive_static_lib",
1061            "transitive_r_txt",
1062            "validation_artifacts",
1063        ]}
1064    )
1065
1066def _validate_resources(resource_files = None):
1067    for resource_file in resource_files:
1068        path_segments = resource_file.path.split("/")
1069        if len(path_segments) < 3:
1070            fail(_INCORRECT_RESOURCE_LAYOUT_ERROR % resource_file)
1071
1072        # Check the resource directory type if the resource file is not a Fileset.
1073        if not resource_file.is_directory:
1074            # The resource directory is presumed to be the second directory from the end.
1075            # Resource directories can have multiple qualifiers, each one separated with a dash.
1076            res_type = path_segments[-2].partition(_RESOURCE_QUALIFIER_SEP)[0]
1077            if res_type not in _RESOURCE_FOLDER_TYPES:
1078                fail(_INCORRECT_RESOURCE_LAYOUT_ERROR % resource_file)
1079
1080def _process_manifest_values(ctx, manifest_values, min_sdk_floor):
1081    expanded_manifest_values = utils.expand_make_vars(ctx, manifest_values)
1082    if _MIN_SDK_VERSION in expanded_manifest_values and min_sdk_floor > 0:
1083        expanded_manifest_values[_MIN_SDK_VERSION] = str(
1084            max(int(expanded_manifest_values[_MIN_SDK_VERSION]), min_sdk_floor),
1085        )
1086    return expanded_manifest_values
1087
1088def _bump_min_sdk(
1089        ctx,
1090        manifest = None,
1091        manifest_values = None,
1092        floor = None,
1093        enforce_min_sdk_floor_tool = None):
1094    """Bumps the min SDK attribute of AndroidManifest to the floor.
1095
1096    Args:
1097      ctx: The rules context.
1098      manifest: File. The AndroidManifest.xml file.
1099      manifest_values: Dictionary. The optional manifest_values to process.
1100      floor: int. The min SDK floor. Manifest is unchanged if floor <= 0.
1101      enforce_min_sdk_floor_tool: FilesToRunProvider. The enforce_min_sdk_tool executable or
1102        FilesToRunprovider
1103
1104    Returns:
1105      A dict containing _ManifestContextInfo provider fields.
1106    """
1107    manifest_ctx = {}
1108
1109    if floor == None:
1110        fail("Missing required `floor` in bump_min_sdk")
1111
1112    if manifest_values != None:
1113        manifest_ctx[_PROCESSED_MANIFEST_VALUES] = _process_manifest_values(
1114            ctx,
1115            manifest_values,
1116            floor,
1117        )
1118
1119    if not manifest or floor <= 0:
1120        manifest_ctx[_PROCESSED_MANIFEST] = manifest
1121        return _ManifestContextInfo(**manifest_ctx)
1122
1123    args = ctx.actions.args()
1124    args.add("-action", "bump")
1125    args.add("-manifest", manifest)
1126    args.add("-min_sdk_floor", floor)
1127
1128    out_dir = "_migrated/_min_sdk_bumped/" + ctx.label.name + "/"
1129    log = ctx.actions.declare_file(
1130        out_dir + "log.txt",
1131    )
1132    args.add("-log", log.path)
1133
1134    out_manifest = ctx.actions.declare_file(
1135        out_dir + "AndroidManifest.xml",
1136    )
1137    args.add("-output", out_manifest.path)
1138    ctx.actions.run(
1139        executable = enforce_min_sdk_floor_tool,
1140        inputs = [manifest],
1141        outputs = [out_manifest, log],
1142        arguments = [args],
1143        mnemonic = "BumpMinSdkFloor",
1144        progress_message = "Bumping up AndroidManifest min SDK %s" % str(ctx.label),
1145        toolchain = None,
1146    )
1147    manifest_ctx[_PROCESSED_MANIFEST] = out_manifest
1148
1149    return _ManifestContextInfo(**manifest_ctx)
1150
1151def _set_default_min_sdk(
1152        ctx,
1153        manifest,
1154        default,
1155        enforce_min_sdk_floor_tool):
1156    """ Sets the min SDK attribute of AndroidManifest to default if it is not already set.
1157
1158    Args:
1159      ctx: The rules context.
1160      manifest: File. The AndroidManifest.xml file.
1161      default: string. The default value for min SDK. The manifest is unchanged if it already
1162        specifies a min SDK.
1163      enforce_min_sdk_floor_tool: FilesToRunProvider. The enforce_min_sdk_tool executable or
1164        FilesToRunprovider
1165
1166    Returns:
1167      A dict containing _ManifestContextInfo provider fields.
1168    """
1169    manifest_ctx = {}
1170    if not manifest or not default:
1171        manifest_ctx[_PROCESSED_MANIFEST] = manifest
1172        return _ManifestContextInfo(**manifest_ctx)
1173
1174    args = ctx.actions.args()
1175    args.add("-action", "set_default")
1176    args.add("-manifest", manifest)
1177    args.add("-default_min_sdk", default)
1178
1179    out_dir = "_migrated/_min_sdk_default_set/" + ctx.label.name + "/"
1180    log = ctx.actions.declare_file(
1181        out_dir + "log.txt",
1182    )
1183    args.add("-log", log.path)
1184
1185    out_manifest = ctx.actions.declare_file(
1186        out_dir + "AndroidManifest.xml",
1187    )
1188    args.add("-output", out_manifest.path)
1189    ctx.actions.run(
1190        executable = enforce_min_sdk_floor_tool,
1191        inputs = [manifest],
1192        outputs = [out_manifest, log],
1193        arguments = [args],
1194        mnemonic = "SetDefaultMinSdkFloor",
1195        progress_message = "Setting AndroidManifest min SDK to default %s" % str(ctx.label),
1196        toolchain = None,
1197    )
1198    manifest_ctx[_PROCESSED_MANIFEST] = out_manifest
1199
1200    return _ManifestContextInfo(**manifest_ctx)
1201
1202def _validate_min_sdk(
1203        ctx,
1204        manifest,
1205        floor,
1206        enforce_min_sdk_floor_tool):
1207    """Validates that the min SDK attribute of AndroidManifest is at least at the floor.
1208
1209    Args:
1210      ctx: The rules context.
1211      manifest: File. The AndroidManifest.xml file.
1212      floor: int. The min SDK floor. No validation is done if floor <= 0.
1213      enforce_min_sdk_floor_tool: FilesToRunProvider. The enforce_min_sdk_tool executable or
1214        FilesToRunprovider
1215
1216    Returns:
1217      A dict containing _ManifestValidationContextInfo provider fields.
1218    """
1219    manifest_validation_ctx = {_VALIDATION_OUTPUTS: []}
1220    if not manifest or floor <= 0:
1221        return _ManifestValidationContextInfo(**manifest_validation_ctx)
1222
1223    args = ctx.actions.args()
1224    args.add("-action", "validate")
1225    args.add("-manifest", manifest)
1226    args.add("-min_sdk_floor", floor)
1227
1228    out_dir = "_migrated/_min_sdk_validated/" + ctx.label.name + "/"
1229    log = ctx.actions.declare_file(
1230        out_dir + "log.txt",
1231    )
1232    args.add("-log", log.path)
1233
1234    ctx.actions.run(
1235        executable = enforce_min_sdk_floor_tool,
1236        inputs = [manifest],
1237        outputs = [log],
1238        arguments = [args],
1239        mnemonic = "ValidateMinSdkFloor",
1240        progress_message = "Validating AndroidManifest min SDK %s" % str(ctx.label),
1241        toolchain = None,
1242    )
1243    manifest_validation_ctx[_VALIDATION_OUTPUTS].append(log)
1244
1245    return _ManifestValidationContextInfo(**manifest_validation_ctx)
1246
1247def _process_starlark(
1248        ctx,
1249        java_package = None,
1250        manifest = None,
1251        defined_assets = False,
1252        assets = None,
1253        defined_assets_dir = False,
1254        assets_dir = None,
1255        exports_manifest = False,
1256        stamp_manifest = True,
1257        deps = [],
1258        resource_apks = [],
1259        exports = [],
1260        resource_files = None,
1261        neverlink = False,
1262        enable_data_binding = False,
1263        propagate_resources = True,
1264        fix_resource_transitivity = False,
1265        aapt = None,
1266        android_jar = None,
1267        android_kit = None,
1268        busybox = None,
1269        java_toolchain = None,
1270        host_javabase = None,
1271        instrument_xslt = None,
1272        xsltproc = None,
1273        zip_tool = None):
1274    """Processes Android Resources.
1275
1276    Args:
1277      ctx: The rules context.
1278      java_package: string. Java package for which java sources will be
1279        generated. By default the package is inferred from the directory where
1280        the BUILD file containing the rule is.
1281      manifest: File. The AndroidManifest.xml file.
1282      defined_assets: Bool. Signifies that the assets attribute was set, even
1283        if the value is an empty list.
1284      assets: sequence of Files. A list of Android assets files to be processed.
1285      defined_assets_dir: Bool. Signifies that the assets dir attribute was set,
1286        even if the value is an empty string.
1287      assets_dir: String. The name of the assets directory.
1288      exports_manifest: boolean. Whether to export manifest entries to the
1289        android_binary targets that depend on this target.
1290        NOTE: "uses-permissions" attributes are never exported.
1291      stamp_manifest: boolean. Whether to stamp the manifest with the java
1292        package of the target. If True, java_package needs to be passed to
1293        the function.
1294      deps: sequence of Targets. The list of other libraries targets to link
1295        against.
1296      resource_apks: sequence of resource apk files to link against.
1297      exports: sequence of Targets. The closure of all rules reached via exports
1298        attributes are considered direct dependencies of any rule that directly
1299        depends on the target with exports. The exports are not direct deps of
1300        the rule they belong to (TODO(b/144134042): make this so).
1301      resource_files: sequence of Files. A list of Android resource files to be
1302        processed.
1303      neverlink: boolean. Only use this library for compilation and not runtime.
1304        The outputs of a rule marked as neverlink will not be used in .apk
1305        creation. Useful if the library will be provided by the runtime
1306        environment during execution.
1307      enable_data_binding: boolean. If true, processesing the data binding
1308        expressions in layout resources included through the resource_files
1309        parameter is enabled. Without this setting, data binding expressions
1310        produce build failures.
1311      propagate_resources: boolean. If false, the target will no longer propagate
1312        providers required for Android Resource processing/packaging. But will
1313        continue to propagate others (AndroidLibraryResourceClassJarProvider).
1314      fix_resource_transitivity: Whether to ensure that transitive resources are
1315        correctly marked as transitive.
1316      aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
1317      android_jar: File. The android Jar.
1318      android_kit: FilesToRunProvider. The android_kit executable or
1319        FilesToRunProvider.
1320      busybox: FilesToRunProvider. The ResourceBusyBox executable or
1321        FilesToRunprovider
1322      java_toolchain: The java_toolchain Target.
1323      host_javabase: Target. The host javabase.
1324      instrument_xslt: File. The xslt transform to apply g3itr.
1325      xsltproc: FilesToRunProvider. The xsltproc executable or FilesToRunProvider.
1326      zip_tool: FilesToRunProvider. The zip tool executable or FilesToRunProvider.
1327
1328    Returns:
1329      A dict containing _ResourcesProcessContextInfo provider fields.
1330    """
1331    if (xsltproc and not instrument_xslt) or (not xsltproc and instrument_xslt):
1332        fail(
1333            "Error, both instrument_xslt and xsltproc need to be " +
1334            "specified or not, got:\nxlstproc = %s\ninstrument_xslt = %s" %
1335            (xsltproc, instrument_xslt),
1336        )
1337
1338    _validate_resources(resource_files)
1339
1340    defines_resources = bool(
1341        manifest or
1342        resource_files or
1343        defined_assets or
1344        defined_assets_dir or
1345        exports_manifest,
1346    )
1347
1348    # TODO(djwhang): Clean up the difference between neverlink the attribute used
1349    # by Java compilation and resources neverlink.
1350    resources_neverlink = (
1351        neverlink and (
1352            defines_resources or
1353            ctx.fragments.android.fixed_resource_neverlinking
1354        )
1355    )
1356
1357    resources_ctx = {
1358        _RESOURCES_APK: None,
1359        _PROVIDERS: [],
1360        # TODO(b/156530953): Move the validation result to the validation_outputs list when we are
1361        # done rolling out Starlark resources processing
1362        _VALIDATION_RESULTS: [],
1363        _DEFINES_RESOURCES: defines_resources,
1364        _R_JAVA: None,
1365        _DATA_BINDING_LAYOUT_INFO: None,
1366        _MERGED_MANIFEST: None,
1367        _STARLARK_PROCESSED_MANIFEST: None,
1368        _STARLARK_R_TXT: None,
1369        _STARLARK_PROCESSED_RESOURCES: [],
1370    }
1371
1372    if resource_files and not manifest:
1373        _log.error(_MANIFEST_MISSING_ERROR % ctx.label)
1374
1375    direct_resources_nodes = []
1376    transitive_resources_nodes = []
1377    transitive_assets = []
1378    transitive_assets_symbols = []
1379    transitive_compiled_assets = []
1380    direct_compiled_resources = []
1381    transitive_compiled_resources = []
1382    transitive_resources_files = []
1383    transitive_manifests = []
1384    transitive_r_txts = []
1385    packages_to_r_txts_depset = dict()
1386    transitive_resource_apks = []
1387
1388    for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, deps):
1389        direct_resources_nodes.append(dep.direct_resources_nodes)
1390        transitive_resources_nodes.append(dep.transitive_resources_nodes)
1391        transitive_assets.append(dep.transitive_assets)
1392        transitive_assets_symbols.append(dep.transitive_assets_symbols)
1393        transitive_compiled_assets.append(dep.transitive_compiled_assets)
1394        direct_compiled_resources.append(dep.direct_compiled_resources)
1395        transitive_compiled_resources.append(dep.transitive_compiled_resources)
1396        transitive_resources_files.append(dep.transitive_resource_files)
1397        transitive_manifests.append(dep.transitive_manifests)
1398        transitive_r_txts.append(dep.transitive_r_txts)
1399        for pkg, r_txts in dep.packages_to_r_txts.items():
1400            packages_to_r_txts_depset.setdefault(pkg, []).append(r_txts)
1401        transitive_resource_apks.append(dep.transitive_resource_apks)
1402    exports_direct_resources_nodes = []
1403    exports_transitive_resources_nodes = []
1404    exports_transitive_assets = []
1405    exports_transitive_assets_symbols = []
1406    exports_transitive_compiled_assets = []
1407    exports_direct_compiled_resources = []
1408    exports_transitive_compiled_resources = []
1409    exports_transitive_resources_files = []
1410    exports_transitive_manifests = []
1411    exports_transitive_r_txts = []
1412    for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, exports):
1413        exports_direct_resources_nodes.append(dep.direct_resources_nodes)
1414        exports_transitive_resources_nodes.append(dep.transitive_resources_nodes)
1415        exports_transitive_assets.append(dep.transitive_assets)
1416        exports_transitive_assets_symbols.append(dep.transitive_assets_symbols)
1417        exports_transitive_compiled_assets.append(dep.transitive_compiled_assets)
1418        exports_direct_compiled_resources.append(dep.direct_compiled_resources)
1419        exports_transitive_compiled_resources.append(dep.transitive_compiled_resources)
1420        exports_transitive_resources_files.append(dep.transitive_resource_files)
1421        exports_transitive_manifests.append(dep.transitive_manifests)
1422        exports_transitive_r_txts.append(dep.transitive_r_txts)
1423        for pkg, r_txts in dep.packages_to_r_txts.items():
1424            packages_to_r_txts_depset.setdefault(pkg, []).append(r_txts)
1425
1426    # TODO(b/144134042): Don't merge exports; exports are not deps.
1427    direct_resources_nodes.extend(exports_direct_resources_nodes)
1428    transitive_resources_nodes.extend(exports_transitive_resources_nodes)
1429    transitive_assets.extend(exports_transitive_assets)
1430    transitive_assets_symbols.extend(exports_transitive_assets_symbols)
1431    transitive_compiled_assets.extend(exports_transitive_compiled_assets)
1432    direct_compiled_resources.extend(exports_direct_compiled_resources)
1433    transitive_compiled_resources.extend(exports_transitive_compiled_resources)
1434    transitive_resources_files.extend(exports_transitive_resources_files)
1435    transitive_manifests.extend(exports_transitive_manifests)
1436    transitive_r_txts.extend(exports_transitive_r_txts)
1437
1438    compiled_assets = None
1439    parsed_assets = None
1440    compiled_resources = None
1441    out_aapt2_r_txt = None
1442    r_txt = None
1443    data_binding_layout_info = None
1444    processed_resources = resource_files
1445    processed_manifest = None
1446    if not defines_resources:
1447        if aapt:
1448            # Generate an empty manifest with the right package
1449            generated_manifest = ctx.actions.declare_file(
1450                "_migrated/_generated/" + ctx.label.name + "/AndroidManifest.xml",
1451            )
1452            _generate_dummy_manifest(
1453                ctx,
1454                out_manifest = generated_manifest,
1455                java_package = java_package if java_package else ctx.label.package.replace("/", "."),
1456                min_sdk_version = acls.get_min_sdk_floor(str(ctx.label)),
1457            )
1458            r_txt = ctx.actions.declare_file(
1459                "_migrated/" + ctx.label.name + "_symbols/R.txt",
1460            )
1461            out_manifest = ctx.actions.declare_file(
1462                "_migrated/" + ctx.label.name + "_processed_manifest/AndroidManifest.xml",
1463            )
1464            _busybox.package(
1465                ctx,
1466                out_r_src_jar = ctx.actions.declare_file(
1467                    "_migrated/" + ctx.label.name + ".srcjar",
1468                ),
1469                out_r_txt = r_txt,
1470                out_manifest = out_manifest,
1471                manifest = generated_manifest,
1472                assets = assets,
1473                assets_dir = assets_dir,
1474                resource_files = resource_files,
1475                resource_apks = depset(resource_apks, transitive = transitive_resource_apks, order = "preorder"),
1476                direct_resources_nodes =
1477                    depset(transitive = direct_resources_nodes, order = "preorder"),
1478                transitive_resources_nodes =
1479                    depset(transitive = transitive_resources_nodes, order = "preorder"),
1480                transitive_assets = transitive_assets,
1481                transitive_compiled_assets = transitive_compiled_assets,
1482                transitive_resource_files = transitive_resources_files,
1483                transitive_compiled_resources = transitive_compiled_resources,
1484                transitive_manifests = transitive_manifests,
1485                transitive_r_txts = transitive_r_txts,
1486                package_type = "LIBRARY",
1487                java_package = java_package,
1488                android_jar = android_jar,
1489                aapt = aapt,
1490                busybox = busybox,
1491                host_javabase = host_javabase,
1492                should_throw_on_conflict = False,
1493            )
1494            resources_ctx[_STARLARK_PROCESSED_MANIFEST] = out_manifest
1495            resources_ctx[_STARLARK_R_TXT] = r_txt
1496            resources_ctx[_STARLARK_PROCESSED_RESOURCES] = resource_files
1497
1498    else:
1499        if stamp_manifest:
1500            stamped_manifest = ctx.actions.declare_file(
1501                "_migrated/_renamed/" + ctx.label.name + "/AndroidManifest.xml",
1502            )
1503            _busybox.merge_manifests(
1504                ctx,
1505                out_file = stamped_manifest,
1506                manifest = manifest,
1507                merge_type = "LIBRARY",
1508                java_package = java_package,
1509                busybox = busybox,
1510                host_javabase = host_javabase,
1511            )
1512            manifest = stamped_manifest
1513
1514        if instrument_xslt:
1515            g3itr_manifest = ctx.actions.declare_file(
1516                "_migrated/" + ctx.label.name + "_g3itr_manifest/AndroidManifest.xml",
1517            )
1518            _add_g3itr(
1519                ctx,
1520                out_manifest = g3itr_manifest,
1521                manifest = manifest,
1522                xsltproc = xsltproc,
1523                instrument_xslt = instrument_xslt,
1524            )
1525            manifest = g3itr_manifest
1526
1527        parsed_assets = ctx.actions.declare_file(
1528            "_migrated/" + ctx.label.name + "_symbols/assets.bin",
1529        )
1530        _busybox.parse(
1531            ctx,
1532            out_symbols = parsed_assets,
1533            assets = assets,
1534            assets_dir = assets_dir,
1535            busybox = busybox,
1536            host_javabase = host_javabase,
1537        )
1538        merged_assets = ctx.actions.declare_file(
1539            "_migrated/" + ctx.label.name + "_files/assets.zip",
1540        )
1541        _busybox.merge_assets(
1542            ctx,
1543            out_assets_zip = merged_assets,
1544            assets = assets,
1545            assets_dir = assets_dir,
1546            symbols = parsed_assets,
1547            direct_resources_nodes = depset(
1548                transitive = direct_resources_nodes,
1549                order = "preorder",
1550            ),
1551            transitive_resources_nodes = depset(
1552                transitive = transitive_resources_nodes,
1553                order = "preorder",
1554            ),
1555            transitive_assets = transitive_assets,
1556            transitive_assets_symbols = transitive_assets_symbols,
1557            busybox = busybox,
1558            host_javabase = host_javabase,
1559        )
1560        resources_ctx[_VALIDATION_RESULTS].append(merged_assets)
1561
1562        if assets:
1563            compiled_assets = ctx.actions.declare_file(
1564                "_migrated/" + ctx.label.name + "_symbols/assets.zip",
1565            )
1566            _busybox.compile(
1567                ctx,
1568                out_file = compiled_assets,
1569                assets = assets,
1570                assets_dir = assets_dir,
1571                aapt = aapt,
1572                busybox = busybox,
1573                host_javabase = host_javabase,
1574            )
1575
1576        if enable_data_binding:
1577            data_binding_layout_info = ctx.actions.declare_file(
1578                "_migrated/databinding/" + ctx.label.name + "/layout-info.zip",
1579            )
1580            processed_resources, resources_dirname = _make_databinding_outputs(
1581                ctx,
1582                resource_files,
1583            )
1584            _busybox.process_databinding(
1585                ctx,
1586                out_databinding_info = data_binding_layout_info,
1587                out_databinding_processed_resources = processed_resources,
1588                databinding_resources_dirname = resources_dirname,
1589                resource_files = resource_files,
1590                java_package = java_package,
1591                busybox = busybox,
1592                host_javabase = host_javabase,
1593            )
1594
1595        compiled_resources = ctx.actions.declare_file(
1596            "_migrated/" + ctx.label.name + "_symbols/symbols.zip",
1597        )
1598        _busybox.compile(
1599            ctx,
1600            out_file = compiled_resources,
1601            resource_files = processed_resources,
1602            aapt = aapt,
1603            busybox = busybox,
1604            host_javabase = host_javabase,
1605        )
1606
1607        # TODO(b/160907203): Remove this fix once the native resource processing pipeline is turned off.
1608        if enable_data_binding:
1609            fixed_compiled_resources = ctx.actions.declare_file(
1610                "_migrated/fixed/" + ctx.label.name + "_symbols/symbols.zip",
1611            )
1612            _fix_databinding_compiled_resources(
1613                ctx,
1614                out_compiled_resources = fixed_compiled_resources,
1615                compiled_resources = compiled_resources,
1616                zip_tool = zip_tool,
1617            )
1618            compiled_resources = fixed_compiled_resources
1619
1620        out_class_jar = ctx.actions.declare_file(
1621            "_migrated/" + ctx.label.name + "_resources.jar",
1622        )
1623        processed_manifest = ctx.actions.declare_file(
1624            "_migrated/" + ctx.label.name + "_processed_manifest/AndroidManifest.xml",
1625        )
1626        out_aapt2_r_txt = ctx.actions.declare_file(
1627            "_migrated/" + ctx.label.name + "_symbols/R.aapt2.txt",
1628        )
1629        _busybox.merge_compiled(
1630            ctx,
1631            out_class_jar = out_class_jar,
1632            out_manifest = processed_manifest,
1633            out_aapt2_r_txt = out_aapt2_r_txt,
1634            java_package = java_package,
1635            manifest = manifest,
1636            compiled_resources = compiled_resources,
1637            direct_resources_nodes =
1638                depset(transitive = direct_resources_nodes, order = "preorder"),
1639            transitive_resources_nodes = depset(
1640                transitive = transitive_resources_nodes,
1641                order = "preorder",
1642            ),
1643            direct_compiled_resources = depset(
1644                transitive = direct_compiled_resources,
1645                order = "preorder",
1646            ),
1647            transitive_compiled_resources = depset(
1648                transitive = transitive_compiled_resources,
1649                order = "preorder",
1650            ),
1651            android_jar = android_jar,
1652            busybox = busybox,
1653            host_javabase = host_javabase,
1654        )
1655        resources_ctx[_MERGED_MANIFEST] = processed_manifest
1656
1657        apk = ctx.actions.declare_file(
1658            "_migrated/" + ctx.label.name + "_files/library.ap_",
1659        )
1660        r_java = ctx.actions.declare_file(
1661            "_migrated/" + ctx.label.name + ".srcjar",
1662        )
1663        r_txt = ctx.actions.declare_file(
1664            "_migrated/" + ctx.label.name + "_symbols/R.txt",
1665        )
1666        _busybox.validate_and_link(
1667            ctx,
1668            out_r_src_jar = r_java,
1669            out_r_txt = r_txt,
1670            out_file = apk,
1671            compiled_resources = compiled_resources,
1672            transitive_compiled_resources = depset(
1673                transitive = transitive_compiled_resources,
1674                order = "preorder",
1675            ),
1676            java_package = java_package,
1677            manifest = processed_manifest,
1678            android_jar = android_jar,
1679            aapt = aapt,
1680            busybox = busybox,
1681            host_javabase = host_javabase,
1682            resource_apks = resource_apks,
1683        )
1684        resources_ctx[_RESOURCES_APK] = apk
1685
1686        java_info = JavaInfo(
1687            output_jar = out_class_jar,
1688            compile_jar = out_class_jar,
1689            source_jar = r_java,
1690        )
1691
1692        packages_to_r_txts_depset.setdefault(java_package, []).append(depset([out_aapt2_r_txt]))
1693
1694        resources_ctx[_R_JAVA] = java_info
1695        resources_ctx[_DATA_BINDING_LAYOUT_INFO] = data_binding_layout_info
1696
1697        # In a normal build, the outputs of _busybox.validate_and_link are unused. However we need
1698        # this action to run to support resource visibility checks.
1699        resources_ctx[_VALIDATION_RESULTS].append(r_txt)
1700
1701        # Needed for AAR generation. The Starlark resource processing pipeline uses the aapt2_r_txt file,
1702        # which is why we can't use the StarlarkAndroidResourcesInfo provider when generating the aar.
1703        resources_ctx[_STARLARK_PROCESSED_MANIFEST] = processed_manifest
1704        resources_ctx[_STARLARK_R_TXT] = r_txt
1705        resources_ctx[_STARLARK_PROCESSED_RESOURCES] = processed_resources
1706
1707    # TODO(b/117338320): Transitive lists defined here are incorrect; direct should come
1708    # before transitive, and the order should be topological order instead of preorder.
1709    # However, some applications may depend on this incorrect order.
1710    if defines_resources:
1711        transitive_resources_nodes = transitive_resources_nodes + direct_resources_nodes
1712        direct_resources_nodes = []
1713        transitive_compiled_resources = transitive_compiled_resources + direct_compiled_resources
1714        direct_compiled_resources = []
1715    else:
1716        if fix_resource_transitivity:
1717            transitive_resources_nodes = transitive_resources_nodes + direct_resources_nodes
1718            direct_resources_nodes = []
1719            transitive_compiled_resources = transitive_compiled_resources + direct_compiled_resources
1720            direct_compiled_resources = []
1721
1722        # TODO(b/144163743): If the resource transitivity fix is disabled and resources-related
1723        # inputs are missing, we implicitly export deps here. This legacy behavior must exist in the
1724        # Starlark resource processing pipeline until we can clean up the depot.
1725
1726    packages_to_r_txts = dict()
1727    for pkg, depsets in packages_to_r_txts_depset.items():
1728        packages_to_r_txts[pkg] = depset(transitive = depsets)
1729
1730    # TODO(b/159916013): Audit neverlink behavior. Some processing can likely be skipped if the target is neverlink.
1731    # TODO(b/69668042): Don't propagate exported providers/artifacts. Exports should respect neverlink.
1732    if resources_neverlink:
1733        resources_ctx[_PROVIDERS].append(StarlarkAndroidResourcesInfo(
1734            direct_resources_nodes = depset(
1735                transitive = exports_direct_resources_nodes,
1736                order = "preorder",
1737            ),
1738            transitive_resources_nodes = depset(
1739                transitive = exports_transitive_resources_nodes,
1740                order = "preorder",
1741            ),
1742            transitive_assets = depset(
1743                transitive = exports_transitive_assets,
1744                order = "preorder",
1745            ),
1746            transitive_assets_symbols = depset(
1747                transitive = exports_transitive_assets_symbols,
1748                order = "preorder",
1749            ),
1750            transitive_compiled_assets = depset(
1751                transitive = exports_transitive_compiled_assets,
1752                order = "preorder",
1753            ),
1754            transitive_resource_files = depset(
1755                transitive = exports_transitive_resources_files,
1756                order = "preorder",
1757            ),
1758            direct_compiled_resources = depset(
1759                transitive = exports_direct_compiled_resources,
1760                order = "preorder",
1761            ),
1762            transitive_compiled_resources = depset(
1763                transitive = exports_transitive_compiled_resources,
1764                order = "preorder",
1765            ),
1766            transitive_manifests = depset(
1767                [processed_manifest] if processed_manifest else [],
1768                transitive = exports_transitive_manifests,
1769                order = "preorder",
1770            ),
1771            transitive_r_txts = depset(
1772                [out_aapt2_r_txt] if out_aapt2_r_txt else [],
1773                transitive = exports_transitive_r_txts,
1774                order = "preorder",
1775            ),
1776            packages_to_r_txts = packages_to_r_txts,
1777            transitive_resource_apks = depset(
1778                resource_apks,
1779                transitive = transitive_resource_apks,
1780                order = "preorder",
1781            ),
1782        ))
1783    else:
1784        # Depsets are ordered below to match the order in the legacy native rules.
1785        resources_ctx[_PROVIDERS].append(StarlarkAndroidResourcesInfo(
1786            direct_resources_nodes = depset(
1787                [ResourcesNodeInfo(
1788                    label = ctx.label,
1789                    assets = depset(assets),
1790                    assets_dir = assets_dir,
1791                    assets_symbols = parsed_assets,
1792                    compiled_assets = compiled_assets,
1793                    resource_apks = depset(resource_apks),
1794                    resource_files = depset(processed_resources),
1795                    compiled_resources = compiled_resources,
1796                    r_txt = out_aapt2_r_txt,
1797                    manifest = processed_manifest,
1798                    exports_manifest = exports_manifest,
1799                )] if defines_resources else [],
1800                transitive = direct_resources_nodes + exports_direct_resources_nodes,
1801                order = "preorder",
1802            ),
1803            transitive_resources_nodes = depset(
1804                transitive = transitive_resources_nodes + exports_transitive_resources_nodes,
1805                order = "preorder",
1806            ),
1807            transitive_assets = depset(
1808                assets,
1809                transitive = transitive_assets + exports_transitive_assets,
1810                order = "preorder",
1811            ),
1812            transitive_assets_symbols = depset(
1813                [parsed_assets] if parsed_assets else [],
1814                transitive = transitive_assets_symbols + exports_transitive_assets_symbols,
1815                order = "preorder",
1816            ),
1817            transitive_compiled_assets = depset(
1818                [compiled_assets] if compiled_assets else [],
1819                transitive = transitive_compiled_assets + exports_transitive_compiled_assets,
1820                order = "preorder",
1821            ),
1822            transitive_resource_files = depset(
1823                processed_resources,
1824                transitive = transitive_resources_files + exports_transitive_resources_files,
1825                order = "preorder",
1826            ),
1827            direct_compiled_resources = depset(
1828                [compiled_resources] if compiled_resources else [],
1829                transitive = direct_compiled_resources + exports_direct_compiled_resources,
1830                order = "preorder",
1831            ),
1832            transitive_compiled_resources = depset(
1833                [compiled_resources] if compiled_resources else [],
1834                transitive = transitive_compiled_resources + exports_transitive_compiled_resources,
1835                order = "preorder",
1836            ),
1837            transitive_manifests = depset(
1838                [processed_manifest] if processed_manifest else [],
1839                transitive = transitive_manifests + exports_transitive_manifests,
1840                order = "preorder",
1841            ),
1842            transitive_r_txts = depset(
1843                [out_aapt2_r_txt] if out_aapt2_r_txt else [],
1844                transitive = transitive_r_txts + exports_transitive_r_txts,
1845                order = "preorder",
1846            ),
1847            packages_to_r_txts = packages_to_r_txts,
1848            transitive_resource_apks = depset(
1849                resource_apks,
1850                transitive = transitive_resource_apks,
1851                order = "preorder",
1852            ),
1853        ))
1854
1855    if not propagate_resources:
1856        resources_ctx[_R_JAVA] = None
1857        resources_ctx[_PROVIDERS] = []
1858
1859    # TODO(b/69552500): In the Starlark Android Rules, the R compile time
1860    # JavaInfo is added as a runtime dependency to the JavaInfo. Stop
1861    # adding the R.jar as a runtime dependency.
1862    resources_ctx[_PROVIDERS].append(
1863        AndroidLibraryResourceClassJarProvider(
1864            depset(
1865                (resources_ctx[_R_JAVA].runtime_output_jars if resources_ctx[_R_JAVA] else []),
1866                transitive = [
1867                    p.jars
1868                    for p in utils.collect_providers(
1869                        AndroidLibraryResourceClassJarProvider,
1870                        deps,
1871                        exports,
1872                    )
1873                ],
1874                order = "preorder",
1875            ),
1876        ),
1877    )
1878
1879    return resources_ctx
1880
1881def _process(
1882        ctx,
1883        manifest = None,
1884        resource_files = None,
1885        defined_assets = False,
1886        assets = None,
1887        defined_assets_dir = False,
1888        assets_dir = None,
1889        exports_manifest = False,
1890        java_package = None,
1891        custom_package = None,
1892        neverlink = False,
1893        enable_data_binding = False,
1894        deps = [],
1895        resource_apks = [],
1896        exports = [],
1897        android_jar = None,
1898        android_kit = None,
1899        aapt = None,
1900        busybox = None,
1901        xsltproc = None,
1902        instrument_xslt = None,
1903        java_toolchain = None,
1904        host_javabase = None,
1905        enable_res_v3 = False,
1906        res_v3_dummy_manifest = None,
1907        res_v3_dummy_r_txt = None,
1908        fix_resource_transitivity = False,
1909        fix_export_exporting = False,
1910        propagate_resources = True,
1911        zip_tool = None):
1912    out_ctx = _process_starlark(
1913        ctx,
1914        java_package = java_package,
1915        manifest = manifest,
1916        defined_assets = defined_assets,
1917        # TODO(b/159937795): When the Starlark Resources Processing pipeline is
1918        # default and the native version is no longer used, remove the depset
1919        # creation and directly pass through ctx.files.assets to this method.
1920        assets =
1921            depset(transitive = [target.files for target in assets]).to_list(),
1922        defined_assets_dir = defined_assets_dir,
1923        assets_dir = assets_dir,
1924        exports_manifest = exports_manifest,
1925        stamp_manifest = True if java_package else False,
1926        deps = deps,
1927        resource_apks = resource_apks,
1928        exports = exports,
1929        resource_files = depset(transitive = [target.files for target in resource_files]).to_list(),
1930        enable_data_binding = enable_data_binding,
1931        fix_resource_transitivity = fix_resource_transitivity,
1932        neverlink = neverlink,
1933        propagate_resources = propagate_resources,
1934        android_jar = android_jar,
1935        aapt = aapt,
1936        android_kit = android_kit,
1937        busybox = busybox,
1938        instrument_xslt = instrument_xslt,
1939        xsltproc = xsltproc,
1940        java_toolchain = java_toolchain,
1941        host_javabase = host_javabase,
1942        zip_tool = zip_tool,
1943    )
1944
1945    if _VALIDATION_OUTPUTS not in out_ctx:
1946        out_ctx[_VALIDATION_OUTPUTS] = []
1947
1948    return _ResourcesProcessContextInfo(**out_ctx)
1949
1950def _shrink(
1951        ctx,
1952        resources_zip = None,
1953        aapt = None,
1954        android_jar = None,
1955        r_txt = None,
1956        shrunk_jar = None,
1957        proguard_mapping = None,
1958        busybox = None,
1959        host_javabase = None):
1960    """Shrinks the resources apk.
1961
1962    Args:
1963        ctx: The context.
1964        resources_zip: File. The input resources file zip containing the merged assets and resources to be shrunk.
1965        aapt: FilesToRunProvider. The AAPT executable.
1966        android_jar: File. The Android Jar.
1967        r_txt: File. The resource IDs outputted by linking resources in text.
1968        shrunk_jar: File. The proguarded output jar.
1969        proguard_mapping: File. The Proguard Mapping file.
1970        busybox: FilesToRunProvider. The ResourceBusyBox executable.
1971        host_javabase: Target. The host javabase.
1972
1973    Returns:
1974        A dict contaning all of the shrunk resource outputs.
1975    """
1976    shrunk_ctx = {
1977        _SHRUNK_RESOURCE_APK: None,
1978        _SHRUNK_RESOURCE_ZIP: None,
1979        _RESOURCE_SHRINKER_LOG: None,
1980        _RESOURCE_OPTIMIZATION_CONFIG: None,
1981    }
1982
1983    out_apk = ctx.actions.declare_file(ctx.label.name + "_shrunk.ap_")
1984    out_zip = ctx.actions.declare_file(ctx.label.name + "_files/resource_files_shrunk.zip")
1985    out_log = ctx.actions.declare_file(ctx.label.name + "_files/resource_shrinker.log")
1986    out_config = ctx.actions.declare_file(ctx.label.name + "_files/resource_optimization.cfg")
1987    _busybox.shrink(
1988        ctx,
1989        out_apk,
1990        out_zip,
1991        out_log,
1992        out_config,
1993        resources_zip = resources_zip,
1994        aapt = aapt,
1995        android_jar = android_jar,
1996        r_txt = r_txt,
1997        shrunk_jar = shrunk_jar,
1998        proguard_mapping = proguard_mapping,
1999        debug = _compilation_mode.get(ctx) != _compilation_mode.OPT,
2000        busybox = busybox,
2001        host_javabase = host_javabase,
2002    )
2003
2004    shrunk_ctx[_SHRUNK_RESOURCE_APK] = out_apk
2005    shrunk_ctx[_SHRUNK_RESOURCE_ZIP] = out_zip
2006    shrunk_ctx[_RESOURCE_SHRINKER_LOG] = out_log
2007    shrunk_ctx[_RESOURCE_OPTIMIZATION_CONFIG] = out_config
2008
2009    return _ResourcesShrinkContextInfo(**shrunk_ctx)
2010
2011def _optimize(
2012        ctx,
2013        resources_apk = None,
2014        resource_optimization_config = None,
2015        is_resource_shrunk = False,
2016        aapt = None,
2017        busybox = None,
2018        host_javabase = None):
2019    """Optimizes the resources apk if necessary.
2020
2021    Args:
2022        ctx: The context.
2023        resources_apk: File. The resources apk.
2024        resource_optimization_config: File. The resource optimization config outputted
2025          by resource shrinking. It will only be used if resource name obfuscation is enabled.
2026        is_resource_shrunk: Boolean. Whether the resources has been shrunk or not.
2027        aapt: FilesToRunProvider. The AAPT executable.
2028        busybox: FilesToRunProvider. The ResourceBusyBox executable.
2029        host_javabase: Target. The host javabase.
2030
2031    Returns:
2032        A dict contaning all of the optimized resource outputs.
2033    """
2034    optimize_ctx = {
2035        _OPTIMIZED_RESOURCE_APK: None,
2036        _RESOURCE_PATH_SHORTENING_MAP: None,
2037    }
2038
2039    use_resource_path_shortening_map = _is_resource_path_shortening_enabled(ctx)
2040    use_resource_optimization_config = _is_resource_name_obfuscation_enabled(ctx, is_resource_shrunk)
2041
2042    if not (use_resource_path_shortening_map or use_resource_optimization_config):
2043        return _ResourcesOptimizeContextInfo(**optimize_ctx)
2044
2045    optimized_resource_apk = ctx.actions.declare_file(ctx.label.name + "optimized.ap_")
2046    optimize_ctx[_OPTIMIZED_RESOURCE_APK] = optimized_resource_apk
2047
2048    resource_path_shortening_map = None
2049    if use_resource_path_shortening_map:
2050        resource_path_shortening_map = ctx.actions.declare_file(ctx.label.name + "_resource_paths.map")
2051        optimize_ctx[_RESOURCE_PATH_SHORTENING_MAP] = resource_path_shortening_map
2052
2053    _busybox.optimize(
2054        ctx,
2055        out_apk = optimized_resource_apk,
2056        in_apk = resources_apk,
2057        resource_path_shortening_map = optimize_ctx[_RESOURCE_PATH_SHORTENING_MAP],
2058        resource_optimization_config = resource_optimization_config if use_resource_optimization_config else None,
2059        aapt = aapt,
2060        busybox = busybox,
2061        host_javabase = host_javabase,
2062    )
2063
2064    return _ResourcesOptimizeContextInfo(**optimize_ctx)
2065
2066def _is_resource_path_shortening_enabled(ctx):
2067    return ctx.fragments.android.use_android_resource_path_shortening and \
2068           _compilation_mode.get(ctx) == _compilation_mode.OPT and \
2069           not acls.in_android_binary_raw_access_to_resource_paths_allowlist(str(ctx.label))
2070
2071def _is_resource_name_obfuscation_enabled(ctx, is_resource_shrunk):
2072    return (ctx.fragments.android.use_android_resource_name_obfuscation or
2073            _FEATURE_RESOURCE_NAME_OBFUSCATION in ctx.features) and \
2074           is_resource_shrunk and \
2075           not acls.in_android_binary_raw_access_to_resource_paths_allowlist(str(ctx.label))
2076
2077resources = struct(
2078    process = _process,
2079    process_starlark = _process_starlark,
2080    package = _package,
2081    make_aar = _make_aar,
2082
2083    # Exposed for mobile-install
2084    compile = _compile,
2085    legacy_merge_manifests = _legacy_merge_manifests,
2086
2087    # Exposed for android_local_test and android_library
2088    generate_dummy_manifest = _generate_dummy_manifest,
2089
2090    # Exposed for android_library, aar_import, android_local_test and android_binary
2091    bump_min_sdk = _bump_min_sdk,
2092    process_manifest_values = _process_manifest_values,
2093
2094    # Exposed for use in AOSP
2095    set_default_min_sdk = _set_default_min_sdk,
2096    # TODO: b/301258446 - AOSP-only change, should upstream some equivalent.
2097    ManifestContextInfo = _ManifestContextInfo,
2098
2099    # Exposed for android_binary
2100    is_resource_shrinking_enabled = _is_resource_shrinking_enabled,
2101    validate_min_sdk = _validate_min_sdk,
2102    shrink = _shrink,
2103    optimize = _optimize,
2104)
2105
2106testing = struct(
2107    add_g3itr = _add_g3itr,
2108    filter_multi_cpu_configuration_targets = _filter_multi_cpu_configuration_targets,
2109    get_legacy_mergee_manifests = _get_legacy_mergee_manifests,
2110    make_databinding_outputs = _make_databinding_outputs,
2111    ResourcesPackageContextInfo = _ResourcesPackageContextInfo,
2112    ResourcesProcessContextInfo = _ResourcesProcessContextInfo,
2113    ResourcesShrinkContextInfo = _ResourcesShrinkContextInfo,
2114    ResourcesOptimizeContextInfo = _ResourcesOptimizeContextInfo,
2115)
2116