| # Copyright 2023 The Bazel Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """ | |
| Defines baseline profiles processing methods in Android Rules. | |
| """ | |
| load("//providers:providers.bzl", "ArtProfileInfo") | |
| load("//rules:common.bzl", _common = "common") | |
| load("//rules:java.bzl", _java = "java") | |
| load("//rules:visibility.bzl", "PROJECT_VISIBILITY") | |
| visibility(PROJECT_VISIBILITY) | |
| _BASELINE_PROFILE_DIR_SUFFIX = "-baseline-profile/" | |
| def _process( | |
| ctx, | |
| transitive_profiles = depset(), | |
| startup_profiles = [], | |
| deploy_jar = None, | |
| has_proguard_specs = False, | |
| enable_optimizer_integration = False, | |
| merge_tool = None, | |
| profgen = None, | |
| toolchain_type = None): | |
| """Processes all the transitive baseline profiles. | |
| Baseline profiles propagated from libraries will be merged, and if optimizer integration is | |
| enabled, startup profiles will be merged as well, and wildcards in baseline profiles will be | |
| expanded. | |
| Args: | |
| ctx: The context. | |
| transitive_profiles: Depset. The transitive baseline profiles propagated from android_library | |
| and aar_import. | |
| startup_profiles: List. The startup profiles. | |
| deploy_jar: File. The deploy jar. | |
| has_proguard_specs: Boolean. Whether to have proguard specs. | |
| enable_optimizer_integration: Boolean. Whether to use startup profile and baseline profiles in optimization. | |
| merge_tool: FilesToRunProvider. An executable for merging baseline profiles. | |
| profgen: FilesToRunProvider: An executable for compiling baseline profiles. | |
| toolchain_type: Label or String. Toolchain type of the executable used in actions. | |
| Returns: | |
| A struct containing all the outputs from processing baseline profiles. | |
| """ | |
| baseline_profile = None | |
| startup_profile = None | |
| if transitive_profiles: | |
| baseline_profile = _get_profile_artifact(ctx, "static-prof.txt") | |
| _merge( | |
| ctx, | |
| baseline_profile, | |
| transitive_profiles, | |
| "MergeBaselineProfiles", | |
| merge_tool = merge_tool, | |
| toolchain_type = toolchain_type, | |
| ) | |
| if has_proguard_specs and enable_optimizer_integration: | |
| # This is only needed for optimized builds since otherwise the dexer doesn't process this. | |
| if startup_profiles: | |
| startup_profile = _get_profile_artifact(ctx, "static-startup-prof.txt") | |
| _merge( | |
| ctx, | |
| output = startup_profile, | |
| inputs = ctx.files.startup_profiles, | |
| mnemonic = "MergeStartupProfiles", | |
| merge_tool = merge_tool, | |
| toolchain_type = toolchain_type, | |
| ) | |
| # Wildcards only need to be expanded for optimized builds since if these aren't consumed by | |
| # the optimizer, they can just be expanded during profile compilation instead. | |
| # Start-up profiles are not expanded because it shouldn't be necessary as these should | |
| # contain profiles generated by devices on start-up. | |
| if baseline_profile: | |
| expanded_baseline_profile = _get_profile_artifact(ctx, "expanded-static-prof.txt") | |
| _expand_wildcards( | |
| ctx, | |
| output = expanded_baseline_profile, | |
| deploy_jar = deploy_jar, | |
| profile = baseline_profile, | |
| profgen = profgen, | |
| toolchain_type = toolchain_type, | |
| ) | |
| baseline_profile = expanded_baseline_profile | |
| return struct( | |
| baseline_profile = baseline_profile, | |
| startup_profile = startup_profile, | |
| ) | |
| def _process_art_profile( | |
| ctx, | |
| final_classes_dex, | |
| merged_profile, | |
| output_primary_profile, | |
| proguard_output_map = None, | |
| profgen = None, | |
| toolchain_type = None): | |
| """ Compiles the merged baseline profile. | |
| Profiles are compiled with profgen into binary ART profiles. The binary | |
| profiles will be bundled into the final APK and used at installation time to speed up app | |
| startup and reduce jank. | |
| Args: | |
| ctx: The context. | |
| final_classes_dex: File. Final classes zip artifact. | |
| merged_profile: File. The merged profile from transitive baseline profile files. | |
| proguard_output_map: File. Optional. The proguard output mapping file. | |
| profgen: FilesToRunProvider. The profgen executable for profile compilation. | |
| toolchain_type: Label or String. Toolchain type of the executable used in actions. | |
| Returns: | |
| ArtProfileInfo containing the generated profile, the metadata, and the combined zip file. | |
| """ | |
| output_profile = _get_profile_artifact(ctx, "baseline.prof") | |
| output_profile_meta = _get_profile_artifact(ctx, "baseline.profm") | |
| _generate_profile( | |
| ctx, | |
| output_profile, | |
| output_profile_meta, | |
| final_classes_dex, | |
| merged_profile, | |
| proguard_output_map, | |
| profgen, | |
| toolchain_type, | |
| ) | |
| # Zip ART profiles | |
| output_profile_zip = _get_profile_artifact(ctx, "art_profile.zip") | |
| _java.singlejar( | |
| ctx, | |
| compression = False, | |
| inputs = [], | |
| output = output_profile_zip, | |
| mnemonic = "ZipARTProfiles", | |
| progress_message = "Zip ART Profiles for %{label}", | |
| resource_paths = [output_profile.path + ":assets/dexopt/baseline.prof", output_profile_meta.path + ":assets/dexopt/baseline.profm"], | |
| resources = [output_profile, output_profile_meta], | |
| java_toolchain = _common.get_java_toolchain(ctx), | |
| ) | |
| _dump_profile( | |
| ctx, | |
| output_primary_profile, | |
| output_profile, | |
| final_classes_dex, | |
| profgen, | |
| toolchain_type, | |
| ) | |
| return ArtProfileInfo( | |
| art_profile_zip = output_profile_zip, | |
| baseline_profile = output_profile, | |
| baseline_profile_metadata = output_profile_meta, | |
| primary_profile = output_primary_profile, | |
| ) | |
| def _get_profile_dir(ctx): | |
| return ctx.label.name + _BASELINE_PROFILE_DIR_SUFFIX | |
| def _get_profile_artifact(ctx, name): | |
| return ctx.actions.declare_file(_get_profile_dir(ctx) + name) | |
| def _merge( | |
| ctx, | |
| output, | |
| inputs = [], | |
| mnemonic = "MergeBaselineProfiles", | |
| merge_tool = None, | |
| toolchain_type = None): | |
| args = ctx.actions.args() | |
| args.add_all(inputs, before_each = "--input") | |
| args.add("--output", output) | |
| ctx.actions.run( | |
| executable = merge_tool, | |
| mnemonic = mnemonic, | |
| arguments = [args], | |
| inputs = inputs, | |
| outputs = [output], | |
| use_default_shell_env = True, | |
| toolchain = toolchain_type, | |
| ) | |
| def _expand_wildcards( | |
| ctx, | |
| output, | |
| deploy_jar = None, | |
| profile = None, | |
| profgen = None, | |
| toolchain_type = None): | |
| args = ctx.actions.args() | |
| args.add("expandWildcards", deploy_jar) | |
| args.add("--profile", profile) | |
| args.add("--output", output) | |
| ctx.actions.run( | |
| executable = profgen, | |
| outputs = [output], | |
| inputs = [deploy_jar, profile], | |
| arguments = [args], | |
| mnemonic = "ExpandBaselineProfileWildcards", | |
| progress_message = "Expanding baseline profile wildcards for %{label} APK", | |
| toolchain = toolchain_type, | |
| ) | |
| def _generate_profile( | |
| ctx, | |
| output_profile, | |
| output_profile_meta, | |
| final_classes_dex, | |
| merged_profile, | |
| proguard_output_map = None, | |
| profgen = None, | |
| toolchain_type = None): | |
| profgen_inputs = [final_classes_dex, merged_profile] | |
| args = ctx.actions.args() | |
| args.add("bin", merged_profile) | |
| args.add("--apk", final_classes_dex) | |
| args.add("--output", output_profile) | |
| args.add("--output-meta", output_profile_meta) | |
| if proguard_output_map: | |
| args.add("--map", proguard_output_map) | |
| profgen_inputs.append(proguard_output_map) | |
| ctx.actions.run( | |
| mnemonic = "GenerateARTProfile", | |
| executable = profgen, | |
| progress_message = "Generating Android P-R ART profile for %{label} APK", | |
| arguments = [args], | |
| inputs = profgen_inputs, | |
| outputs = [output_profile, output_profile_meta], | |
| use_default_shell_env = True, | |
| toolchain = toolchain_type, | |
| ) | |
| def _dump_profile( | |
| ctx, | |
| output, | |
| binary_profile, | |
| final_classes_dex, | |
| profgen = None, | |
| toolchain_type = None): | |
| args = ctx.actions.args() | |
| args.add("dumpProfile") | |
| args.add("--profile", binary_profile) | |
| args.add("--apk", final_classes_dex) | |
| args.add("--output", output) | |
| ctx.actions.run( | |
| mnemonic = "DumpProfile", | |
| executable = profgen, | |
| progress_message = "Dumping Obfuscated-HRP profile for %{label} APK", | |
| arguments = [args], | |
| inputs = [binary_profile, final_classes_dex], | |
| outputs = [output], | |
| use_default_shell_env = True, | |
| toolchain = toolchain_type, | |
| ) | |
| baseline_profiles = struct( | |
| expand_wildcards = _expand_wildcards, | |
| get_profile_artifact = _get_profile_artifact, | |
| process = _process, | |
| process_art_profile = _process_art_profile, | |
| ) |