diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-03-05 17:34:47 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-03-06 10:04:14 +0000 |
commit | eaf1da4d961fbbda9455f9af3b23d1af777f43fa (patch) | |
tree | 95970599ecee31c4f7f940bc97ac98c61a3d0cad /chromium/build/android/gyp | |
parent | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (diff) |
BASELINE: Update Chromium to 73.0.3683.64
Change-Id: I76517dc277ba4e16bfd7e098fda3d079656b3b9f
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/build/android/gyp')
-rwxr-xr-x | chromium/build/android/gyp/apkbuilder.py | 298 | ||||
-rwxr-xr-x | chromium/build/android/gyp/assert_static_initializers.py | 117 | ||||
-rw-r--r-- | chromium/build/android/gyp/assert_static_initializers.pydeps | 7 | ||||
-rwxr-xr-x | chromium/build/android/gyp/bundletool.py | 2 | ||||
-rwxr-xr-x | chromium/build/android/gyp/compile_resources.py | 2 | ||||
-rwxr-xr-x | chromium/build/android/gyp/create_app_bundle_minimal_apks.py | 46 | ||||
-rw-r--r-- | chromium/build/android/gyp/create_app_bundle_minimal_apks.pydeps | 11 | ||||
-rwxr-xr-x | chromium/build/android/gyp/create_size_info_files.py | 167 | ||||
-rw-r--r-- | chromium/build/android/gyp/create_size_info_files.pydeps (renamed from chromium/build/android/gyp/merge_jar_info_files.pydeps) | 4 | ||||
-rwxr-xr-x | chromium/build/android/gyp/javac.py | 24 | ||||
-rwxr-xr-x | chromium/build/android/gyp/merge_jar_info_files.py | 99 | ||||
-rw-r--r-- | chromium/build/android/gyp/util/build_utils.py | 35 | ||||
-rw-r--r-- | chromium/build/android/gyp/util/jar_info_utils.py | 17 | ||||
-rwxr-xr-x | chromium/build/android/gyp/write_build_config.py | 7 |
14 files changed, 508 insertions, 328 deletions
diff --git a/chromium/build/android/gyp/apkbuilder.py b/chromium/build/android/gyp/apkbuilder.py index b5097aafb0c..9ffb137ec00 100755 --- a/chromium/build/android/gyp/apkbuilder.py +++ b/chromium/build/android/gyp/apkbuilder.py @@ -30,19 +30,18 @@ _NO_COMPRESS_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.gif', '.wav', '.mp2', def _ParseArgs(args): parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) - parser.add_argument('--assets', - help='GYP-list of files to add as assets in the form ' - '"srcPath:zipPath", where ":zipPath" is optional.', - default='[]') - parser.add_argument('--java-resources', - help='GYP-list of java_resources JARs to include.', - default='[]') + parser.add_argument( + '--assets', + help='GYP-list of files to add as assets in the form ' + '"srcPath:zipPath", where ":zipPath" is optional.') + parser.add_argument( + '--java-resources', help='GYP-list of java_resources JARs to include.') parser.add_argument('--write-asset-list', action='store_true', help='Whether to create an assets/assets_list file.') - parser.add_argument('--uncompressed-assets', - help='Same as --assets, except disables compression.', - default='[]') + parser.add_argument( + '--uncompressed-assets', + help='Same as --assets, except disables compression.') parser.add_argument('--resource-apk', help='An .ap_ file built using aapt', required=True) @@ -51,10 +50,6 @@ def _ParseArgs(args): required=True) parser.add_argument('--format', choices=['apk', 'bundle-module'], default='apk', help='Specify output format.') - parser.add_argument('--apk-pak-info-path', - help='Path to the *.apk.pak.info file') - parser.add_argument('--apk-res-info-path', - help='Path to the *.apk.res.info file') parser.add_argument('--dex-file', help='Path to the classes.dex to use') parser.add_argument('--uncompress-dex', action='store_true', @@ -74,13 +69,13 @@ def _ParseArgs(args): parser.add_argument('--secondary-android-abi', help='The secondary Android architecture to use for' 'secondary native libraries') - parser.add_argument('--native-lib-placeholders', - help='GYP-list of native library placeholders to add.', - default='[]') - parser.add_argument('--secondary-native-lib-placeholders', - help='GYP-list of native library placeholders to add ' - 'for the secondary ABI', - default='[]') + parser.add_argument( + '--native-lib-placeholders', + help='GYP-list of native library placeholders to add.') + parser.add_argument( + '--secondary-native-lib-placeholders', + help='GYP-list of native library placeholders to add ' + 'for the secondary ABI') parser.add_argument('--uncompress-shared-libraries', default='False', choices=['true', 'True', 'false', 'False'], help='Whether to uncompress native shared libraries. Argument must be ' @@ -226,31 +221,12 @@ def _AddNativeLibraries(out_apk, native_libs, android_abi, uncompress): compress=compress) -def _MergeResInfoFiles(res_info_path, resource_apk): - resource_apk_info_path = resource_apk + '.info' - shutil.copy(resource_apk_info_path, res_info_path) - - -def _FilterPakInfoPaths(assets): - return [f.split(':')[0] + '.info' for f in assets if f.endswith('.pak')] - - -def _MergePakInfoFiles(merged_path, pak_infos): - info_lines = set() - for pak_info_path in pak_infos: - with open(pak_info_path, 'r') as src_info_file: - info_lines.update(src_info_file.readlines()) - with open(merged_path, 'w') as merged_info_file: - merged_info_file.writelines(sorted(info_lines)) - - def main(args): args = build_utils.ExpandFileArgs(args) options = _ParseArgs(args) native_libs = sorted(options.native_libs) - input_paths = [options.resource_apk, __file__] # Include native libs in the depfile_deps since GN doesn't know about the # dependencies when is_component_build=true. depfile_deps = list(native_libs) @@ -260,17 +236,6 @@ def main(args): secondary_native_libs = sorted(options.secondary_native_libs) depfile_deps += secondary_native_libs - if options.dex_file: - input_paths.append(options.dex_file) - - input_strings = [options.android_abi, - options.native_lib_placeholders, - options.secondary_native_lib_placeholders, - str(options.uncompress_shared_libraries)] - - if options.secondary_android_abi: - input_strings.append(options.secondary_android_abi) - if options.java_resources: # Included via .build_config, so need to write it to depfile. depfile_deps.extend(options.java_resources) @@ -278,21 +243,9 @@ def main(args): assets = _ExpandPaths(options.assets) uncompressed_assets = _ExpandPaths(options.uncompressed_assets) - if options.apk_pak_info_path: - pak_infos = _FilterPakInfoPaths( - options.assets + options.uncompressed_assets) - depfile_deps.extend(pak_infos) - - for src_path, dest_path in itertools.chain(assets, uncompressed_assets): - # Included via .build_config, so need to write it to depfile. - depfile_deps.append(src_path) - input_strings.append(dest_path) - - output_paths = [options.output_apk] - if options.apk_pak_info_path: - output_paths.append(options.apk_pak_info_path) - if options.apk_res_info_path: - output_paths.append(options.apk_res_info_path) + # Included via .build_config, so need to write it to depfile. + depfile_deps.extend(x[0] for x in assets) + depfile_deps.extend(x[0] for x in uncompressed_assets) # Bundle modules have a structure similar to APKs, except that resources # are compiled in protobuf format (instead of binary xml), and that some @@ -314,119 +267,110 @@ def main(args): apk_root_dir = '' apk_dex_dir = '' - def on_stale_md5(): - with tempfile.NamedTemporaryFile() as tmp_apk: - tmp_file = tmp_apk.name - with zipfile.ZipFile(options.resource_apk) as resource_apk, \ - zipfile.ZipFile(tmp_file, 'w', zipfile.ZIP_DEFLATED) as out_apk: - def copy_resource(zipinfo, out_dir=''): - compress = zipinfo.compress_type != zipfile.ZIP_STORED - build_utils.AddToZipHermetic(out_apk, out_dir + zipinfo.filename, - data=resource_apk.read(zipinfo.filename), - compress=compress) - - # Make assets come before resources in order to maintain the same file - # ordering as GYP / aapt. http://crbug.com/561862 - resource_infos = resource_apk.infolist() - - # 1. AndroidManifest.xml - copy_resource( - resource_apk.getinfo('AndroidManifest.xml'), - out_dir=apk_manifest_dir) - - # 2. Assets - if options.write_asset_list: - data = _CreateAssetsList( - itertools.chain(assets, uncompressed_assets)) - build_utils.AddToZipHermetic(out_apk, 'assets/assets_list', data=data) - - _AddAssets(out_apk, assets, disable_compression=False) - _AddAssets(out_apk, uncompressed_assets, disable_compression=True) - - # 3. Dex files - if options.dex_file and options.dex_file.endswith('.zip'): - with zipfile.ZipFile(options.dex_file, 'r') as dex_zip: - for dex in (d for d in dex_zip.namelist() if d.endswith('.dex')): - build_utils.AddToZipHermetic(out_apk, apk_dex_dir + dex, - data=dex_zip.read(dex), - compress=not options.uncompress_dex) - elif options.dex_file: - build_utils.AddToZipHermetic(out_apk, apk_dex_dir + 'classes.dex', - src_path=options.dex_file, - compress=not options.uncompress_dex) - - # 4. Native libraries. - _AddNativeLibraries(out_apk, - native_libs, - options.android_abi, + # Targets generally do not depend on apks, so no need for only_if_changed. + with build_utils.AtomicOutput(options.output_apk, only_if_changed=False) as f: + with zipfile.ZipFile(options.resource_apk) as resource_apk, \ + zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as out_apk: + + def copy_resource(zipinfo, out_dir=''): + compress = zipinfo.compress_type != zipfile.ZIP_STORED + build_utils.AddToZipHermetic( + out_apk, + out_dir + zipinfo.filename, + data=resource_apk.read(zipinfo.filename), + compress=compress) + + # Make assets come before resources in order to maintain the same file + # ordering as GYP / aapt. http://crbug.com/561862 + resource_infos = resource_apk.infolist() + + # 1. AndroidManifest.xml + copy_resource( + resource_apk.getinfo('AndroidManifest.xml'), out_dir=apk_manifest_dir) + + # 2. Assets + if options.write_asset_list: + data = _CreateAssetsList(itertools.chain(assets, uncompressed_assets)) + build_utils.AddToZipHermetic(out_apk, 'assets/assets_list', data=data) + + _AddAssets(out_apk, assets, disable_compression=False) + _AddAssets(out_apk, uncompressed_assets, disable_compression=True) + + # 3. Dex files + if options.dex_file and options.dex_file.endswith('.zip'): + with zipfile.ZipFile(options.dex_file, 'r') as dex_zip: + for dex in (d for d in dex_zip.namelist() if d.endswith('.dex')): + build_utils.AddToZipHermetic( + out_apk, + apk_dex_dir + dex, + data=dex_zip.read(dex), + compress=not options.uncompress_dex) + elif options.dex_file: + build_utils.AddToZipHermetic( + out_apk, + apk_dex_dir + 'classes.dex', + src_path=options.dex_file, + compress=not options.uncompress_dex) + + # 4. Native libraries. + _AddNativeLibraries(out_apk, native_libs, options.android_abi, + options.uncompress_shared_libraries) + + if options.secondary_android_abi: + _AddNativeLibraries(out_apk, secondary_native_libs, + options.secondary_android_abi, options.uncompress_shared_libraries) - if options.secondary_android_abi: - _AddNativeLibraries(out_apk, - secondary_native_libs, - options.secondary_android_abi, - options.uncompress_shared_libraries) - - for name in sorted(options.native_lib_placeholders): - # Note: Empty libs files are ignored by md5check (can cause issues - # with stale builds when the only change is adding/removing - # placeholders). - apk_path = 'lib/%s/%s' % (options.android_abi, name) - build_utils.AddToZipHermetic(out_apk, apk_path, data='') - - for name in sorted(options.secondary_native_lib_placeholders): - # Note: Empty libs files are ignored by md5check (can cause issues - # with stale builds when the only change is adding/removing - # placeholders). - apk_path = 'lib/%s/%s' % (options.secondary_android_abi, name) - build_utils.AddToZipHermetic(out_apk, apk_path, data='') - - # 5. Resources - for info in resource_infos: - if info.filename != 'AndroidManifest.xml': - copy_resource(info) - - # 6. Java resources that should be accessible via - # Class.getResourceAsStream(), in particular parts of Emma jar. - # Prebuilt jars may contain class files which we shouldn't include. - for java_resource in options.java_resources: - with zipfile.ZipFile(java_resource, 'r') as java_resource_jar: - for apk_path in java_resource_jar.namelist(): - apk_path_lower = apk_path.lower() - - if apk_path_lower.startswith('meta-inf/'): - continue - if apk_path_lower.endswith('/'): - continue - if apk_path_lower.endswith('.class'): - continue - - build_utils.AddToZipHermetic( - out_apk, apk_root_dir + apk_path, - data=java_resource_jar.read(apk_path)) - - if options.apk_pak_info_path: - _MergePakInfoFiles(options.apk_pak_info_path, pak_infos) - if options.apk_res_info_path: - _MergeResInfoFiles(options.apk_res_info_path, options.resource_apk) - - if options.format == 'apk': - finalize_apk.FinalizeApk(options.apksigner_path, options.zipalign_path, - tmp_file, options.output_apk, - options.key_path, options.key_passwd, - options.key_name) - else: - shutil.move(tmp_file, options.output_apk) - tmp_apk.delete = False - - build_utils.CallAndWriteDepfileIfStale( - on_stale_md5, - options, - input_paths=input_paths + depfile_deps, - input_strings=input_strings, - output_paths=output_paths, - depfile_deps=depfile_deps, - add_pydeps=False) + for name in sorted(options.native_lib_placeholders): + # Note: Empty libs files are ignored by md5check (can cause issues + # with stale builds when the only change is adding/removing + # placeholders). + apk_path = 'lib/%s/%s' % (options.android_abi, name) + build_utils.AddToZipHermetic(out_apk, apk_path, data='') + + for name in sorted(options.secondary_native_lib_placeholders): + # Note: Empty libs files are ignored by md5check (can cause issues + # with stale builds when the only change is adding/removing + # placeholders). + apk_path = 'lib/%s/%s' % (options.secondary_android_abi, name) + build_utils.AddToZipHermetic(out_apk, apk_path, data='') + + # 5. Resources + for info in resource_infos: + if info.filename != 'AndroidManifest.xml': + copy_resource(info) + + # 6. Java resources that should be accessible via + # Class.getResourceAsStream(), in particular parts of Emma jar. + # Prebuilt jars may contain class files which we shouldn't include. + for java_resource in options.java_resources: + with zipfile.ZipFile(java_resource, 'r') as java_resource_jar: + for apk_path in java_resource_jar.namelist(): + apk_path_lower = apk_path.lower() + + if apk_path_lower.startswith('meta-inf/'): + continue + if apk_path_lower.endswith('/'): + continue + if apk_path_lower.endswith('.class'): + continue + + build_utils.AddToZipHermetic( + out_apk, + apk_root_dir + apk_path, + data=java_resource_jar.read(apk_path)) + + if options.format == 'apk': + finalize_apk.FinalizeApk(options.apksigner_path, options.zipalign_path, + f.name, f.name, options.key_path, + options.key_passwd, options.key_name) + + if options.depfile: + build_utils.WriteDepfile( + options.depfile, + options.output_apk, + inputs=depfile_deps, + add_pydeps=False) if __name__ == '__main__': diff --git a/chromium/build/android/gyp/assert_static_initializers.py b/chromium/build/android/gyp/assert_static_initializers.py index 717861b77c9..019baface15 100755 --- a/chromium/build/android/gyp/assert_static_initializers.py +++ b/chromium/build/android/gyp/assert_static_initializers.py @@ -7,17 +7,116 @@ import argparse import os +import re +import subprocess import sys - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -import resource_sizes +import tempfile +import zipfile from util import build_utils +_DUMP_STATIC_INITIALIZERS_PATH = os.path.join(build_utils.DIR_SOURCE_ROOT, + 'tools', 'linux', + 'dump-static-initializers.py') + + +def _RunReadelf(so_path, options, tool_prefix=''): + return subprocess.check_output([tool_prefix + 'readelf'] + options + + [so_path]) + + +def _ParseLibBuildId(so_path, tool_prefix): + """Returns the Build ID of the given native library.""" + stdout = _RunReadelf(so_path, ['-n'], tool_prefix) + match = re.search(r'Build ID: (\w+)', stdout) + return match.group(1) if match else None + + +def _VerifyLibBuildIdsMatch(tool_prefix, *so_files): + if len(set(_ParseLibBuildId(f, tool_prefix) for f in so_files)) > 1: + raise Exception('Found differing build ids in output directory and apk. ' + 'Your output directory is likely stale.') + + +def _GetStaticInitializers(so_path, tool_prefix): + output = subprocess.check_output( + [_DUMP_STATIC_INITIALIZERS_PATH, '-d', so_path, '-t', tool_prefix]) + summary = re.search(r'Found \d+ static initializers in (\d+) files.', output) + return output.splitlines()[:-1], int(summary.group(1)) + + +def _PrintDumpSIsCount(apk_so_name, unzipped_so, out_dir, tool_prefix): + lib_name = os.path.basename(apk_so_name).replace('crazy.', '') + so_with_symbols_path = os.path.join(out_dir, 'lib.unstripped', lib_name) + if not os.path.exists(so_with_symbols_path): + raise Exception('Unstripped .so not found. Looked here: %s', + so_with_symbols_path) + _VerifyLibBuildIdsMatch(tool_prefix, unzipped_so, so_with_symbols_path) + sis, _ = _GetStaticInitializers(so_with_symbols_path, tool_prefix) + for si in sis: + print si + + +# Mostly copied from //infra/scripts/legacy/scripts/slave/chromium/sizes.py. +def _ReadInitArray(so_path, tool_prefix): + stdout = _RunReadelf(so_path, ['-SW'], tool_prefix) + # Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8 + match = re.search(r'\.init_array.*$', stdout, re.MULTILINE) + if not match: + raise Exception('Did not find section: .init_array in:\n' + stdout) + size_str = re.split(r'\W+', match.group(0))[5] + return int(size_str, 16) + + +def _CountStaticInitializers(so_path, tool_prefix): + # Find the number of files with at least one static initializer. + # First determine if we're 32 or 64 bit + stdout = _RunReadelf(so_path, ['-h'], tool_prefix) + elf_class_line = re.search('Class:.*$', stdout, re.MULTILINE).group(0) + elf_class = re.split(r'\W+', elf_class_line)[1] + if elf_class == 'ELF32': + word_size = 4 + else: + word_size = 8 + + # Then find the number of files with global static initializers. + # NOTE: this is very implementation-specific and makes assumptions + # about how compiler and linker implement global static initializers. + init_array_size = _ReadInitArray(so_path, tool_prefix) + return init_array_size / word_size + + +def _AnalyzeStaticInitializers(apk_filename, tool_prefix, dump_sis, out_dir, + ignored_libs): + # Static initializer counting mostly copies logic in + # infra/scripts/legacy/scripts/slave/chromium/sizes.py. + with zipfile.ZipFile(apk_filename) as z: + so_files = [ + f for f in z.infolist() if f.filename.endswith('.so') + and f.file_size > 0 and os.path.basename(f.filename) not in ignored_libs + ] + # Skip checking static initializers for secondary abi libs. They will be + # checked by 32-bit bots. This avoids the complexity of finding 32 bit .so + # files in the output directory in 64 bit builds. + has_64 = any('64' in f.filename for f in so_files) + files_to_check = [f for f in so_files if not has_64 or '64' in f.filename] + + si_count = 0 + for f in files_to_check: + with tempfile.NamedTemporaryFile() as temp: + temp.write(z.read(f)) + temp.flush() + si_count += _CountStaticInitializers(temp.name, tool_prefix) + if dump_sis: + # Print count and list of SIs reported by dump-static-initializers.py. + # Doesn't work well on all archs (particularly arm), which is why + # the readelf method is used for tracking SI counts. + _PrintDumpSIsCount(f.filename, temp.name, out_dir, tool_prefix) + return si_count + def main(): parser = argparse.ArgumentParser() - build_utils.AddDepfileOption(parser) parser.add_argument('--touch', help='File to touch upon success') parser.add_argument('--tool-prefix', required=True, help='Prefix for nm and friends') @@ -30,8 +129,8 @@ def main(): #TODO(crbug.com/838414): add support for files included via loadable_modules. ignored_libs = ['libarcore_sdk_c.so'] - si_count = resource_sizes.AnalyzeStaticInitializers( - args.apk, args.tool_prefix, False, '.', ignored_libs) + si_count = _AnalyzeStaticInitializers(args.apk, args.tool_prefix, False, '.', + ignored_libs) if si_count != args.expected_count: print 'Expected {} static initializers, but found {}.'.format( args.expected_count, si_count) @@ -42,8 +141,8 @@ def main(): else: print 'Dumping static initializers via dump-static-initializers.py:' sys.stdout.flush() - resource_sizes.AnalyzeStaticInitializers( - args.apk, args.tool_prefix, True, '.', ignored_libs) + _AnalyzeStaticInitializers(args.apk, args.tool_prefix, True, '.', + ignored_libs) print print 'If the above list is not useful, consider listing them with:' print ' //tools/binary_size/diagnose_bloat.py' @@ -53,8 +152,6 @@ def main(): 'static_initializers.md') sys.exit(1) - if args.depfile: - build_utils.WriteDepfile(args.depfile, args.touch) if args.touch: open(args.touch, 'w') diff --git a/chromium/build/android/gyp/assert_static_initializers.pydeps b/chromium/build/android/gyp/assert_static_initializers.pydeps new file mode 100644 index 00000000000..e031668f467 --- /dev/null +++ b/chromium/build/android/gyp/assert_static_initializers.pydeps @@ -0,0 +1,7 @@ +# Generated by running: +# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/assert_static_initializers.pydeps build/android/gyp/assert_static_initializers.py +../../gn_helpers.py +assert_static_initializers.py +util/__init__.py +util/build_utils.py +util/md5_check.py diff --git a/chromium/build/android/gyp/bundletool.py b/chromium/build/android/gyp/bundletool.py index 1709b936d98..3ac9cddec35 100755 --- a/chromium/build/android/gyp/bundletool.py +++ b/chromium/build/android/gyp/bundletool.py @@ -8,6 +8,7 @@ Bundletool is distributed as a versioned jar file. This script abstracts the location and version of this jar file, as well as the JVM invokation.""" +import logging import os import subprocess import sys @@ -24,6 +25,7 @@ BUNDLETOOL_JAR_PATH = os.path.join( def RunBundleTool(args): args = ['java', '-jar', BUNDLETOOL_JAR_PATH] + args + logging.debug(' '.join(args)) subprocess.check_call(args) if __name__ == '__main__': diff --git a/chromium/build/android/gyp/compile_resources.py b/chromium/build/android/gyp/compile_resources.py index 72ff6fe1f4f..15381e8efca 100755 --- a/chromium/build/android/gyp/compile_resources.py +++ b/chromium/build/android/gyp/compile_resources.py @@ -653,7 +653,7 @@ def _CreateResourceInfoFile( lines.update(zip_info_file.readlines()) for dest, source in renamed_paths.iteritems(): lines.add('Rename:{},{}\n'.format(dest, source)) - with open(apk_info_path, 'w') as info_file: + with build_utils.AtomicOutput(apk_info_path) as info_file: info_file.writelines(sorted(lines)) diff --git a/chromium/build/android/gyp/create_app_bundle_minimal_apks.py b/chromium/build/android/gyp/create_app_bundle_minimal_apks.py new file mode 100755 index 00000000000..f01691e418f --- /dev/null +++ b/chromium/build/android/gyp/create_app_bundle_minimal_apks.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. + +"""Creates an .apks from an .aab with only English strings.""" + +import argparse +import os +import sys + +sys.path.append( + os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))) +from pylib.utils import app_bundle_utils + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + '--bundle', required=True, help='Path to input .aab file.') + parser.add_argument( + '--output', required=True, help='Path to output .apks file.') + parser.add_argument('--aapt2-path', required=True, help='Path to aapt2.') + parser.add_argument( + '--keystore-path', required=True, help='Path to keystore.') + parser.add_argument( + '--keystore-password', required=True, help='Keystore password.') + parser.add_argument( + '--keystore-name', required=True, help='Key name within keystore') + + args = parser.parse_args() + + app_bundle_utils.GenerateBundleApks( + args.bundle, + args.output, + args.aapt2_path, + args.keystore_path, + args.keystore_password, + args.keystore_name, + minimal=True, + check_for_noop=False) + + +if __name__ == '__main__': + main() diff --git a/chromium/build/android/gyp/create_app_bundle_minimal_apks.pydeps b/chromium/build/android/gyp/create_app_bundle_minimal_apks.pydeps new file mode 100644 index 00000000000..7cf09fdc174 --- /dev/null +++ b/chromium/build/android/gyp/create_app_bundle_minimal_apks.pydeps @@ -0,0 +1,11 @@ +# Generated by running: +# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/create_app_bundle_minimal_apks.pydeps build/android/gyp/create_app_bundle_minimal_apks.py +../../gn_helpers.py +../pylib/__init__.py +../pylib/utils/__init__.py +../pylib/utils/app_bundle_utils.py +bundletool.py +create_app_bundle_minimal_apks.py +util/__init__.py +util/build_utils.py +util/md5_check.py diff --git a/chromium/build/android/gyp/create_size_info_files.py b/chromium/build/android/gyp/create_size_info_files.py new file mode 100755 index 00000000000..5b248e41956 --- /dev/null +++ b/chromium/build/android/gyp/create_size_info_files.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python + +# Copyright 2018 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. + +"""Creates size-info/*.info files used by SuperSize.""" + +import argparse +import os +import sys +import zipfile + +from util import build_utils +from util import jar_info_utils +from util import md5_check + + +def _MergeResInfoFiles(res_info_path, info_paths): + # Concatenate them all. + # only_if_changed=False since no build rules depend on this as an input. + with build_utils.AtomicOutput(res_info_path, only_if_changed=False) as dst: + for p in info_paths: + with open(p) as src: + dst.write(src.read()) + + +def _PakInfoPathsForAssets(assets): + return [f.split(':')[0] + '.info' for f in assets if f.endswith('.pak')] + + +def _MergePakInfoFiles(merged_path, pak_infos): + info_lines = set() + for pak_info_path in pak_infos: + with open(pak_info_path, 'r') as src_info_file: + info_lines.update(src_info_file.readlines()) + # only_if_changed=False since no build rules depend on this as an input. + with build_utils.AtomicOutput(merged_path, only_if_changed=False) as f: + f.writelines(sorted(info_lines)) + + +def _FullJavaNameFromClassFilePath(path): + # Input: base/android/java/src/org/chromium/Foo.class + # Output: base.android.java.src.org.chromium.Foo + if not path.endswith('.class'): + return '' + path = os.path.splitext(path)[0] + parts = [] + while path: + # Use split to be platform independent. + head, tail = os.path.split(path) + path = head + parts.append(tail) + parts.reverse() # Package comes first + return '.'.join(parts) + + +def _MergeJarInfoFiles(output, inputs): + """Merge several .jar.info files to generate an .apk.jar.info. + + Args: + output: output file path. + inputs: List of .info.jar or .jar files. + """ + info_data = dict() + for path in inputs: + # android_java_prebuilt adds jar files in the src directory (relative to + # the output directory, usually ../../third_party/example.jar). + # android_aar_prebuilt collects jar files in the aar file and uses the + # java_prebuilt rule to generate gen/example/classes.jar files. + # We scan these prebuilt jars to parse each class path for the FQN. This + # allows us to later map these classes back to their respective src + # directories. + # TODO(agrieve): This should probably also check that the mtime of the .info + # is newer than that of the .jar, or change prebuilts to always output + # .info files so that they always exist (and change the depfile to + # depend directly on them). + if path.endswith('.info'): + info_data.update(jar_info_utils.ParseJarInfoFile(path)) + else: + with zipfile.ZipFile(path) as zip_info: + for name in zip_info.namelist(): + fully_qualified_name = _FullJavaNameFromClassFilePath(name) + if fully_qualified_name: + info_data[fully_qualified_name] = '{}/{}'.format(path, name) + + # only_if_changed=False since no build rules depend on this as an input. + with build_utils.AtomicOutput(output, only_if_changed=False) as f: + jar_info_utils.WriteJarInfoFile(f, info_data) + + +def _FindJarInputs(jar_paths): + ret = [] + for jar_path in jar_paths: + jar_info_path = jar_path + '.info' + if os.path.exists(jar_info_path): + ret.append(jar_info_path) + else: + ret.append(jar_path) + return ret + + +def main(args): + args = build_utils.ExpandFileArgs(args) + parser = argparse.ArgumentParser(description=__doc__) + build_utils.AddDepfileOption(parser) + parser.add_argument( + '--jar-info-path', required=True, help='Output .jar.info file') + parser.add_argument( + '--pak-info-path', required=True, help='Output .pak.info file') + parser.add_argument( + '--res-info-path', required=True, help='Output .res.info file') + parser.add_argument( + '--jar-files', + required=True, + action='append', + help='GN-list of .jar file paths') + parser.add_argument( + '--assets', + required=True, + action='append', + help='GN-list of files to add as assets in the form ' + '"srcPath:zipPath", where ":zipPath" is optional.') + parser.add_argument( + '--uncompressed-assets', + required=True, + action='append', + help='Same as --assets, except disables compression.') + parser.add_argument( + '--resource-apk', + dest='resource_apks', + required=True, + action='append', + help='An .ap_ file built using aapt') + + options = parser.parse_args(args) + + options.jar_files = build_utils.ParseGnList(options.jar_files) + options.assets = build_utils.ParseGnList(options.assets) + options.uncompressed_assets = build_utils.ParseGnList( + options.uncompressed_assets) + + jar_inputs = _FindJarInputs(set(options.jar_files)) + pak_inputs = _PakInfoPathsForAssets(options.assets + + options.uncompressed_assets) + res_inputs = [p + '.info' for p in options.resource_apks] + + # Don't bother re-running if no .info files have changed (saves ~250ms). + md5_check.CallAndRecordIfStale( + lambda: _MergeJarInfoFiles(options.jar_info_path, jar_inputs), + input_paths=jar_inputs, + output_paths=[options.jar_info_path]) + + # Always recreate these (just as fast as md5 checking them). + _MergePakInfoFiles(options.pak_info_path, pak_inputs) + _MergeResInfoFiles(options.res_info_path, res_inputs) + + all_inputs = jar_inputs + pak_inputs + res_inputs + build_utils.WriteDepfile( + options.depfile, + options.jar_info_path, + inputs=all_inputs, + add_pydeps=False) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/chromium/build/android/gyp/merge_jar_info_files.pydeps b/chromium/build/android/gyp/create_size_info_files.pydeps index 710091c42fa..4ab7f94ea60 100644 --- a/chromium/build/android/gyp/merge_jar_info_files.pydeps +++ b/chromium/build/android/gyp/create_size_info_files.pydeps @@ -1,7 +1,7 @@ # Generated by running: -# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/merge_jar_info_files.pydeps build/android/gyp/merge_jar_info_files.py +# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/create_size_info_files.pydeps build/android/gyp/create_size_info_files.py ../../gn_helpers.py -merge_jar_info_files.py +create_size_info_files.py util/__init__.py util/build_utils.py util/jar_info_utils.py diff --git a/chromium/build/android/gyp/javac.py b/chromium/build/android/gyp/javac.py index 8ad9bb7ebf0..e8ca89ab2fd 100755 --- a/chromium/build/android/gyp/javac.py +++ b/chromium/build/android/gyp/javac.py @@ -266,9 +266,6 @@ def _CreateInfoFile(java_files, jar_path, chromium_code, srcjar_files, This maps fully qualified names for classes to either the java file that they are defined in or the path of the srcjar that they came from. - - For apks this also produces a coalesced .apk.jar.info file combining all the - .jar.info files of its transitive dependencies. """ output_path = jar_path + '.info' logging.info('Start creating info file: %s', output_path) @@ -290,7 +287,7 @@ def _CreateInfoFile(java_files, jar_path, chromium_code, srcjar_files, all_info_data[fully_qualified_name] = java_file logging.info('Writing info file: %s', output_path) with build_utils.AtomicOutput(output_path) as f: - jar_info_utils.WriteJarInfoFile(f.name, all_info_data, srcjar_files) + jar_info_utils.WriteJarInfoFile(f, all_info_data, srcjar_files) logging.info('Completed info file: %s', output_path) @@ -471,13 +468,6 @@ def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs, logging.info('Completed all steps in _OnStaleMd5') -def _ParseAndFlattenGnLists(gn_lists): - ret = [] - for arg in gn_lists: - ret.extend(build_utils.ParseGnList(arg)) - return ret - - def _ParseOptions(argv): parser = optparse.OptionParser() build_utils.AddDepfileOption(parser) @@ -561,13 +551,13 @@ def _ParseOptions(argv): options, args = parser.parse_args(argv) build_utils.CheckOptions(options, parser, required=('jar_path',)) - options.bootclasspath = _ParseAndFlattenGnLists(options.bootclasspath) - options.full_classpath = _ParseAndFlattenGnLists(options.full_classpath) - options.interface_classpath = _ParseAndFlattenGnLists( + options.bootclasspath = build_utils.ParseGnList(options.bootclasspath) + options.full_classpath = build_utils.ParseGnList(options.full_classpath) + options.interface_classpath = build_utils.ParseGnList( options.interface_classpath) - options.processorpath = _ParseAndFlattenGnLists(options.processorpath) - options.processors = _ParseAndFlattenGnLists(options.processors) - options.java_srcjars = _ParseAndFlattenGnLists(options.java_srcjars) + options.processorpath = build_utils.ParseGnList(options.processorpath) + options.processors = build_utils.ParseGnList(options.processors) + options.java_srcjars = build_utils.ParseGnList(options.java_srcjars) if options.java_version == '1.8' and options.bootclasspath: # Android's boot jar doesn't contain all java 8 classes. diff --git a/chromium/build/android/gyp/merge_jar_info_files.py b/chromium/build/android/gyp/merge_jar_info_files.py deleted file mode 100755 index e6160f68469..00000000000 --- a/chromium/build/android/gyp/merge_jar_info_files.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2018 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. - -"""Merges .jar.info files into one for APKs.""" - -import argparse -import os -import shutil -import sys -import tempfile -import zipfile - -from util import build_utils -from util import jar_info_utils - - -def _FullJavaNameFromClassFilePath(path): - # Input: base/android/java/src/org/chromium/Foo.class - # Output: base.android.java.src.org.chromium.Foo - if not path.endswith('.class'): - return '' - path = os.path.splitext(path)[0] - parts = [] - while path: - # Use split to be platform independent. - head, tail = os.path.split(path) - path = head - parts.append(tail) - parts.reverse() # Package comes first - return '.'.join(parts) - - -def _MergeInfoFiles(output, jar_paths): - """Merge several .jar.info files to generate an .apk.jar.info. - - Args: - output: output file path. - jar_paths: List of .jar file paths for the target apk. - """ - info_data = dict() - for jar_path in jar_paths: - # android_java_prebuilt adds jar files in the src directory (relative to - # the output directory, usually ../../third_party/example.jar). - # android_aar_prebuilt collects jar files in the aar file and uses the - # java_prebuilt rule to generate gen/example/classes.jar files. - # We scan these prebuilt jars to parse each class path for the FQN. This - # allows us to later map these classes back to their respective src - # directories. - jar_info_path = jar_path + '.info' - # TODO(agrieve): This should probably also check that the mtime of the .info - # is newer than that of the .jar, or change prebuilts to always output - # .info files so that they always exist (and change the depfile to - # depend directly on them). - if os.path.exists(jar_info_path): - info_data.update(jar_info_utils.ParseJarInfoFile(jar_path + '.info')) - else: - with zipfile.ZipFile(jar_path) as zip_info: - for path in zip_info.namelist(): - fully_qualified_name = _FullJavaNameFromClassFilePath(path) - if fully_qualified_name: - info_data[fully_qualified_name] = '{}/{}'.format(jar_path, path) - - jar_info_utils.WriteJarInfoFile(output, info_data) - - -def main(args): - args = build_utils.ExpandFileArgs(args) - parser = argparse.ArgumentParser(description=__doc__) - build_utils.AddDepfileOption(parser) - parser.add_argument('--output', required=True, - help='Output .apk.jar.info file') - parser.add_argument('--apk-jar-file', required=True, - help='Path to main .jar file for this APK.') - parser.add_argument('--dep-jar-files', required=True, - help='GN-list of dependent .jar file paths') - - options = parser.parse_args(args) - options.dep_jar_files = build_utils.ParseGnList(options.dep_jar_files) - jar_files = [ options.apk_jar_file ] + options.dep_jar_files - - def _OnStaleMd5(): - with tempfile.NamedTemporaryFile() as tmp_file: - _MergeInfoFiles(tmp_file.name, jar_files) - shutil.move(tmp_file.name, options.output) - tmp_file.delete = False - - build_utils.CallAndWriteDepfileIfStale( - _OnStaleMd5, options, - input_paths=jar_files, - output_paths=[options.output], - depfile_deps=jar_files, - add_pydeps=False) - - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/chromium/build/android/gyp/util/build_utils.py b/chromium/build/android/gyp/util/build_utils.py index b5fd17ae543..ad26224673e 100644 --- a/chromium/build/android/gyp/util/build_utils.py +++ b/chromium/build/android/gyp/util/build_utils.py @@ -83,24 +83,33 @@ def ReadBuildVars(path): return dict(l.rstrip().split('=', 1) for l in f) -def ParseGnList(gn_string): - """Converts a command-line parameter into a list. +def ParseGnList(value): + """Converts a "GN-list" command-line parameter into a list. - If the input starts with a '[' it is assumed to be a GN-formatted list and - it will be parsed accordingly. When empty an empty list will be returned. - Otherwise, the parameter will be treated as a single raw string (not - GN-formatted in that it's not assumed to have literal quotes that must be - removed) and a list will be returned containing that string. + Conversions handled: + * None -> [] + * '' -> [] + * 'asdf' -> ['asdf'] + * '["a", "b"]' -> ['a', 'b'] + * ['["a", "b"]', 'c'] -> ['a', 'b', 'c'] (flattened list) The common use for this behavior is in the Android build where things can take lists of @FileArg references that are expanded via ExpandFileArgs. """ - if gn_string.startswith('['): - parser = gn_helpers.GNValueParser(gn_string) - return parser.ParseList() - if len(gn_string): - return [ gn_string ] - return [] + # Convert None to []. + if not value: + return [] + # Convert a list of GN lists to a flattened list. + if isinstance(value, list): + ret = [] + for arg in value: + ret.extend(ParseGnList(arg)) + return ret + # Convert normal GN list. + if value.startswith('['): + return gn_helpers.GNValueParser(value).ParseList() + # Convert a single string value to a list. + return [value] def CheckOptions(options, parser, required=None): diff --git a/chromium/build/android/gyp/util/jar_info_utils.py b/chromium/build/android/gyp/util/jar_info_utils.py index 987ee9dcf14..677e4e42616 100644 --- a/chromium/build/android/gyp/util/jar_info_utils.py +++ b/chromium/build/android/gyp/util/jar_info_utils.py @@ -32,21 +32,20 @@ def ParseJarInfoFile(info_path): return info_data -def WriteJarInfoFile(info_path, info_data, source_file_map=None): +def WriteJarInfoFile(output_obj, info_data, source_file_map=None): """Generate a .jar.info file from a given dictionary. Args: - info_path: output file path. + output_obj: output file object. info_data: a mapping of fully qualified Java class names to filepaths. source_file_map: an optional mapping from java source file paths to the corresponding source .srcjar. This is because info_data may contain the path of Java source files that where extracted from an .srcjar into a temporary location. """ - with open(info_path, 'w') as info_file: - for fully_qualified_name, path in info_data.iteritems(): - if source_file_map and path in source_file_map: - path = source_file_map[path] - assert not path.startswith('/tmp'), ( - 'Java file path should not be in temp dir: {}'.format(path)) - info_file.write('{},{}\n'.format(fully_qualified_name, path)) + for fully_qualified_name, path in sorted(info_data.iteritems()): + if source_file_map and path in source_file_map: + path = source_file_map[path] + assert not path.startswith('/tmp'), ( + 'Java file path should not be in temp dir: {}'.format(path)) + output_obj.write('{},{}\n'.format(fully_qualified_name, path)) diff --git a/chromium/build/android/gyp/write_build_config.py b/chromium/build/android/gyp/write_build_config.py index 7427845ddd5..7050374f1ff 100755 --- a/chromium/build/android/gyp/write_build_config.py +++ b/chromium/build/android/gyp/write_build_config.py @@ -1417,6 +1417,13 @@ def main(argv): c['main_class'] for c in processor_deps.Direct()] deps_info['javac_full_classpath'] = javac_full_classpath deps_info['javac_full_interface_classpath'] = javac_full_interface_classpath + elif options.type == 'android_app_bundle': + # bundles require javac_full_classpath to create .aab.jar.info. + javac_full_classpath = set() + for d in deps.Direct('android_app_bundle_module'): + javac_full_classpath.update(p for p in d['javac_full_classpath']) + javac_full_classpath.add(d['jar_path']) + deps_info['javac_full_classpath'] = sorted(javac_full_classpath) if options.type in ('android_apk', 'dist_jar', 'java_binary', 'junit_binary', 'android_app_bundle_module', 'android_app_bundle'): |