xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/baseline_profiles.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"""
16Defines baseline profiles processing methods in Android Rules.
17"""
18
19_BASELINE_PROFILE_DIR_SUFFIX = "-baseline-profile/"
20
21def _process(
22        ctx,
23        transitive_profiles = depset(),
24        startup_profiles = [],
25        deploy_jar = None,
26        has_proguard_specs = False,
27        enable_optimizer_integration = False,
28        merge_tool = None,
29        profgen = None,
30        toolchain_type = None):
31    """Processes all the transitive baseline profiles.
32
33    Baseline profiles propagated from libraries will be merged, and if optimizer integration is
34    enabled, startup profiles will be merged as well, and wildcards in baseline profiles will be
35    expanded.
36
37    Args:
38      ctx: The context.
39      transitive_profiles: Depset. The transitive baseline profiles propagated from android_library
40          and aar_import.
41      startup_profiles: List. The startup profiles.
42      deploy_jar: File. The deploy jar.
43      has_proguard_specs: Boolean. Whether to have proguard specs.
44      enable_optimizer_integration: Boolean. Whether to use startup profile and baseline profiles in optimization.
45      merge_tool: FilesToRunProvider. An executable for merging baseline profiles.
46      profgen: FilesToRunProvider: An executable for compiling baseline profiles.
47      toolchain_type: Label or String. Toolchain type of the executable used in actions.
48    Returns:
49      A struct containing all the outputs from processing baseline profiles.
50    """
51
52    baseline_profile = None
53    startup_profile = None
54    if transitive_profiles:
55        baseline_profile = _get_profile_artifact(ctx, "static-prof.txt")
56        _merge(
57            ctx,
58            baseline_profile,
59            transitive_profiles,
60            "MergeBaselineProfiles",
61            merge_tool = merge_tool,
62            toolchain_type = toolchain_type,
63        )
64
65    if has_proguard_specs and enable_optimizer_integration:
66        # This is only needed for optimized builds since otherwise the dexer doesn't process this.
67        if startup_profiles:
68            startup_profile = _get_profile_artifact(ctx, "static-startup-prof.txt")
69            _merge(
70                ctx,
71                output = startup_profile,
72                inputs = ctx.files.startup_profiles,
73                mnemonic = "MergeStartupProfiles",
74                merge_tool = merge_tool,
75                toolchain_type = toolchain_type,
76            )
77
78        # Wildcards only need to be expanded for optimized builds since if these aren't consumed by
79        # the optimizer, they can just be expanded during profile compilation instead.
80        # Start-up profiles are not expanded because it shouldn't be necessary as these should
81        # contain profiles generated by devices on start-up.
82        if baseline_profile:
83            expanded_baseline_profile = _get_profile_artifact(ctx, "expanded-static-prof.txt")
84            _expand_wildcards(
85                ctx,
86                output = expanded_baseline_profile,
87                deploy_jar = deploy_jar,
88                profile = baseline_profile,
89                profgen = profgen,
90                toolchain_type = toolchain_type,
91            )
92            baseline_profile = expanded_baseline_profile
93    return struct(
94        baseline_profile = baseline_profile,
95        startup_profile = startup_profile,
96    )
97
98def _process_art_profile(
99        ctx,
100        final_classes_dex,
101        merged_profile,
102        proguard_output_map = None,
103        profgen = None,
104        zipper = None,
105        toolchain_type = None):
106    """ Compiles the merged baseline profile.
107
108    Profiles are compiled with profgen into binary ART profiles. The binary
109    profiles will be bundled into the final APK and used at installation time to speed up app
110    startup and reduce jank.
111
112    Args:
113      ctx: The context.
114      final_classes_dex: File. Final classes zip artifact.
115      merged_profile: File. The merged profile from transitive baseline profile files.
116      proguard_output_map: File. Optional. The proguard output mapping file.
117      profgen: FilesToRunProvider. The profgen executable for profile compilation.
118      zipper: FilesToRunProvider. An executable for compressing files to an archive.
119      toolchain_type: Label or String. Toolchain type of the executable used in actions.
120    Returns:
121      Provider info containing BaselineProfileProvider for all merged profiles.
122    """
123
124    # Profgen
125    output_profile = _get_profile_artifact(ctx, "baseline.prof")
126    output_profile_meta = _get_profile_artifact(ctx, "baseline.profm")
127    profgen_inputs = [final_classes_dex, merged_profile]
128    profgen_args = ctx.actions.args()
129    profgen_args.add("bin", merged_profile)
130    profgen_args.add("--apk", final_classes_dex)
131    profgen_args.add("--output", output_profile)
132    profgen_args.add("--output-meta", output_profile_meta)
133    if proguard_output_map:
134        profgen_args.add("--map", proguard_output_map)
135        profgen_inputs.append(proguard_output_map)
136    ctx.actions.run(
137        mnemonic = "GenerateARTProfile",
138        executable = profgen,
139        progress_message = "Generating Android P-R ART profile for %{label} APK",
140        arguments = [profgen_args],
141        inputs = profgen_inputs,
142        outputs = [output_profile, output_profile_meta],
143        use_default_shell_env = True,
144        toolchain = toolchain_type,
145    )
146
147    # Zip ART profiles
148    output_profile_zip = _get_profile_artifact(ctx, "art_profile.zip")
149    zip_args = ctx.actions.args()
150    zip_args.add("c", output_profile_zip)
151    zip_args.add(output_profile.path, format = "assets/dexopt/baseline.prof=%s")
152    zip_args.add(output_profile_meta.path, format = "assets/dexopt/baseline.profm=%s")
153    ctx.actions.run(
154        mnemonic = "ZipARTProfiles",
155        executable = zipper,
156        progress_message = "Zip ART Profiles for %{label}",
157        arguments = [zip_args],
158        inputs = [output_profile, output_profile_meta],
159        outputs = [output_profile_zip],
160        use_default_shell_env = True,
161        toolchain = toolchain_type,
162    )
163    return BaselineProfileProvider(
164        # Unnecessary to pass the transitive profiles to native rule
165        depset(),
166        output_profile_zip,
167    )
168
169def _get_profile_dir(ctx):
170    return ctx.label.name + _BASELINE_PROFILE_DIR_SUFFIX
171
172def _get_profile_artifact(ctx, name):
173    return ctx.actions.declare_file(_get_profile_dir(ctx) + name)
174
175def _merge(
176        ctx,
177        output,
178        inputs = [],
179        mnemonic = "MergeBaselineProfiles",
180        merge_tool = None,
181        toolchain_type = None):
182    args = ctx.actions.args()
183    args.add_all(inputs, before_each = "--input")
184    args.add("--output", output)
185
186    ctx.actions.run(
187        executable = merge_tool,
188        mnemonic = mnemonic,
189        arguments = [args],
190        inputs = inputs,
191        outputs = [output],
192        use_default_shell_env = True,
193        toolchain = toolchain_type,
194    )
195
196def _expand_wildcards(
197        ctx,
198        output,
199        deploy_jar = None,
200        profile = None,
201        profgen = None,
202        toolchain_type = None):
203    args = ctx.actions.args()
204    args.add("expandWildcards", deploy_jar)
205    args.add("--profile", profile)
206    args.add("--output", output)
207
208    ctx.actions.run(
209        executable = profgen,
210        outputs = [output],
211        inputs = [deploy_jar, profile],
212        arguments = [args],
213        mnemonic = "ExpandBaselineProfileWildcards",
214        progress_message = "Expanding baseline profile wildcards for %{label} APK",
215        toolchain = toolchain_type,
216    )
217
218baseline_profiles = struct(
219    expand_wildcards = _expand_wildcards,
220    get_profile_artifact = _get_profile_artifact,
221    process = _process,
222    process_art_profile = _process_art_profile,
223)
224