• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(":attrs.bzl", _attrs = "attrs")
18load(":busybox.bzl", _busybox = "busybox")
19load(":common.bzl", _common = "common")
20load(":java.bzl", _java = "java")
21load(":path.bzl", _path = "path")
22load(
23    ":providers.bzl",
24    "ResourcesNodeInfo",
25    "StarlarkAndroidResourcesInfo",
26)
27load(
28    ":utils.bzl",
29    "utils",
30    _compilation_mode = "compilation_mode",
31    _log = "log",
32)
33
34_RESOURCE_FOLDER_TYPES = [
35    "anim",
36    "animator",
37    "color",
38    "drawable",
39    "font",
40    "interpolator",
41    "layout",
42    "menu",
43    "mipmap",
44    "navigation",
45    "values",
46    "xml",
47    "raw",
48    "transition",
49]
50
51_RESOURCE_QUALIFIER_SEP = "-"
52
53_MANIFEST_MISSING_ERROR = (
54    "In target %s, manifest attribute is required when resource_files or " +
55    "assets are defined."
56)
57
58_ASSET_DEFINITION_ERROR = (
59    "In target %s, the assets and assets_dir attributes should be either " +
60    "both empty or non-empty."
61)
62
63_JAVA_PACKAGE_MISSING_ERROR = (
64    "In target %s, a java package is required when stamping " +
65    "the manifest."
66)
67
68_INCORRECT_RESOURCE_LAYOUT_ERROR = (
69    "'%s' is not in the expected resource directory structure of " +
70    "<resource directory>/{%s}/<file>" % (",").join(_RESOURCE_FOLDER_TYPES)
71)
72
73# Keys for manifest_values
74_VERSION_NAME = "versionName"
75_VERSION_CODE = "versionCode"
76
77# Resources context attributes.
78_ASSETS_PROVIDER = "assets_provider"
79_DEFINES_RESOURCES = "defines_resources"
80_DIRECT_ANDROID_RESOURCES = "direct_android_resources"
81_MERGED_MANIFEST = "merged_manifest"
82_PROVIDERS = "providers"
83_R_JAVA = "r_java"
84_RESOURCES_APK = "resources_apk"
85_VALIDATION_RESULTS = "validation_results"
86_VALIDATION_OUTPUTS = "validation_outputs"
87_RESOURCES_PROVIDER = "resources_provider"
88_STARLARK_PROCESSED_MANIFEST = "starlark_processed_manifest"
89_STARLARK_R_TXT = "starlark_r_txt"
90_STARLARK_PROCESSED_RESOURCES = "starlark_processed_resources"
91
92_ResourcesProcessContextInfo = provider(
93    "Resources context object",
94    fields = {
95        _DEFINES_RESOURCES: "If local resources were defined.",
96        _DIRECT_ANDROID_RESOURCES: "Direct android resources.",
97        _MERGED_MANIFEST: "Merged manifest.",
98        _PROVIDERS: "The list of all providers to propagate.",
99        _R_JAVA: "JavaInfo for R.jar.",
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
120_ResourcesPackageContextInfo = provider(
121    "Packaged resources context object",
122    fields = {
123        _PACKAGED_FINAL_MANIFEST: "Final processed manifest.",
124        _PACKAGED_RESOURCE_APK: "ResourceApk.",
125        _PACKAGED_CLASS_JAR: "R class jar.",
126        _PACKAGED_VALIDATION_RESULT: "Validation result.",
127        _R_JAVA: "JavaInfo for R.jar",
128        _PROVIDERS: "The list of all providers to propagate.",
129    },
130)
131
132def _generate_dummy_manifest(
133        ctx,
134        out_manifest = None,
135        java_package = None,
136        min_sdk_version = None):
137    content = """<?xml version="1.0" encoding="utf-8"?>
138<manifest xmlns:android="http://schemas.android.com/apk/res/android"
139    package="%s">""" % java_package
140
141    if min_sdk_version:
142        content = content + """
143    <uses-sdk android:minSdkVersion="%s" />""" % min_sdk_version
144
145    content = content + """
146    <application>
147    </application>
148</manifest>"""
149
150    ctx.actions.write(
151        output = out_manifest,
152        content = content,
153    )
154
155def _add_g3itr(
156        ctx,
157        manifest = None,
158        out_manifest = None,
159        xsltproc = None,
160        instrument_xslt = None):
161    """Adds Google3InstrumentationTestRunner instrumentation element to the manifest.
162
163    Element is only added if the manifest contains an instrumentation element with
164    name "android.test.InstrumentationTestRunner". The added element's name attr is
165    "com.google.android.apps.common.testing.testrunner.Google3InstrumentationTestRunner".
166
167    Args:
168      ctx: The context.
169      manifest: File. The AndroidManifest.xml file.
170      out_manifest: File. The transformed AndroidManifest.xml.
171      xsltproc: FilesToRunProvider. The xsltproc executable or
172        FilesToRunProvider.
173      instrument_xslt: File. The add_g3itr.xslt file describing the xslt
174        transformation to apply.
175    """
176    args = ctx.actions.args()
177    args.add("--nonet")
178    args.add("--novalid")
179    args.add("-o", out_manifest)
180    args.add(instrument_xslt)
181    args.add(manifest)
182
183    ctx.actions.run(
184        executable = xsltproc,
185        arguments = [args],
186        inputs = [manifest, instrument_xslt],
187        outputs = [out_manifest],
188        mnemonic = "AddG3ITRStarlark",
189        progress_message = "Adding G3ITR to test manifest for %s" % ctx.label,
190    )
191
192def _get_legacy_mergee_manifests(resources_infos):
193    all_dependencies = depset(
194        transitive = [
195            ri.direct_android_resources
196            for ri in resources_infos
197        ] + [
198            ri.transitive_android_resources
199            for ri in resources_infos
200        ],
201    )
202
203    mergee_manifests = []
204    for dep in all_dependencies.to_list():
205        if dep.to_provider.manifest.exports_manifest:
206            mergee_manifests.append(dep.to_provider.manifest.manifest)
207
208    return depset(mergee_manifests)
209
210def _legacy_mergee_manifest(manifest):
211    sort_key = manifest.short_path + "#"
212    return sort_key + "--mergee=" + manifest.path
213
214def _legacy_merge_manifests(
215        ctx,
216        out_merged_manifest = None,
217        manifest = None,
218        mergee_manifests = None,
219        legacy_merger = None):
220    """Merges manifests with the legacy manifest merger."
221
222    This should not be called with empty mergee_manifests.
223
224    Args:
225      ctx: The context.
226      out_merged_manifest: File. The merged AndroidManifest.xml.
227      manifest: File. The AndroidManifest.xml.
228      mergee_manifests: A sequence of Files. All transitive manifests to be merged.
229      legacy_merger: A FilesToRunProvider. The legacy manifest merger executable.
230    """
231    args = ctx.actions.args()
232    args.use_param_file("%s", use_always = True)
233    args.set_param_file_format("multiline")
234    args.add("--merger=%s" % manifest.path)
235    args.add("--exclude_permission=all")
236    args.add("--output=%s" % out_merged_manifest.path)
237
238    manifest_params = ctx.actions.declare_file(ctx.label.name + "/legacy_merger.params")
239    manifest_args = ctx.actions.args()
240    manifest_args.use_param_file("%s", use_always = True)
241    manifest_args.set_param_file_format("multiline")
242    manifest_args.add_joined(mergee_manifests, map_each = _legacy_mergee_manifest, join_with = "\n")
243    ctx.actions.run_shell(
244        command = """
245# Sorts the mergee manifests by path and combines with other busybox args.
246set -e
247SORTED=`sort $1 | sed 's/^.*#//'`
248cat $2 > $3
249echo "$SORTED" >> $3
250""",
251        arguments = [manifest_args, args, manifest_params.path],
252        outputs = [manifest_params],
253    )
254    args = ctx.actions.args()
255    args.add(manifest_params, format = "--flagfile=%s")
256
257    ctx.actions.run(
258        executable = legacy_merger,
259        arguments = [args],
260        inputs = depset([manifest, manifest_params], transitive = [mergee_manifests]),
261        outputs = [out_merged_manifest],
262        mnemonic = "StarlarkLegacyAndroidManifestMerger",
263        progress_message = "Merging Android Manifests",
264    )
265
266def _make_databinding_outputs(
267        ctx,
268        resource_files):
269    """Helper method to create arguments for the process_databinding busybox tool.
270
271    Declares databinding-processed resource files that are generated by the
272    PROCESS_DATABINDING busybox tool, which must be declared underneath an output
273    resources directory and namespaced by their paths. The busybox takes the
274    output directory exec path and generates the underlying resource files.
275
276    Args:
277      ctx: The context.
278      resource_files: List of Files. The android resource files to be processed by
279        _process_databinding.
280
281    Returns:
282      A tuple containing the list of declared databinding processed resource files and the
283        output resource directory path expected by the busybox. The path is a full path.
284    """
285
286    # TODO(b/160907203): Clean up databinding_rel_path. We capitalize "Databinding" here to avoid
287    # conflicting with native artifact file names. This is changed back to "databinding" during
288    # process_starlark so that compiled resources exactly match those of the native resource
289    # processing pipeline. Even a single character mismatch in the file names causes selected
290    # resources to differ in the final APK.
291    databinding_rel_path = _path.join(["Databinding-processed-resources", ctx.label.name])
292    databinding_processed_resources = [
293        ctx.actions.declare_file(_path.join([databinding_rel_path, f.path]))
294        for f in resource_files
295    ]
296    databinding_resources_dirname = _path.join([
297        ctx.bin_dir.path,
298        ctx.label.package,
299        databinding_rel_path,
300    ])
301    return databinding_processed_resources, databinding_resources_dirname
302
303def _fix_databinding_compiled_resources(
304        ctx,
305        out_compiled_resources = None,
306        compiled_resources = None,
307        zip_tool = None):
308    """Fix compiled resources to match those produced by the native pipeline.
309
310    Changes "Databinding" to "databinding" in each compiled resource .flat file name and header.
311
312    Args:
313      ctx: The context.
314      out_compiled_resources: File. The modified compiled_resources output.
315      compiled_resources: File. The compiled_resources zip.
316    """
317    ctx.actions.run_shell(
318        outputs = [out_compiled_resources],
319        inputs = [compiled_resources],
320        tools = [zip_tool],
321        arguments = [compiled_resources.path, out_compiled_resources.path, zip_tool.executable.path],
322        command = """#!/bin/bash
323set -e
324
325IN_DIR=$(mktemp -d)
326OUT_DIR=$(mktemp -d)
327CUR_PWD=$(pwd)
328
329if zipinfo -t "$1"; then
330    ORDERED_LIST=`(unzip -l "$1" | sed -e '1,3d' | head -n -2 | tr -s " " | cut -d " " -f5)`
331
332    unzip -q "$1" -d "$IN_DIR"
333
334    # Iterate through the ordered list, change "Databinding" to "databinding" in the file header
335    # and file name and zip the files with the right comment
336    for FILE in $ORDERED_LIST; do
337        cd "$IN_DIR"
338        if [ -f "$FILE" ]; then
339            sed -i 's/Databinding\\-processed\\-resources/databinding\\-processed\\-resources/g' "$FILE"
340            NEW_NAME=`echo "$FILE" | sed 's/Databinding\\-processed\\-resources/databinding\\-processed\\-resources/g' | sed 's#'"$IN_DIR"'/##g'`
341            mkdir -p `dirname "$OUT_DIR/$NEW_NAME"` && touch "$OUT_DIR/$NEW_NAME"
342            cp -p "$FILE" "$OUT_DIR/$NEW_NAME"
343
344            PATH_SEGMENTS=(`echo ${FILE} | tr '/' ' '`)
345            BASE_PATH_SEGMENT="${PATH_SEGMENTS[0]}"
346                COMMENT=
347            if [ "${BASE_PATH_SEGMENT}" == "generated" ]; then
348                COMMENT="generated"
349            elif [ "${BASE_PATH_SEGMENT}" == "default" ]; then
350                COMMENT="default"
351            fi
352
353            cd "$OUT_DIR"
354            "$CUR_PWD/$3" -jt -X -0 -q -r -c "$CUR_PWD/$2" $NEW_NAME <<EOM
355${COMMENT}
356EOM
357        fi
358    done
359
360    cd "$CUR_PWD"
361    touch -r "$1" "$2"
362else
363    cp -p "$1" "$2"
364fi
365        """,
366    )
367
368def _is_resource_shrinking_enabled(
369        shrink_resources,
370        use_android_resource_shrinking):
371    if shrink_resources == _attrs.tristate.auto:
372        return use_android_resource_shrinking
373    return shrink_resources == _attrs.tristate.yes
374
375def _should_shrink_resource_cycles(
376        use_android_resource_cycle_shrinking,
377        resource_shrinking_enabled):
378    if use_android_resource_cycle_shrinking and not resource_shrinking_enabled:
379        fail("resource cycle shrinking can only be enabled when resource shrinking is enabled")
380    return use_android_resource_cycle_shrinking
381
382def _filter_multi_cpu_configuration_targets(
383        targets):
384    """Filter out duplicate split-configured targets.
385
386    This method simulates logic in the native rule where if a label_list attribute has
387    split-configuration but is requested in target mode, only targets from the first architecture
388    are returned. Without this filtering there are duplicate targets if multiple CPU configurations
389    are specified on the command line. This is the case with deps in the packaging step of
390    android_binary.
391
392    Args:
393      targets: A list of Target objects.
394
395    Returns:
396      A list of Target objects with duplicates removed.
397    """
398    seen_labels = {}
399    filtered_targets = []
400    for t in targets:
401        if t.label in seen_labels:
402            continue
403        seen_labels[t.label] = True
404        filtered_targets.append(t)
405    return filtered_targets
406
407def _package(
408        ctx,
409        assets = [],
410        assets_dir = None,
411        deps = [],
412        manifest = None,
413        manifest_values = None,
414        instruments = None,
415        resource_configs = None,
416        densities = [],
417        resource_files = [],
418        nocompress_extensions = [],
419        java_package = None,
420        compilation_mode = _compilation_mode.FASTBUILD,
421        shrink_resources = None,
422        use_android_resource_shrinking = None,
423        use_android_resource_cycle_shrinking = None,
424        use_legacy_manifest_merger = False,
425        should_throw_on_conflict = True,
426        enable_data_binding = False,
427        enable_manifest_merging = True,
428        aapt = None,
429        android_jar = None,
430        legacy_merger = None,
431        xsltproc = None,
432        instrument_xslt = None,
433        busybox = None,
434        host_javabase = None):
435    """Package resources for top-level rules.
436
437    Args:
438      ctx: The context.
439      assets: sequence of Files. A list of assets to be packaged. All files be
440        under the assets_dir directory in the corresponding package.
441      assets_dir: String. A string giving the path to the files in assets. The
442        pair assets and assets_dir describe packaged assets and either both
443        parameters should be provided or none of them.
444      deps: sequence of Targets. The list of other libraries targets to link
445        against.
446      manifest: File. The input top-level AndroidManifest.xml.
447      manifest_values: String dictionary. Manifest values to substitute.
448      instruments: Optional target. The value of the "instruments" attr if set.
449      resource_configs: sequence of Strings. A list of resource_configuration_filters
450        to apply.
451      densities: sequence of Strings. A list of densities to filter for when building
452        the apk.
453      resource_files: sequence of Files. A list of Android resource files
454        to be processed.
455      nocompress_extensions: sequence of Strings. File extension to leave uncompressed
456        in the apk.
457      java_package: String. Java package for which java sources will be
458        generated. By default the package is inferred from the directory where
459        the BUILD file containing the rule is.
460      compilation_mode: String. A string that represents compilation mode. The
461        list of expected values are as follows: dbg, fastbuild, opt.
462      shrink_resources: Tristate. Whether resource shrinking is enabled by the rule.
463      use_android_resource_shrinking: Bool. Flag that controls the default value for
464        shrink_resources if the tristate value is auto (-1).
465      use_android_resource_cycle_shrinking: Bool. Flag that enables more shrinking of
466        code and resources by instructing AAPT2 to emit conditional Proguard keep rules.
467      use_legacy_manifest_merger: A boolean. Whether to use the legacy manifest merger
468      instead of the android manifest merger.
469      should_throw_on_conflict: A boolean. Determines whether an error should be thrown
470        when a resource conflict occurs.
471      enable_data_binding: boolean. If true, processesing the data binding
472        expressions in layout resources included through the resource_files
473        parameter is enabled. Without this setting, data binding expressions
474        produce build failures.
475      enable_manifest_merging: boolean. If true, manifest merging will be performed.
476      aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
477      android_jar: File. The Android jar.
478      legacy_merger: FilesToRunProvider. The legacy manifest merger executable.
479      xsltproc: FilesToRunProvider. The xsltproc executable or
480        FilesToRunProvider.
481      instrument_xslt: File. The add_g3itr.xslt file describing the xslt
482        transformation to apply.
483      busybox: FilesToRunProvider. The ResourceBusyBox executable or
484        FilesToRunprovider
485      host_javabase: A Target. The host javabase.
486
487    Returns:
488      A ResourcesPackageContextInfo containing packaged resource artifacts and
489        providers.
490    """
491    _validate_resources(resource_files)
492
493    # Filtering is necessary if a build is requested with multiple CPU configurations.
494    deps = _filter_multi_cpu_configuration_targets(deps)
495
496    packaged_resources_ctx = {
497        _PROVIDERS: [],
498    }
499
500    g3itr_manifest = manifest
501
502    if xsltproc or instrument_xslt:
503        g3itr_manifest = ctx.actions.declare_file(
504            "_migrated/" + ctx.label.name + "add_g3itr/AndroidManifest.xml",
505        )
506        _add_g3itr(
507            ctx,
508            out_manifest = g3itr_manifest,
509            manifest = manifest,
510            xsltproc = xsltproc,
511            instrument_xslt = instrument_xslt,
512        )
513
514    direct_resources_nodes = []
515    transitive_resources_nodes = []
516    transitive_assets = []
517    transitive_assets_symbols = []
518    transitive_compiled_assets = []
519    transitive_resource_files = []
520    transitive_compiled_resources = []
521    transitive_manifests = []
522    transitive_r_txts = []
523    for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, deps):
524        direct_resources_nodes.append(dep.direct_resources_nodes)
525        transitive_resources_nodes.append(dep.transitive_resources_nodes)
526        transitive_assets.append(dep.transitive_assets)
527        transitive_assets_symbols.append(dep.transitive_assets_symbols)
528        transitive_compiled_assets.append(dep.transitive_compiled_assets)
529        transitive_resource_files.append(dep.transitive_resource_files)
530        transitive_compiled_resources.append(dep.transitive_compiled_resources)
531        transitive_manifests.append(dep.transitive_manifests)
532        transitive_r_txts.append(dep.transitive_r_txts)
533
534    mergee_manifests = depset([
535        node_info.manifest
536        for node_info in depset(transitive = transitive_resources_nodes + direct_resources_nodes).to_list()
537        if node_info.exports_manifest
538    ])
539
540    # TODO(b/156763506): Add analysis tests to verify logic around when manifest merging is configured.
541    # TODO(b/154153771): Run the android merger if mergee_manifests or manifest values are present.
542    merged_manifest = g3itr_manifest
543    if enable_manifest_merging and (manifest_values or mergee_manifests):
544        if use_legacy_manifest_merger:
545            # Legacy manifest merger only runs if mergee manifests are present
546            if mergee_manifests:
547                merged_manifest = ctx.actions.declare_file(
548                    "_migrated/_merged/" + ctx.label.name + "/AndroidManifest.xml",
549                )
550                _legacy_merge_manifests(
551                    ctx,
552                    out_merged_manifest = merged_manifest,
553                    manifest = g3itr_manifest,
554                    mergee_manifests = mergee_manifests,
555                    legacy_merger = legacy_merger,
556                )
557        else:
558            merged_manifest = ctx.actions.declare_file(
559                "_migrated/_merged/" + ctx.label.name + "/AndroidManifest.xml",
560            )
561            _busybox.merge_manifests(
562                ctx,
563                out_file = merged_manifest,
564                out_log_file = ctx.actions.declare_file(
565                    "_migrated/_merged/" + ctx.label.name + "/manifest_merger_log.txt",
566                ),
567                manifest = g3itr_manifest,
568                mergee_manifests = mergee_manifests,
569                manifest_values = manifest_values,
570                merge_type = "APPLICATION",
571                java_package = java_package,
572                busybox = busybox,
573                host_javabase = host_javabase,
574            )
575
576    processed_resources = resource_files
577    databinding_info = None
578    if enable_data_binding:
579        databinding_info = ctx.actions.declare_file("_migrated/databinding/" + ctx.label.name + "/layout-info.zip")
580        processed_resources, resources_dirname = _make_databinding_outputs(
581            ctx,
582            resource_files,
583        )
584        _busybox.process_databinding(
585            ctx,
586            out_databinding_info = databinding_info,
587            out_databinding_processed_resources = processed_resources,
588            databinding_resources_dirname = resources_dirname,
589            resource_files = resource_files,
590            java_package = java_package,
591            busybox = busybox,
592            host_javabase = host_javabase,
593        )
594
595    resource_apk = ctx.actions.declare_file(ctx.label.name + "_migrated/.ap_")
596    r_java = ctx.actions.declare_file("_migrated/" + ctx.label.name + ".srcjar")
597    r_txt = ctx.actions.declare_file(ctx.label.name + "_migrated/_symbols/R.txt")
598    processed_manifest = ctx.actions.declare_file(ctx.label.name + "_migrated/_processed_manifest/AndroidManifest.xml")
599    proguard_cfg = ctx.actions.declare_file(
600        "_migrated/proguard/%s/_%s_proguard.cfg" % (ctx.label.name, ctx.label.name),
601    )
602    main_dex_proguard_cfg = ctx.actions.declare_file(
603        "_migrated/proguard/%s/main_dex_%s_proguard.cfg" %
604        (ctx.label.name, ctx.label.name),
605    )
606    resource_files_zip = ctx.actions.declare_file(
607        "_migrated/" + ctx.label.name + "_files/resource_files.zip",
608    )
609    _busybox.package(
610        ctx,
611        out_file = resource_apk,
612        out_r_src_jar = r_java,
613        out_r_txt = r_txt,
614        out_symbols = ctx.actions.declare_file("_migrated/" + ctx.label.name + "_symbols/merged.bin"),
615        out_manifest = processed_manifest,
616        out_proguard_cfg = proguard_cfg,
617        out_main_dex_proguard_cfg = main_dex_proguard_cfg,
618        out_resource_files_zip = resource_files_zip,
619        application_id = manifest_values.get("applicationId", None),
620        manifest = merged_manifest,
621        assets = assets,
622        assets_dir = assets_dir,
623        resource_files = processed_resources,
624        direct_resources_nodes =
625            depset(transitive = direct_resources_nodes, order = "preorder"),
626        transitive_resources_nodes =
627            depset(transitive = transitive_resources_nodes, order = "preorder"),
628        transitive_assets = transitive_assets,
629        transitive_compiled_assets = transitive_compiled_assets,
630        transitive_resource_files = transitive_resource_files,
631        transitive_compiled_resources = transitive_compiled_resources,
632        transitive_manifests = transitive_manifests,
633        transitive_r_txts = transitive_r_txts,
634        resource_configs = resource_configs,
635        densities = densities,
636        nocompress_extensions = nocompress_extensions,
637        java_package = java_package,
638        version_name = manifest_values[_VERSION_NAME] if _VERSION_NAME in manifest_values else None,
639        version_code = manifest_values[_VERSION_CODE] if _VERSION_CODE in manifest_values else None,
640        android_jar = android_jar,
641        aapt = aapt,
642        busybox = busybox,
643        host_javabase = host_javabase,
644        debug = compilation_mode != _compilation_mode.OPT,
645        should_throw_on_conflict = should_throw_on_conflict,
646    )
647    packaged_resources_ctx[_PACKAGED_FINAL_MANIFEST] = processed_manifest
648    packaged_resources_ctx[_PACKAGED_RESOURCE_APK] = resource_apk
649    packaged_resources_ctx[_PACKAGED_VALIDATION_RESULT] = resource_files_zip
650
651    resource_shrinking_enabled = _is_resource_shrinking_enabled(
652        shrink_resources,
653        use_android_resource_shrinking,
654    )
655    shrink_resource_cycles = _should_shrink_resource_cycles(
656        use_android_resource_cycle_shrinking,
657        resource_shrinking_enabled,
658    )
659
660    # Fix class jar name because some tests depend on {label_name}_resources.jar being the suffix of
661    # the path, with _RESOURCES_DO_NOT_USE removed from the label name.
662    _RESOURCES_SUFFIX = "_RESOURCES_DO_NOT_USE"
663    class_jar_name = ctx.label.name + "_migrated/_resources.jar"
664    if ctx.label.name.endswith(_RESOURCES_SUFFIX):
665        label_name = ctx.label.name[:-len(_RESOURCES_SUFFIX)]
666        class_jar_name = ctx.label.name + "_migrated/" + label_name + "_resources.jar"
667
668    class_jar = ctx.actions.declare_file(class_jar_name)
669    _busybox.generate_binary_r(
670        ctx,
671        out_class_jar = class_jar,
672        r_txt = r_txt,
673        manifest = processed_manifest,
674        package_for_r = java_package,
675        final_fields = not shrink_resource_cycles and not instruments,
676        resources_nodes = depset(transitive = direct_resources_nodes + transitive_resources_nodes),
677        transitive_r_txts = transitive_r_txts,
678        transitive_manifests = transitive_manifests,
679        busybox = busybox,
680        host_javabase = host_javabase,
681    )
682    packaged_resources_ctx[_PACKAGED_CLASS_JAR] = class_jar
683
684    java_info = JavaInfo(
685        output_jar = class_jar,
686        compile_jar = class_jar,
687        source_jar = r_java,
688    )
689
690    packaged_resources_ctx[_R_JAVA] = java_info
691
692    packaged_resources_ctx[_PROVIDERS].append(AndroidApplicationResourceInfo(
693        resource_apk = resource_apk,
694        resource_java_src_jar = r_java,
695        resource_java_class_jar = class_jar,
696        manifest = processed_manifest,
697        resource_proguard_config = proguard_cfg,
698        main_dex_proguard_config = main_dex_proguard_cfg,
699        r_txt = r_txt,
700        resources_zip = resource_files_zip,
701        databinding_info = databinding_info,
702    ))
703    return _ResourcesPackageContextInfo(**packaged_resources_ctx)
704
705def _liteparse(ctx, out_r_pb, resource_files, android_kit):
706    """Creates an R.pb which contains the resource ids gotten from a light parse.
707
708    Args:
709      ctx: The context.
710      out_r_pb: File. The R.pb output file.
711      resource_files: List of Files. The list of resource files.
712      android_kit: FilesToRunProvider. The Android Kit executable or
713        FilesToRunProvider.
714    """
715    args = ctx.actions.args()
716    args.use_param_file(param_file_arg = "--flagfile=%s", use_always = True)
717    args.set_param_file_format("multiline")
718    args.add_joined("--res_files", resource_files, join_with = ",")
719    args.add("--out", out_r_pb)
720
721    ctx.actions.run(
722        executable = android_kit,
723        arguments = ["liteparse", args],
724        inputs = resource_files,
725        outputs = [out_r_pb],
726        mnemonic = "ResLiteParse",
727        progress_message = "Lite parse Android Resources %s" % ctx.label,
728    )
729
730def _fastr(ctx, r_pbs, package, manifest, android_kit):
731    """Create R.srcjar from the given R.pb files in the transitive closure.
732
733    Args:
734      ctx: The context.
735      r_pbs: Transitive  set of resource pbs.
736      package: The package name of the compile-time R.java.
737      manifest: File. The AndroidManifest.xml file.
738      android_kit: FilesToRunProvider. The Android Kit executable or
739        FilesToRunProvider.
740
741    Returns:
742      The output R source jar artifact.
743    """
744    inputs = r_pbs
745    r_srcjar = ctx.actions.declare_file(ctx.label.name + "/resources/R-fastr.srcjar")
746    args = ctx.actions.args()
747    args.use_param_file(param_file_arg = "--flagfile=%s", use_always = True)
748    args.set_param_file_format("multiline")
749    args.add("-rJavaOutput", r_srcjar)
750    if package:
751        args.add("-packageForR", package)
752    else:
753        args.add("-manifest", manifest)
754        inputs = depset([manifest], transitive = [inputs])
755    args.add_joined("-resourcePbs", r_pbs, join_with = ",")
756
757    ctx.actions.run(
758        executable = android_kit,
759        arguments = ["rstub", args],
760        inputs = inputs,
761        outputs = [r_srcjar],
762        mnemonic = "CompileTimeR",
763        progress_message = "Generating compile-time R %s" % r_srcjar.short_path,
764    )
765    return r_srcjar
766
767def _compile(
768        ctx,
769        out_compiled_resources = None,
770        out_r_pb = None,
771        resource_files = [],
772        aapt = None,
773        android_kit = None,
774        busybox = None,
775        host_javabase = None):
776    """Compile Android Resources processing pipeline.
777
778    Args:
779      ctx: The context.
780      out_compiled_resources: File. The compiled resources output file.
781      out_r_pb: File. The R.pb output file.
782      resource_files: A list of Files. The resource files can be directories.
783      aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
784      android_kit: FilesToRunProvider. The android_kit executable or
785        FilesToRunProvider.
786      busybox: FilesToRunProvider. The ResourceBusyBox executable or
787        FilesToRunprovider
788      host_javabase: A Target. The host javabase.
789    """
790    _liteparse(ctx, out_r_pb, resource_files, android_kit)
791    _busybox.compile(
792        ctx,
793        out_file = out_compiled_resources,
794        resource_files = resource_files,
795        aapt = aapt,
796        busybox = busybox,
797        host_javabase = host_javabase,
798    )
799
800def _make_aar(
801        ctx,
802        assets = [],
803        assets_dir = None,
804        resource_files = [],
805        class_jar = None,
806        r_txt = None,
807        manifest = None,
808        proguard_specs = [],
809        busybox = None,
810        host_javabase = None):
811    """Generate an android archive file.
812
813    Args:
814      ctx: The context.
815      assets: sequence of Files. A list of Android assets files to be processed.
816      assets_dir: String. The name of the assets directory.
817      resource_files: A list of Files. The resource files.
818      class_jar: File. The class jar file.
819      r_txt: File. The resource IDs outputted by linking resources in text.
820      manifest: File. The primary AndroidManifest.xml.
821      proguard_specs: List of File. The proguard spec files.
822      busybox: FilesToRunProvider. The ResourceBusyBox executable or
823        FilesToRunprovider
824      host_javabase: A Target. The host javabase.
825
826    Returns:
827      The output aar artifact.
828    """
829    aar = ctx.actions.declare_file(ctx.label.name + ".aar")
830    _busybox.make_aar(
831        ctx,
832        out_aar = aar,
833        assets = assets,
834        assets_dir = assets_dir,
835        resource_files = resource_files,
836        class_jar = class_jar,
837        r_txt = r_txt,
838        manifest = manifest,
839        proguard_specs = proguard_specs,
840        busybox = busybox,
841        host_javabase = host_javabase,
842    )
843    return aar
844
845def _validate(ctx, manifest, defined_assets, defined_assets_dir):
846    if ((defined_assets and not defined_assets_dir) or
847        (not defined_assets and defined_assets_dir)):
848        _log.error(_ASSET_DEFINITION_ERROR % ctx.label)
849
850    if not manifest:
851        _log.error(_MANIFEST_MISSING_ERROR % ctx.label)
852
853def _make_direct_assets_transitive(assets_info):
854    return AndroidAssetsInfo(
855        assets_info.label,
856        assets_info.validation_result,
857        depset([]),  # direct_parsed_assets
858        depset(
859            transitive = [
860                assets_info.direct_parsed_assets,
861                assets_info.transitive_parsed_assets,
862            ],
863            order = "preorder",
864        ),
865        assets_info.assets,
866        assets_info.symbols,
867        assets_info.compiled_symbols,
868    )
869
870def _make_direct_resources_transitive(resources_info):
871    return AndroidResourcesInfo(
872        resources_info.label,
873        resources_info.manifest,
874        resources_info.compiletime_r_txt,
875        # NB: the ordering of "direct" and "transitive" is inconsistent with that used for
876        # AndroidAssetsInfo.
877        depset(
878            transitive = [
879                # Ordering is inconsistent here too:
880                # https://github.com/bazelbuild/bazel/blob/82c7f48b4628ebbec18123afdbed701bbaa605e2/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java#L158
881                resources_info.transitive_android_resources,
882                resources_info.direct_android_resources,
883            ],
884            order = "preorder",
885        ),
886        depset([]),  # direct_android_resources
887        resources_info.transitive_resources,
888        resources_info.transitive_manifests,
889        resources_info.transitive_aapt2_r_txt,
890        resources_info.transitive_symbols_bin,
891        resources_info.transitive_compiled_symbols,
892        resources_info.transitive_static_lib,
893        resources_info.transitive_r_txt,
894        validation_artifacts = resources_info.validation_artifacts,
895    )
896
897def _export_assets(assets_info, exports):
898    all_providers = [assets_info] + utils.collect_providers(AndroidAssetsInfo, exports)
899    return AndroidAssetsInfo(
900        assets_info.label,
901        assets_info.validation_result,
902        direct_parsed_assets = utils.join_depsets(all_providers, "direct_parsed_assets", order = "preorder"),
903        transitive_parsed_assets = utils.join_depsets(all_providers, "transitive_parsed_assets", order = "preorder"),
904        transitive_assets = utils.join_depsets(all_providers, "assets", order = "preorder"),
905        transitive_symbols = utils.join_depsets(all_providers, "symbols", order = "preorder"),
906        transitive_compiled_symbols = utils.join_depsets(all_providers, "compiled_symbols", order = "preorder"),
907    )
908
909def _export_resources(resources_info, exports):
910    all_providers = [resources_info] + utils.collect_providers(AndroidResourcesInfo, exports)
911    return AndroidResourcesInfo(
912        resources_info.label,
913        resources_info.manifest,
914        resources_info.compiletime_r_txt,
915        **{attr: utils.join_depsets(all_providers, attr, order = "preorder") for attr in [
916            "transitive_android_resources",
917            "direct_android_resources",
918            "transitive_resources",
919            "transitive_manifests",
920            "transitive_aapt2_r_txt",
921            "transitive_symbols_bin",
922            "transitive_compiled_symbols",
923            "transitive_static_lib",
924            "transitive_r_txt",
925            "validation_artifacts",
926        ]}
927    )
928
929def _validate_resources(resource_files = None):
930    for resource_file in resource_files:
931        path_segments = resource_file.path.split("/")
932        if len(path_segments) < 3:
933            fail(_INCORRECT_RESOURCE_LAYOUT_ERROR % resource_file)
934
935        # Check the resource directory type if the resource file is not a Fileset.
936        if not resource_file.is_directory:
937            # The resource directory is presumed to be the second directory from the end.
938            # Resource directories can have multiple qualifiers, each one separated with a dash.
939            res_type = path_segments[-2].partition(_RESOURCE_QUALIFIER_SEP)[0]
940            if res_type not in _RESOURCE_FOLDER_TYPES:
941                fail(_INCORRECT_RESOURCE_LAYOUT_ERROR % resource_file)
942
943def _process_starlark(
944        ctx,
945        java_package = None,
946        manifest = None,
947        defined_assets = False,
948        assets = None,
949        defined_assets_dir = False,
950        assets_dir = None,
951        exports_manifest = False,
952        stamp_manifest = True,
953        deps = [],
954        exports = [],
955        resource_files = None,
956        neverlink = False,
957        enable_data_binding = False,
958        android_test_migration = False,
959        fix_resource_transitivity = False,
960        aapt = None,
961        android_jar = None,
962        android_kit = None,
963        busybox = None,
964        java_toolchain = None,
965        host_javabase = None,
966        instrument_xslt = None,
967        xsltproc = None,
968        zip_tool = None):
969    """Processes Android Resources.
970
971    Args:
972      ctx: The rules context.
973      java_package: string. Java package for which java sources will be
974        generated. By default the package is inferred from the directory where
975        the BUILD file containing the rule is.
976      manifest: File. The AndroidManifest.xml file.
977      defined_assets: Bool. Signifies that the assets attribute was set, even
978        if the value is an empty list.
979      assets: sequence of Files. A list of Android assets files to be processed.
980      defined_assets_dir: Bool. Signifies that the assets dir attribute was set,
981        even if the value is an empty string.
982      assets_dir: String. The name of the assets directory.
983      exports_manifest: boolean. Whether to export manifest entries to the
984        android_binary targets that depend on this target.
985        NOTE: "uses-permissions" attributes are never exported.
986      stamp_manifest: boolean. Whether to stamp the manifest with the java
987        package of the target. If True, java_package needs to be passed to
988        the function.
989      deps: sequence of Targets. The list of other libraries targets to link
990        against.
991      exports: sequence of Targets. The closure of all rules reached via exports
992        attributes are considered direct dependencies of any rule that directly
993        depends on the target with exports. The exports are not direct deps of
994        the rule they belong to (TODO(b/144134042): make this so).
995      resource_files: sequence of Files. A list of Android resource files to be
996        processed.
997      neverlink: boolean. Only use this library for compilation and not runtime.
998        The outputs of a rule marked as neverlink will not be used in .apk
999        creation. Useful if the library will be provided by the runtime
1000        environment during execution.
1001      enable_data_binding: boolean. If true, processesing the data binding
1002        expressions in layout resources included through the resource_files
1003        parameter is enabled. Without this setting, data binding expressions
1004        produce build failures.
1005      android_test_migration: boolean. If true, the target is part of the android
1006      test to android instrumentation test migration and should not propagate
1007      any Android Resource providers.
1008      fix_resource_transitivity: Whether to ensure that transitive resources are
1009        correctly marked as transitive.
1010      aapt: FilesToRunProvider. The aapt executable or FilesToRunProvider.
1011      android_jar: File. The android Jar.
1012      android_kit: FilesToRunProvider. The android_kit executable or
1013        FilesToRunProvider.
1014      busybox: FilesToRunProvider. The ResourceBusyBox executable or
1015        FilesToRunprovider
1016      java_toolchain: The java_toolchain Target.
1017      host_javabase: Target. The host javabase.
1018      instrument_xslt: File. The xslt transform to apply g3itr.
1019      xsltproc: FilesToRunProvider. The xsltproc executable or FilesToRunProvider.
1020      zip_tool: FilesToRunProvider. The zip tool executable or FilesToRunProvider.
1021
1022    Returns:
1023      A dict containing _ResourcesProcessContextInfo provider fields.
1024    """
1025    if (xsltproc and not instrument_xslt) or (not xsltproc and instrument_xslt):
1026        fail(
1027            "Error, both instrument_xslt and xsltproc need to be " +
1028            "specified or not, got:\nxlstproc = %s\ninstrument_xslt = %s" %
1029            (xsltproc, instrument_xslt),
1030        )
1031
1032    _validate_resources(resource_files)
1033
1034    defines_resources = bool(
1035        manifest or
1036        resource_files or
1037        defined_assets or
1038        defined_assets_dir or
1039        exports_manifest,
1040    )
1041
1042    # TODO(djwhang): Clean up the difference between neverlink the attribute used
1043    # by Java compilation and resources neverlink.
1044    resources_neverlink = (
1045        neverlink and (
1046            defines_resources or
1047            ctx.fragments.android.fixed_resource_neverlinking
1048        )
1049    )
1050
1051    resources_ctx = {
1052        _RESOURCES_APK: None,
1053        _PROVIDERS: [],
1054        # TODO(b/156530953): Move the validation result to the validation_outputs list when we are
1055        # done rolling out Starlark resources processing
1056        _VALIDATION_RESULTS: [],
1057        _DEFINES_RESOURCES: defines_resources,
1058        _R_JAVA: None,
1059        _MERGED_MANIFEST: None,
1060        _STARLARK_PROCESSED_MANIFEST: None,
1061        _STARLARK_R_TXT: None,
1062        _STARLARK_PROCESSED_RESOURCES: [],
1063    }
1064
1065    if resource_files and not manifest:
1066        _log.error(_MANIFEST_MISSING_ERROR % ctx.label)
1067
1068    if stamp_manifest and not java_package:
1069        _log.error(_JAVA_PACKAGE_MISSING_ERROR % ctx.label)
1070
1071    direct_resources_nodes = []
1072    transitive_resources_nodes = []
1073    transitive_assets = []
1074    transitive_assets_symbols = []
1075    transitive_compiled_assets = []
1076    direct_compiled_resources = []
1077    transitive_compiled_resources = []
1078    transitive_resources_files = []
1079    transitive_manifests = []
1080    transitive_r_txts = []
1081
1082    for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, deps):
1083        direct_resources_nodes.append(dep.direct_resources_nodes)
1084        transitive_resources_nodes.append(dep.transitive_resources_nodes)
1085        transitive_assets.append(dep.transitive_assets)
1086        transitive_assets_symbols.append(dep.transitive_assets_symbols)
1087        transitive_compiled_assets.append(dep.transitive_compiled_assets)
1088        direct_compiled_resources.append(dep.direct_compiled_resources)
1089        transitive_compiled_resources.append(dep.transitive_compiled_resources)
1090        transitive_resources_files.append(dep.transitive_resource_files)
1091        transitive_manifests.append(dep.transitive_manifests)
1092        transitive_r_txts.append(dep.transitive_r_txts)
1093
1094    exports_direct_resources_nodes = []
1095    exports_transitive_resources_nodes = []
1096    exports_transitive_assets = []
1097    exports_transitive_assets_symbols = []
1098    exports_transitive_compiled_assets = []
1099    exports_direct_compiled_resources = []
1100    exports_transitive_compiled_resources = []
1101    exports_transitive_resources_files = []
1102    exports_transitive_manifests = []
1103    exports_transitive_r_txts = []
1104    for dep in utils.collect_providers(StarlarkAndroidResourcesInfo, exports):
1105        exports_direct_resources_nodes.append(dep.direct_resources_nodes)
1106        exports_transitive_resources_nodes.append(dep.transitive_resources_nodes)
1107        exports_transitive_assets.append(dep.transitive_assets)
1108        exports_transitive_assets_symbols.append(dep.transitive_assets_symbols)
1109        exports_transitive_compiled_assets.append(dep.transitive_compiled_assets)
1110        exports_direct_compiled_resources.append(dep.direct_compiled_resources)
1111        exports_transitive_compiled_resources.append(dep.transitive_compiled_resources)
1112        exports_transitive_resources_files.append(dep.transitive_resource_files)
1113        exports_transitive_manifests.append(dep.transitive_manifests)
1114        exports_transitive_r_txts.append(dep.transitive_r_txts)
1115
1116    # TODO(b/144134042): Don't merge exports; exports are not deps.
1117    direct_resources_nodes.extend(exports_direct_resources_nodes)
1118    transitive_resources_nodes.extend(exports_transitive_resources_nodes)
1119    transitive_assets.extend(exports_transitive_assets)
1120    transitive_assets_symbols.extend(exports_transitive_assets_symbols)
1121    transitive_compiled_assets.extend(exports_transitive_compiled_assets)
1122    direct_compiled_resources.extend(exports_direct_compiled_resources)
1123    transitive_compiled_resources.extend(exports_transitive_compiled_resources)
1124    transitive_resources_files.extend(exports_transitive_resources_files)
1125    transitive_manifests.extend(exports_transitive_manifests)
1126    transitive_r_txts.extend(exports_transitive_r_txts)
1127
1128    compiled_assets = None
1129    parsed_assets = None
1130    compiled_resources = None
1131    out_aapt2_r_txt = None
1132    r_txt = None
1133    processed_resources = resource_files
1134    processed_manifest = None
1135    if not defines_resources:
1136        if aapt:
1137            # Generate an empty manifest with the right package
1138            generated_manifest = ctx.actions.declare_file(
1139                "_migrated/_generated/" + ctx.label.name + "/AndroidManifest.xml",
1140            )
1141            _generate_dummy_manifest(
1142                ctx,
1143                generated_manifest,
1144                java_package if java_package else ctx.label.package.replace("/", "."),
1145            )
1146            r_txt = ctx.actions.declare_file(
1147                "_migrated/" + ctx.label.name + "_symbols/R.txt",
1148            )
1149            out_manifest = ctx.actions.declare_file(
1150                "_migrated/" + ctx.label.name + "_processed_manifest/AndroidManifest.xml",
1151            )
1152            _busybox.package(
1153                ctx,
1154                out_r_src_jar = ctx.actions.declare_file(
1155                    "_migrated/" + ctx.label.name + ".srcjar",
1156                ),
1157                out_r_txt = r_txt,
1158                out_manifest = out_manifest,
1159                manifest = generated_manifest,
1160                assets = assets,
1161                assets_dir = assets_dir,
1162                resource_files = resource_files,
1163                direct_resources_nodes =
1164                    depset(transitive = direct_resources_nodes, order = "preorder"),
1165                transitive_resources_nodes =
1166                    depset(transitive = transitive_resources_nodes, order = "preorder"),
1167                transitive_assets = transitive_assets,
1168                transitive_compiled_assets = transitive_compiled_assets,
1169                transitive_resource_files = transitive_resources_files,
1170                transitive_compiled_resources = transitive_compiled_resources,
1171                transitive_manifests = transitive_manifests,
1172                transitive_r_txts = transitive_r_txts,
1173                package_type = "LIBRARY",
1174                java_package = java_package,
1175                android_jar = android_jar,
1176                aapt = aapt,
1177                busybox = busybox,
1178                host_javabase = host_javabase,
1179                should_throw_on_conflict = False,
1180            )
1181            resources_ctx[_STARLARK_PROCESSED_MANIFEST] = out_manifest
1182            resources_ctx[_STARLARK_R_TXT] = r_txt
1183            resources_ctx[_STARLARK_PROCESSED_RESOURCES] = resource_files
1184
1185    else:
1186        if stamp_manifest:
1187            stamped_manifest = ctx.actions.declare_file(
1188                "_migrated/_renamed/" + ctx.label.name + "/AndroidManifest.xml",
1189            )
1190            _busybox.merge_manifests(
1191                ctx,
1192                out_file = stamped_manifest,
1193                manifest = manifest,
1194                merge_type = "LIBRARY",
1195                java_package = java_package,
1196                busybox = busybox,
1197                host_javabase = host_javabase,
1198            )
1199            manifest = stamped_manifest
1200
1201        if instrument_xslt:
1202            g3itr_manifest = ctx.actions.declare_file(
1203                "_migrated/" + ctx.label.name + "_g3itr_manifest/AndroidManifest.xml",
1204            )
1205            _add_g3itr(
1206                ctx,
1207                out_manifest = g3itr_manifest,
1208                manifest = manifest,
1209                xsltproc = xsltproc,
1210                instrument_xslt = instrument_xslt,
1211            )
1212            manifest = g3itr_manifest
1213
1214        parsed_assets = ctx.actions.declare_file(
1215            "_migrated/" + ctx.label.name + "_symbols/assets.bin",
1216        )
1217        _busybox.parse(
1218            ctx,
1219            out_symbols = parsed_assets,
1220            assets = assets,
1221            assets_dir = assets_dir,
1222            busybox = busybox,
1223            host_javabase = host_javabase,
1224        )
1225        merged_assets = ctx.actions.declare_file(
1226            "_migrated/" + ctx.label.name + "_files/assets.zip",
1227        )
1228        _busybox.merge_assets(
1229            ctx,
1230            out_assets_zip = merged_assets,
1231            assets = assets,
1232            assets_dir = assets_dir,
1233            symbols = parsed_assets,
1234            direct_resources_nodes = depset(
1235                transitive = direct_resources_nodes,
1236                order = "preorder",
1237            ),
1238            transitive_resources_nodes = depset(
1239                transitive = transitive_resources_nodes,
1240                order = "preorder",
1241            ),
1242            transitive_assets = transitive_assets,
1243            transitive_assets_symbols = transitive_assets_symbols,
1244            busybox = busybox,
1245            host_javabase = host_javabase,
1246        )
1247        resources_ctx[_VALIDATION_RESULTS].append(merged_assets)
1248
1249        if assets:
1250            compiled_assets = ctx.actions.declare_file(
1251                "_migrated/" + ctx.label.name + "_symbols/assets.zip",
1252            )
1253            _busybox.compile(
1254                ctx,
1255                out_file = compiled_assets,
1256                assets = assets,
1257                assets_dir = assets_dir,
1258                aapt = aapt,
1259                busybox = busybox,
1260                host_javabase = host_javabase,
1261            )
1262
1263        if enable_data_binding:
1264            out_databinding_info = ctx.actions.declare_file(
1265                "_migrated/databinding/" + ctx.label.name + "/layout-info.zip",
1266            )
1267            processed_resources, resources_dirname = _make_databinding_outputs(
1268                ctx,
1269                resource_files,
1270            )
1271            _busybox.process_databinding(
1272                ctx,
1273                out_databinding_info = out_databinding_info,
1274                out_databinding_processed_resources = processed_resources,
1275                databinding_resources_dirname = resources_dirname,
1276                resource_files = resource_files,
1277                java_package = java_package,
1278                busybox = busybox,
1279                host_javabase = host_javabase,
1280            )
1281
1282        compiled_resources = ctx.actions.declare_file(
1283            "_migrated/" + ctx.label.name + "_symbols/symbols.zip",
1284        )
1285        _busybox.compile(
1286            ctx,
1287            out_file = compiled_resources,
1288            resource_files = processed_resources,
1289            aapt = aapt,
1290            busybox = busybox,
1291            host_javabase = host_javabase,
1292        )
1293
1294        # TODO(b/160907203): Remove this fix once the native resource processing pipeline is turned off.
1295        if enable_data_binding:
1296            fixed_compiled_resources = ctx.actions.declare_file(
1297                "_migrated/fixed/" + ctx.label.name + "_symbols/symbols.zip",
1298            )
1299            _fix_databinding_compiled_resources(
1300                ctx,
1301                out_compiled_resources = fixed_compiled_resources,
1302                compiled_resources = compiled_resources,
1303                zip_tool = zip_tool,
1304            )
1305            compiled_resources = fixed_compiled_resources
1306
1307        out_class_jar = ctx.actions.declare_file(
1308            "_migrated/" + ctx.label.name + "_resources.jar",
1309        )
1310        processed_manifest = ctx.actions.declare_file(
1311            "_migrated/" + ctx.label.name + "_processed_manifest/AndroidManifest.xml",
1312        )
1313        out_aapt2_r_txt = ctx.actions.declare_file(
1314            "_migrated/" + ctx.label.name + "_symbols/R.aapt2.txt",
1315        )
1316        _busybox.merge_compiled(
1317            ctx,
1318            out_class_jar = out_class_jar,
1319            out_manifest = processed_manifest,
1320            out_aapt2_r_txt = out_aapt2_r_txt,
1321            java_package = java_package,
1322            manifest = manifest,
1323            compiled_resources = compiled_resources,
1324            direct_resources_nodes =
1325                depset(transitive = direct_resources_nodes, order = "preorder"),
1326            transitive_resources_nodes = depset(
1327                transitive = transitive_resources_nodes,
1328                order = "preorder",
1329            ),
1330            direct_compiled_resources = depset(
1331                transitive = direct_compiled_resources,
1332                order = "preorder",
1333            ),
1334            transitive_compiled_resources = depset(
1335                transitive = transitive_compiled_resources,
1336                order = "preorder",
1337            ),
1338            android_jar = android_jar,
1339            busybox = busybox,
1340            host_javabase = host_javabase,
1341        )
1342        resources_ctx[_MERGED_MANIFEST] = processed_manifest
1343
1344        apk = ctx.actions.declare_file(
1345            "_migrated/" + ctx.label.name + "_files/library.ap_",
1346        )
1347        r_java = ctx.actions.declare_file(
1348            "_migrated/" + ctx.label.name + ".srcjar",
1349        )
1350        r_txt = ctx.actions.declare_file(
1351            "_migrated/" + ctx.label.name + "_symbols/R.txt",
1352        )
1353        _busybox.validate_and_link(
1354            ctx,
1355            out_r_src_jar = r_java,
1356            out_r_txt = r_txt,
1357            out_file = apk,
1358            compiled_resources = compiled_resources,
1359            transitive_compiled_resources = depset(
1360                transitive = transitive_compiled_resources,
1361                order = "preorder",
1362            ),
1363            java_package = java_package,
1364            manifest = processed_manifest,
1365            android_jar = android_jar,
1366            aapt = aapt,
1367            busybox = busybox,
1368            host_javabase = host_javabase,
1369        )
1370        resources_ctx[_RESOURCES_APK] = apk
1371
1372        java_info = JavaInfo(
1373            output_jar = out_class_jar,
1374            compile_jar = out_class_jar,
1375            source_jar = r_java,
1376        )
1377
1378        resources_ctx[_R_JAVA] = java_info
1379
1380        # In a normal build, the outputs of _busybox.validate_and_link are unused. However we need
1381        # this action to run to support resource visibility checks.
1382        resources_ctx[_VALIDATION_RESULTS].append(r_txt)
1383
1384        # Needed for AAR generation. The Starlark resource processing pipeline uses the aapt2_r_txt file,
1385        # which is why we can't use the StarlarkAndroidResourcesInfo provider when generating the aar.
1386        resources_ctx[_STARLARK_PROCESSED_MANIFEST] = processed_manifest
1387        resources_ctx[_STARLARK_R_TXT] = r_txt
1388        resources_ctx[_STARLARK_PROCESSED_RESOURCES] = processed_resources
1389
1390    # TODO(b/117338320): Transitive lists defined here are incorrect; direct should come
1391    # before transitive, and the order should be topological order instead of preorder.
1392    # However, some applications may depend on this incorrect order.
1393    if defines_resources:
1394        transitive_resources_nodes = transitive_resources_nodes + direct_resources_nodes
1395        direct_resources_nodes = []
1396        transitive_compiled_resources = transitive_compiled_resources + direct_compiled_resources
1397        direct_compiled_resources = []
1398    else:
1399        if fix_resource_transitivity:
1400            transitive_resources_nodes = transitive_resources_nodes + direct_resources_nodes
1401            direct_resources_nodes = []
1402            transitive_compiled_resources = transitive_compiled_resources + direct_compiled_resources
1403            direct_compiled_resources = []
1404
1405        # TODO(b/144163743): If the resource transitivity fix is disabled and resources-related
1406        # inputs are missing, we implicitly export deps here. This legacy behavior must exist in the
1407        # Starlark resource processing pipeline until we can clean up the depot.
1408
1409    # TODO(b/159916013): Audit neverlink behavior. Some processing can likely be skipped if the target is neverlink.
1410    # TODO(b/69668042): Don't propagate exported providers/artifacts. Exports should respect neverlink.
1411    if resources_neverlink:
1412        resources_ctx[_PROVIDERS].append(StarlarkAndroidResourcesInfo(
1413            direct_resources_nodes = depset(
1414                transitive = exports_direct_resources_nodes,
1415                order = "preorder",
1416            ),
1417            transitive_resources_nodes = depset(
1418                transitive = exports_transitive_resources_nodes,
1419                order = "preorder",
1420            ),
1421            transitive_assets = depset(
1422                transitive = exports_transitive_assets,
1423                order = "preorder",
1424            ),
1425            transitive_assets_symbols = depset(
1426                transitive = exports_transitive_assets_symbols,
1427                order = "preorder",
1428            ),
1429            transitive_compiled_assets = depset(
1430                transitive = exports_transitive_compiled_assets,
1431                order = "preorder",
1432            ),
1433            transitive_resource_files = depset(
1434                transitive = exports_transitive_resources_files,
1435                order = "preorder",
1436            ),
1437            direct_compiled_resources = depset(
1438                transitive = exports_direct_compiled_resources,
1439                order = "preorder",
1440            ),
1441            transitive_compiled_resources = depset(
1442                transitive = exports_transitive_compiled_resources,
1443                order = "preorder",
1444            ),
1445            transitive_manifests = depset(
1446                [processed_manifest] if processed_manifest else [],
1447                transitive = exports_transitive_manifests,
1448                order = "preorder",
1449            ),
1450            transitive_r_txts = depset(
1451                [out_aapt2_r_txt] if out_aapt2_r_txt else [],
1452                transitive = exports_transitive_r_txts,
1453                order = "preorder",
1454            ),
1455        ))
1456    else:
1457        # Depsets are ordered below to match the order in the legacy native rules.
1458        resources_ctx[_PROVIDERS].append(StarlarkAndroidResourcesInfo(
1459            direct_resources_nodes = depset(
1460                [ResourcesNodeInfo(
1461                    label = ctx.label,
1462                    assets = depset(assets),
1463                    assets_dir = assets_dir,
1464                    assets_symbols = parsed_assets,
1465                    compiled_assets = compiled_assets,
1466                    resource_files = depset(processed_resources),
1467                    compiled_resources = compiled_resources,
1468                    r_txt = out_aapt2_r_txt,
1469                    manifest = processed_manifest,
1470                    exports_manifest = exports_manifest,
1471                )] if defines_resources else [],
1472                transitive = direct_resources_nodes + exports_direct_resources_nodes,
1473                order = "preorder",
1474            ),
1475            transitive_resources_nodes = depset(
1476                transitive = transitive_resources_nodes + exports_transitive_resources_nodes,
1477                order = "preorder",
1478            ),
1479            transitive_assets = depset(
1480                assets,
1481                transitive = transitive_assets + exports_transitive_assets,
1482                order = "preorder",
1483            ),
1484            transitive_assets_symbols = depset(
1485                [parsed_assets] if parsed_assets else [],
1486                transitive = transitive_assets_symbols + exports_transitive_assets_symbols,
1487                order = "preorder",
1488            ),
1489            transitive_compiled_assets = depset(
1490                [compiled_assets] if compiled_assets else [],
1491                transitive = transitive_compiled_assets + exports_transitive_compiled_assets,
1492                order = "preorder",
1493            ),
1494            transitive_resource_files = depset(
1495                processed_resources,
1496                transitive = transitive_resources_files + exports_transitive_resources_files,
1497                order = "preorder",
1498            ),
1499            direct_compiled_resources = depset(
1500                [compiled_resources] if compiled_resources else [],
1501                transitive = direct_compiled_resources + exports_direct_compiled_resources,
1502                order = "preorder",
1503            ),
1504            transitive_compiled_resources = depset(
1505                [compiled_resources] if compiled_resources else [],
1506                transitive = transitive_compiled_resources + exports_transitive_compiled_resources,
1507                order = "preorder",
1508            ),
1509            transitive_manifests = depset(
1510                [processed_manifest] if processed_manifest else [],
1511                transitive = transitive_manifests + exports_transitive_manifests,
1512                order = "preorder",
1513            ),
1514            transitive_r_txts = depset(
1515                [out_aapt2_r_txt] if out_aapt2_r_txt else [],
1516                transitive = transitive_r_txts + exports_transitive_r_txts,
1517                order = "preorder",
1518            ),
1519        ))
1520
1521    # Do not collect resources and R.java for test apk
1522    if android_test_migration:
1523        resources_ctx[_R_JAVA] = None
1524        resources_ctx[_PROVIDERS] = []
1525
1526    # TODO(b/69552500): In the Starlark Android Rules, the R compile time
1527    # JavaInfo is added as a runtime dependency to the JavaInfo. Stop
1528    # adding the R.jar as a runtime dependency.
1529    resources_ctx[_PROVIDERS].append(
1530        AndroidLibraryResourceClassJarProvider(
1531            depset(
1532                (resources_ctx[_R_JAVA].runtime_output_jars if resources_ctx[_R_JAVA] else []),
1533                transitive = [
1534                    p.jars
1535                    for p in utils.collect_providers(
1536                        AndroidLibraryResourceClassJarProvider,
1537                        deps,
1538                        exports,
1539                    )
1540                ],
1541                order = "preorder",
1542            ),
1543        ),
1544    )
1545
1546    return resources_ctx
1547
1548
1549def _process(
1550        ctx,
1551        manifest = None,
1552        resource_files = None,
1553        defined_assets = False,
1554        assets = None,
1555        defined_assets_dir = False,
1556        assets_dir = None,
1557        exports_manifest = False,
1558        java_package = None,
1559        custom_package = None,
1560        neverlink = False,
1561        enable_data_binding = False,
1562        deps = [],
1563        exports = [],
1564        android_jar = None,
1565        android_kit = None,
1566        aapt = None,
1567        busybox = None,
1568        xsltproc = None,
1569        instrument_xslt = None,
1570        java_toolchain = None,
1571        host_javabase = None,
1572        enable_res_v3 = False,
1573        res_v3_dummy_manifest = None,
1574        res_v3_dummy_r_txt = None,
1575        fix_resource_transitivity = False,
1576        fix_export_exporting = False,
1577        android_test_migration = False,
1578        zip_tool = None):
1579    out_ctx = _process_starlark(
1580        ctx,
1581        java_package = java_package,
1582        manifest = manifest,
1583        defined_assets = defined_assets,
1584        # TODO(b/159937795): When the Starlark Resources Processing pipeline is
1585        # default and the native version is no longer used, remove the depset
1586        # creation and directly pass through ctx.files.assets to this method.
1587        assets =
1588            depset(transitive = [target.files for target in assets]).to_list(),
1589        defined_assets_dir = defined_assets_dir,
1590        assets_dir = assets_dir,
1591        exports_manifest = exports_manifest,
1592        stamp_manifest = True if java_package else False,
1593        deps = deps,
1594        exports = exports,
1595        resource_files = depset(transitive = [target.files for target in resource_files]).to_list(),
1596        enable_data_binding = enable_data_binding,
1597        fix_resource_transitivity = fix_resource_transitivity,
1598        neverlink = neverlink,
1599        android_test_migration = android_test_migration,
1600        android_jar = android_jar,
1601        aapt = aapt,
1602        android_kit = android_kit,
1603        busybox = busybox,
1604        instrument_xslt = instrument_xslt,
1605        xsltproc = xsltproc,
1606        java_toolchain = java_toolchain,
1607        host_javabase = host_javabase,
1608        zip_tool = zip_tool,
1609    )
1610
1611
1612    if _VALIDATION_OUTPUTS not in out_ctx:
1613        out_ctx[_VALIDATION_OUTPUTS] = []
1614
1615    return _ResourcesProcessContextInfo(**out_ctx)
1616
1617resources = struct(
1618    process = _process,
1619    process_starlark = _process_starlark,
1620    package = _package,
1621    make_aar = _make_aar,
1622
1623    # Exposed for mobile-install
1624    compile = _compile,
1625    legacy_merge_manifests = _legacy_merge_manifests,
1626
1627    # Exposed for android_local_test and android_library
1628    generate_dummy_manifest = _generate_dummy_manifest,
1629)
1630
1631testing = struct(
1632    add_g3itr = _add_g3itr,
1633    filter_multi_cpu_configuration_targets = _filter_multi_cpu_configuration_targets,
1634    get_legacy_mergee_manifests = _get_legacy_mergee_manifests,
1635    make_databinding_outputs = _make_databinding_outputs,
1636    ResourcesPackageContextInfo = _ResourcesPackageContextInfo,
1637    ResourcesProcessContextInfo = _ResourcesProcessContextInfo,
1638)
1639