Skip to content

Commit

Permalink
[Android] Enable unused resources removal on bundle targets (relandx2)
Browse files Browse the repository at this point in the history
This reverts commit 7be1e6f.

Fixes issue with missing R.txt files (by still outputting them).

Bug: 636448,1216318
Change-Id: I879ba0449554f71636f7c337a46e2fbca68684cf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2953886
Auto-Submit: Mohamed Heikal <mheikal@chromium.org>
Commit-Queue: Mohamed Heikal <mheikal@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#892081}
  • Loading branch information
m0hamed authored and Chromium LUCI CQ committed Jun 14, 2021
1 parent af6ed02 commit 246710c
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 352 deletions.
2 changes: 1 addition & 1 deletion PRESUBMIT.py
Original file line number Diff line number Diff line change
Expand Up @@ -1132,8 +1132,8 @@
'build/android/gyp/prepare_resources.pydeps',
'build/android/gyp/process_native_prebuilt.pydeps',
'build/android/gyp/proguard.pydeps',
'build/android/gyp/resources_shrinker/shrinker.pydeps',
'build/android/gyp/turbine.pydeps',
'build/android/gyp/unused_resources.pydeps',
'build/android/gyp/validate_static_library_dex_references.pydeps',
'build/android/gyp/write_build_config.pydeps',
'build/android/gyp/write_native_libraries_java.pydeps',
Expand Down
130 changes: 0 additions & 130 deletions build/android/gyp/compile_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,29 +177,10 @@ def _ParseArgs(args):
'--no-xml-namespaces',
action='store_true',
help='Whether to strip xml namespaces from processed xml resources.')
input_opts.add_argument(
'--short-resource-paths',
action='store_true',
help='Whether to shorten resource paths inside the apk or module.')
input_opts.add_argument(
'--strip-resource-names',
action='store_true',
help='Whether to strip resource names from the resource table of the apk '
'or module.')

output_opts.add_argument('--arsc-path', help='Apk output for arsc format.')
output_opts.add_argument('--proto-path', help='Apk output for proto format.')
group = input_opts.add_mutually_exclusive_group()
group.add_argument(
'--optimized-arsc-path',
help='Output for `aapt2 optimize` for arsc format (enables the step).')
group.add_argument(
'--optimized-proto-path',
help='Output for `aapt2 optimize` for proto format (enables the step).')
input_opts.add_argument(
'--resources-config-paths',
default='[]',
help='GN list of paths to aapt2 resources config files.')

output_opts.add_argument(
'--info-path', help='Path to output info file for the partial apk.')
Expand All @@ -222,11 +203,6 @@ def _ParseArgs(args):
output_opts.add_argument(
'--emit-ids-out', help='Path to file produced by aapt2 --emit-ids.')

output_opts.add_argument(
'--resources-path-map-out-path',
help='Path to file produced by aapt2 that maps original resource paths '
'to shortened resource paths inside the apk or module.')

input_opts.add_argument(
'--is-bundle-module',
action='store_true',
Expand Down Expand Up @@ -257,20 +233,10 @@ def _ParseArgs(args):
options.values_filter_rules)
options.extra_main_r_text_files = build_utils.ParseGnList(
options.extra_main_r_text_files)
options.resources_config_paths = build_utils.ParseGnList(
options.resources_config_paths)

if options.optimized_proto_path and not options.proto_path:
# We could write to a temp file, but it's simpler to require it.
parser.error('--optimized-proto-path requires --proto-path')

if not options.arsc_path and not options.proto_path:
parser.error('One of --arsc-path or --proto-path is required.')

if options.resources_path_map_out_path and not options.short_resource_paths:
parser.error(
'--resources-path-map-out-path requires --short-resource-paths')

if options.package_id and options.shared_resources:
parser.error('--package-id and --shared-resources are mutually exclusive')

Expand Down Expand Up @@ -846,9 +812,6 @@ def _PackageApk(options, build):

# We always create a binary arsc file first, then convert to proto, so flags
# such as --shared-lib can be supported.
arsc_path = build.arsc_path
if arsc_path is None:
_, arsc_path = tempfile.mkstmp()
link_command += ['-o', build.arsc_path]

logging.debug('Starting: aapt2 link')
Expand Down Expand Up @@ -896,100 +859,9 @@ def _PackageApk(options, build):
build.arsc_path, build.proto_path
])

if build.arsc_path is None:
os.remove(arsc_path)

if options.optimized_proto_path:
_OptimizeApk(build.optimized_proto_path, options, build.temp_dir,
build.proto_path, build.r_txt_path)
elif options.optimized_arsc_path:
_OptimizeApk(build.optimized_arsc_path, options, build.temp_dir,
build.arsc_path, build.r_txt_path)

return desired_manifest_package_name


def _CombineResourceConfigs(resources_config_paths, out_config_path):
with open(out_config_path, 'w') as out_config:
for config_path in resources_config_paths:
with open(config_path) as config:
out_config.write(config.read())
out_config.write('\n')


def _OptimizeApk(output, options, temp_dir, unoptimized_path, r_txt_path):
"""Optimize intermediate .ap_ file with aapt2.
Args:
output: Path to write to.
options: The command-line options.
temp_dir: A temporary directory.
unoptimized_path: path of the apk to optimize.
r_txt_path: path to the R.txt file of the unoptimized apk.
"""
optimize_command = [
options.aapt2_path,
'optimize',
unoptimized_path,
'-o',
output,
]

# Optimize the resources.arsc file by obfuscating resource names and only
# allow usage via R.java constant.
if options.strip_resource_names:
no_collapse_resources = _ExtractNonCollapsableResources(r_txt_path)
gen_config_path = os.path.join(temp_dir, 'aapt2.config')
if options.resources_config_paths:
_CombineResourceConfigs(options.resources_config_paths, gen_config_path)
with open(gen_config_path, 'a') as config:
for resource in no_collapse_resources:
config.write('{}#no_collapse\n'.format(resource))

optimize_command += [
'--collapse-resource-names',
'--resources-config-path',
gen_config_path,
]

if options.short_resource_paths:
optimize_command += ['--shorten-resource-paths']
if options.resources_path_map_out_path:
optimize_command += [
'--resource-path-shortening-map', options.resources_path_map_out_path
]

logging.debug('Running aapt2 optimize')
build_utils.CheckOutput(
optimize_command, print_stdout=False, print_stderr=False)


def _ExtractNonCollapsableResources(rtxt_path):
"""Extract resources that should not be collapsed from the R.txt file
Resources of type ID are references to UI elements/views. They are used by
UI automation testing frameworks. They are kept in so that they don't break
tests, even though they may not actually be used during runtime. See
https://crbug.com/900993
App icons (aka mipmaps) are sometimes referenced by other apps by name so must
be keps as well. See https://b/161564466
Args:
rtxt_path: Path to R.txt file with all the resources
Returns:
List of resources in the form of <resource_type>/<resource_name>
"""
resources = []
_NO_COLLAPSE_TYPES = ['id', 'mipmap']
with open(rtxt_path) as rtxt:
for line in rtxt:
for resource_type in _NO_COLLAPSE_TYPES:
if ' {} '.format(resource_type) in line:
resource_name = line.split()[2]
resources.append('{}/{}'.format(resource_type, resource_name))
return resources


@contextlib.contextmanager
def _CreateStableIdsFile(in_path, out_path, package_name):
"""Transforms a file generated by --emit-ids from another package.
Expand Down Expand Up @@ -1018,8 +890,6 @@ def _WriteOutputs(options, build):
(options.r_text_out, build.r_txt_path),
(options.arsc_path, build.arsc_path),
(options.proto_path, build.proto_path),
(options.optimized_arsc_path, build.optimized_arsc_path),
(options.optimized_proto_path, build.optimized_proto_path),
(options.proguard_file, build.proguard_path),
(options.proguard_file_main_dex, build.proguard_main_dex_path),
(options.emit_ids_out, build.emit_ids_path),
Expand Down
151 changes: 151 additions & 0 deletions build/android/gyp/optimize_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
#
# Copyright 2021 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import argparse
import logging
import os
import sys

from util import build_utils


def _ParseArgs(args):
"""Parses command line options.
Returns:
An options object as from argparse.ArgumentParser.parse_args()
"""
parser = argparse.ArgumentParser()
parser.add_argument('--aapt2-path',
required=True,
help='Path to the Android aapt2 tool.')
parser.add_argument(
'--short-resource-paths',
action='store_true',
help='Whether to shorten resource paths inside the apk or module.')
parser.add_argument(
'--strip-resource-names',
action='store_true',
help='Whether to strip resource names from the resource table of the apk '
'or module.')
parser.add_argument('--proto-path',
required=True,
help='Input proto format resources APK.')
parser.add_argument('--resources-config-paths',
default='[]',
help='GN list of paths to aapt2 resources config files.')
parser.add_argument('--r-text-in',
required=True,
help='Path to R.txt. Used to exclude id/ resources.')
parser.add_argument(
'--resources-path-map-out-path',
help='Path to file produced by aapt2 that maps original resource paths '
'to shortened resource paths inside the apk or module.')
parser.add_argument('--optimized-proto-path',
required=True,
help='Output for `aapt2 optimize`.')
options = parser.parse_args(args)

options.resources_config_paths = build_utils.ParseGnList(
options.resources_config_paths)

if options.resources_path_map_out_path and not options.short_resource_paths:
parser.error(
'--resources-path-map-out-path requires --short-resource-paths')
return options


def _CombineResourceConfigs(resources_config_paths, out_config_path):
with open(out_config_path, 'w') as out_config:
for config_path in resources_config_paths:
with open(config_path) as config:
out_config.write(config.read())
out_config.write('\n')


def _ExtractNonCollapsableResources(rtxt_path):
"""Extract resources that should not be collapsed from the R.txt file
Resources of type ID are references to UI elements/views. They are used by
UI automation testing frameworks. They are kept in so that they don't break
tests, even though they may not actually be used during runtime. See
https://crbug.com/900993
App icons (aka mipmaps) are sometimes referenced by other apps by name so must
be keps as well. See https://b/161564466
Args:
rtxt_path: Path to R.txt file with all the resources
Returns:
List of resources in the form of <resource_type>/<resource_name>
"""
resources = []
_NO_COLLAPSE_TYPES = ['id', 'mipmap']
with open(rtxt_path) as rtxt:
for line in rtxt:
for resource_type in _NO_COLLAPSE_TYPES:
if ' {} '.format(resource_type) in line:
resource_name = line.split()[2]
resources.append('{}/{}'.format(resource_type, resource_name))
return resources


def _OptimizeApk(output, options, temp_dir, unoptimized_path, r_txt_path):
"""Optimize intermediate .ap_ file with aapt2.
Args:
output: Path to write to.
options: The command-line options.
temp_dir: A temporary directory.
unoptimized_path: path of the apk to optimize.
r_txt_path: path to the R.txt file of the unoptimized apk.
"""
optimize_command = [
options.aapt2_path,
'optimize',
unoptimized_path,
'-o',
output,
]

# Optimize the resources.pb file by obfuscating resource names and only
# allow usage via R.java constant.
if options.strip_resource_names:
no_collapse_resources = _ExtractNonCollapsableResources(r_txt_path)
gen_config_path = os.path.join(temp_dir, 'aapt2.config')
if options.resources_config_paths:
_CombineResourceConfigs(options.resources_config_paths, gen_config_path)
with open(gen_config_path, 'a') as config:
for resource in no_collapse_resources:
config.write('{}#no_collapse\n'.format(resource))

optimize_command += [
'--collapse-resource-names',
'--resources-config-path',
gen_config_path,
]

if options.short_resource_paths:
optimize_command += ['--shorten-resource-paths']
if options.resources_path_map_out_path:
optimize_command += [
'--resource-path-shortening-map', options.resources_path_map_out_path
]

logging.debug('Running aapt2 optimize')
build_utils.CheckOutput(optimize_command,
print_stdout=False,
print_stderr=False)


def main(args):
options = _ParseArgs(args)
with build_utils.TempDir() as temp_dir:
_OptimizeApk(options.optimized_proto_path, options, temp_dir,
options.proto_path, options.r_text_in)


if __name__ == '__main__':
main(sys.argv[1:])
Empty file.
30 changes: 0 additions & 30 deletions build/android/gyp/resources_shrinker/shrinker.pydeps

This file was deleted.

Loading

0 comments on commit 246710c

Please sign in to comment.