blob: c6f0359e9f6f8c137a5e35fba3acb59c03a1d433 [file] [log] [blame]
# 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,
)