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