xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/android_binary_internal/r8.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1# Copyright 2023 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"""R8 processor steps for android_binary_internal."""
16
17load("//rules:acls.bzl", "acls")
18load("//rules:proguard.bzl", "proguard")
19load(
20    "//rules:utils.bzl",
21    "ANDROID_TOOLCHAIN_TYPE",
22    "get_android_sdk",
23    "get_android_toolchain",
24)
25load(
26    "//rules:processing_pipeline.bzl",
27    "ProviderInfo",
28)
29load("//rules:common.bzl", "common")
30load("//rules:java.bzl", "java")
31load("//rules:resources.bzl", _resources = "resources")
32
33def process_r8(ctx, jvm_ctx, packaged_resources_ctx, build_info_ctx, **_unused_ctxs):
34    """Runs R8 for desugaring, optimization, and dexing.
35
36    Args:
37      ctx: Rule contxt.
38      jvm_ctx: Context from the java processor.
39      packaged_resources_ctx: Context from resource processing.
40      build_info_ctx: Context from build info processor.
41      **_unused_ctxs: Unused context.
42
43    Returns:
44      The r8_ctx ProviderInfo.
45    """
46    local_proguard_specs = ctx.files.proguard_specs
47    if not acls.use_r8(str(ctx.label)) or not local_proguard_specs:
48        return ProviderInfo(
49            name = "r8_ctx",
50            value = struct(
51                providers = [],
52            ),
53        )
54
55    # The R8 processor step creates its own deploy jar instead of
56    # The deploy jar from the deploy_jar processor is not used because as of now, whether it
57    # actually produces a deploy jar is determinted by a separate set of ACLs, and also does
58    # desugaring differently than with R8.
59    deploy_jar = ctx.actions.declare_file(ctx.label.name + "_deploy.jar")
60    java.create_deploy_jar(
61        ctx,
62        output = deploy_jar,
63        runtime_jars = depset(
64            direct = jvm_ctx.java_info.runtime_output_jars + [packaged_resources_ctx.class_jar],
65            transitive = [jvm_ctx.java_info.transitive_runtime_jars],
66        ),
67        java_toolchain = common.get_java_toolchain(ctx),
68        build_target = ctx.label.name,
69        deploy_manifest_lines = build_info_ctx.deploy_manifest_lines,
70    )
71
72    dexes_zip = ctx.actions.declare_file(ctx.label.name + "_dexes.zip")
73
74    android_jar = get_android_sdk(ctx).android_jar
75    proguard_specs = proguard.get_proguard_specs(ctx, packaged_resources_ctx.resource_proguard_config)
76    min_sdk_version = getattr(ctx.attr, "min_sdk_version", None)
77
78    args = ctx.actions.args()
79    args.add("--release")
80    if min_sdk_version:
81        args.add("--min-api", min_sdk_version)
82    args.add("--output", dexes_zip)
83    args.add_all(proguard_specs, before_each = "--pg-conf")
84    args.add("--lib", android_jar)
85    args.add(deploy_jar)  # jar to optimize + desugar + dex
86
87    java.run(
88        ctx = ctx,
89        host_javabase = common.get_host_javabase(ctx),
90        executable = get_android_toolchain(ctx).r8.files_to_run,
91        arguments = [args],
92        inputs = [android_jar, deploy_jar] + proguard_specs,
93        outputs = [dexes_zip],
94        mnemonic = "AndroidR8",
95        jvm_flags = ["-Xmx8G"],
96        progress_message = "R8 Optimizing, Desugaring, and Dexing %{label}",
97    )
98
99    android_dex_info = AndroidDexInfo(
100        deploy_jar = deploy_jar,
101        final_classes_dex_zip = dexes_zip,
102        # R8 preserves the Java resources (i.e. non-Java-class files) in its output zip, so no need
103        # to provide a Java resources zip.
104        java_resource_jar = None,
105    )
106
107    return ProviderInfo(
108        name = "r8_ctx",
109        value = struct(
110            final_classes_dex_zip = dexes_zip,
111            providers = [android_dex_info],
112        ),
113    )
114
115def process_resource_shrinking_r8(ctx, r8_ctx, packaged_resources_ctx, **_unused_ctxs):
116    """Runs resource shrinking.
117
118    Args:
119      ctx: Rule contxt.
120      r8_ctx: Context from the R8 processor.
121      packaged_resources_ctx: Context from resource processing.
122      **_unused_ctxs: Unused context.
123
124    Returns:
125      The r8_ctx ProviderInfo.
126    """
127    local_proguard_specs = ctx.files.proguard_specs
128    if (not acls.use_r8(str(ctx.label)) or
129        not local_proguard_specs or
130        not _resources.is_resource_shrinking_enabled(
131            ctx.attr.shrink_resources,
132            ctx.fragments.android.use_android_resource_shrinking,
133        )):
134        return ProviderInfo(
135            name = "resource_shrinking_r8_ctx",
136            value = struct(
137                android_application_resource_info_with_shrunk_resource_apk = None,
138                providers = [],
139            ),
140        )
141
142    android_toolchain = get_android_toolchain(ctx)
143
144    # 1. Convert the resource APK to proto format (resource shrinker operates on a proto apk)
145    proto_resource_apk = ctx.actions.declare_file(ctx.label.name + "_proto_resource_apk.ap_")
146    ctx.actions.run(
147        arguments = [ctx.actions.args()
148            .add("convert")
149            .add(packaged_resources_ctx.resources_apk)  # input apk
150            .add("-o", proto_resource_apk)  # output apk
151            .add("--output-format", "proto")],
152        executable = android_toolchain.aapt2.files_to_run,
153        inputs = [packaged_resources_ctx.resources_apk],
154        mnemonic = "Aapt2ConvertToProtoForResourceShrinkerR8",
155        outputs = [proto_resource_apk],
156        toolchain = ANDROID_TOOLCHAIN_TYPE,
157    )
158
159    # 2. Run the resource shrinker
160    proto_resource_apk_shrunk = ctx.actions.declare_file(
161        ctx.label.name + "_proto_resource_apk_shrunk.ap_",
162    )
163    java.run(
164        ctx = ctx,
165        host_javabase = common.get_host_javabase(ctx),
166        executable = android_toolchain.resource_shrinker.files_to_run,
167        arguments = [ctx.actions.args()
168            .add("--input", proto_resource_apk)
169            .add("--dex_input", r8_ctx.final_classes_dex_zip)
170            .add("--output", proto_resource_apk_shrunk)],
171        inputs = [proto_resource_apk, r8_ctx.final_classes_dex_zip],
172        outputs = [proto_resource_apk_shrunk],
173        mnemonic = "ResourceShrinkerForR8",
174        progress_message = "Shrinking resources %{label}",
175    )
176
177    # 3. Convert back to a binary APK
178    resource_apk_shrunk = ctx.actions.declare_file(ctx.label.name + "_resource_apk_shrunk.ap_")
179    ctx.actions.run(
180        arguments = [ctx.actions.args()
181            .add("convert")
182            .add(proto_resource_apk_shrunk)  # input apk
183            .add("-o", resource_apk_shrunk)  # output apk
184            .add("--output-format", "binary")],
185        executable = android_toolchain.aapt2.files_to_run,
186        inputs = [proto_resource_apk_shrunk],
187        mnemonic = "Aapt2ConvertBackToBinaryForResourceShrinkerR8",
188        outputs = [resource_apk_shrunk],
189        toolchain = ANDROID_TOOLCHAIN_TYPE,
190    )
191
192    aari = packaged_resources_ctx.android_application_resource
193
194    # Replace the resource apk in the AndroidApplicationResourceInfo provider from resource
195    # processing.
196    new_aari = AndroidApplicationResourceInfo(
197        resource_apk = resource_apk_shrunk,
198        resource_java_src_jar = aari.resource_java_src_jar,
199        resource_java_class_jar = aari.resource_java_class_jar,
200        manifest = aari.manifest,
201        resource_proguard_config = aari.resource_proguard_config,
202        main_dex_proguard_config = aari.main_dex_proguard_config,
203        r_txt = aari.r_txt,
204        resources_zip = aari.resources_zip,
205        databinding_info = aari.databinding_info,
206        should_compile_java_srcs = aari.should_compile_java_srcs,
207    )
208
209    return ProviderInfo(
210        name = "resource_shrinking_r8_ctx",
211        value = struct(
212            android_application_resource_info_with_shrunk_resource_apk = new_aari,
213            providers = [],
214        ),
215    )
216