Add create_density_splits option to java_apk.gypi / android_apk (gn)

BUG=488324

Review URL: https://codereview.chromium.org/1133603004

Cr-Original-Commit-Position: refs/heads/master@{#331177}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: ac94e41f40bfc5252dc23dd72549d985ca221168
This commit is contained in:
agrieve 2015-05-22 14:32:09 -07:00 коммит произвёл Commit bot
Родитель 3e96135e62
Коммит acf4713cdf
8 изменённых файлов: 345 добавлений и 57 удалений

Просмотреть файл

@ -0,0 +1,70 @@
# Copyright 2015 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.
# This file is meant to be included into an action to provide an action that
# signs and zipaligns split APKs.
#
# Required variables:
# apk_name - Base name of the apk.
# Optional variables:
# density_splits - Whether to process density splits
# language_splits - Whether to language splits
{
'variables': {
'keystore_path%': '<(DEPTH)/build/android/ant/chromium-debug.keystore',
'keystore_name%': 'chromiumdebugkey',
'keystore_password%': 'chromium',
'zipalign_path%': '<(android_sdk_tools)/zipalign',
'density_splits%': 0,
'language_splits%': 0,
'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
'base_output_path': '<(PRODUCT_DIR)/apks/<(apk_name)',
},
'inputs': [
'<(DEPTH)/build/android/gyp/finalize_splits.py',
'<(DEPTH)/build/android/gyp/finalize_apk.py',
'<(DEPTH)/build/android/gyp/util/build_utils.py',
'<(keystore_path)',
],
'action': [
'python', '<(DEPTH)/build/android/gyp/finalize_splits.py',
'--resource-packaged-apk-path=<(resource_packaged_apk_path)',
'--base-output-path=<(base_output_path)',
'--zipalign-path=<(zipalign_path)',
'--key-path=<(keystore_path)',
'--key-name=<(keystore_name)',
'--key-passwd=<(keystore_password)',
],
'conditions': [
['density_splits == 1', {
'message': 'Signing/aligning <(_target_name) density splits',
'inputs': [
'<(resource_packaged_apk_path)-hdpi',
'<(resource_packaged_apk_path)-xhdpi',
'<(resource_packaged_apk_path)-xxhdpi',
'<(resource_packaged_apk_path)-tvdpi',
],
'outputs': [
'<(base_output_path)-density-hdpi.apk',
'<(base_output_path)-density-xhdpi.apk',
'<(base_output_path)-density-xxhdpi.apk',
'<(base_output_path)-density-tvdpi.apk',
],
'action': [
'--densities=hdpi,xhdpi,xxhdpi,tvdpi',
],
}],
# TODO(agrieve): Implement language splits
['language_splits == 1', {
'message': 'Signing/aligning <(_target_name) language splits',
'inputs': [
],
'outputs': [
],
}],
],
}

Просмотреть файл

@ -86,6 +86,17 @@ def main():
options, _ = parser.parse_args()
FinalizeApk(options)
if options.depfile:
build_utils.WriteDepfile(
options.depfile, build_utils.GetPythonDependencies())
if options.stamp:
build_utils.Touch(options.stamp)
def FinalizeApk(options):
with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \
tempfile.NamedTemporaryFile() as apk_to_sign_tmp:
@ -116,13 +127,6 @@ def main():
# Align uncompressed items to 4 bytes
AlignApk(options.zipalign_path, signed_apk_path, options.final_apk_path)
if options.depfile:
build_utils.WriteDepfile(
options.depfile, build_utils.GetPythonDependencies())
if options.stamp:
build_utils.Touch(options.stamp)
if __name__ == '__main__':
sys.exit(main())

44
android/gyp/finalize_splits.py Executable file
Просмотреть файл

@ -0,0 +1,44 @@
#!/usr/bin/env python
#
# Copyright 2015 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.
"""Signs and zipaligns split APKs.
This script is require only by GYP (not GN).
"""
import optparse
import sys
import finalize_apk
def main():
parser = optparse.OptionParser()
parser.add_option('--zipalign-path', help='Path to the zipalign tool.')
parser.add_option('--resource-packaged-apk-path',
help='Base path to input .ap_s.')
parser.add_option('--base-output-path',
help='Path to output .apk, minus extension.')
parser.add_option('--key-path', help='Path to keystore for signing.')
parser.add_option('--key-passwd', help='Keystore password')
parser.add_option('--key-name', help='Keystore name')
parser.add_option('--densities',
help='Comma separated list of densities finalize.')
options, _ = parser.parse_args()
options.load_library_from_zip = 0
if options.densities:
for density in options.densities.split(','):
options.unsigned_apk_path = ("%s-%s" %
(options.resource_packaged_apk_path, density))
options.final_apk_path = ("%s-density-%s.apk" %
(options.base_output_path, density))
finalize_apk.FinalizeApk(options)
else:
raise Exception('Language splits not yet implemented')
if __name__ == '__main__':
sys.exit(main())

Просмотреть файл

@ -16,9 +16,52 @@ https://android.googlesource.com/platform/sdk/+/master/files/ant/build.xml
import optparse
import os
import shutil
import zipfile
from util import build_utils
# List is generated from the chrome_apk.apk_intermediates.ap_ via:
# unzip -l $FILE_AP_ | cut -c31- | grep res/draw | cut -d'/' -f 2 | sort \
# | uniq | grep -- -tvdpi- | cut -c10-
# and then manually sorted.
# Note that we can't just do a cross-product of dimentions because the filenames
# become too big and aapt fails to create the files.
# This leaves all default drawables (mdpi) in the main apk. Android gets upset
# though if any drawables are missing from the default drawables/ directory.
DENSITY_SPLITS = {
'hdpi': (
'hdpi-v4', # Order matters for output file names.
'ldrtl-hdpi-v4',
'sw600dp-hdpi-v13',
'ldrtl-hdpi-v17',
'ldrtl-sw600dp-hdpi-v17',
'hdpi-v21',
),
'xhdpi': (
'xhdpi-v4',
'ldrtl-xhdpi-v4',
'sw600dp-xhdpi-v13',
'ldrtl-xhdpi-v17',
'ldrtl-sw600dp-xhdpi-v17',
'xhdpi-v21',
),
'xxhdpi': (
'xxhdpi-v4',
'ldrtl-xxhdpi-v4',
'sw600dp-xxhdpi-v13',
'ldrtl-xxhdpi-v17',
'ldrtl-sw600dp-xxhdpi-v17',
'xxhdpi-v21',
),
'tvdpi': (
'tvdpi-v4',
'sw600dp-tvdpi-v13',
'ldrtl-sw600dp-tvdpi-v17',
),
}
def ParseArgs():
"""Parses command line options.
@ -48,6 +91,10 @@ def ParseArgs():
help='directories containing assets to be packaged')
parser.add_option('--no-compress', help='disables compression for the '
'given comma separated list of extensions')
parser.add_option(
'--create-density-splits',
action='store_true',
help='Enables density splits')
parser.add_option('--apk-path',
help='Path to output (partial) apk.')
@ -114,6 +161,29 @@ def PackageArgsForExtractedZip(d):
return package_command
def RenameDensitySplits(apk_path):
"""Renames all density splits to have shorter / predictable names."""
for density, config in DENSITY_SPLITS.iteritems():
src_path = '%s_%s' % (apk_path, '_'.join(config))
dst_path = '%s-%s' % (apk_path, density)
if os.path.exists(dst_path):
os.unlink(dst_path)
os.rename(src_path, dst_path)
def CheckDensityMissedConfigs(apk_path):
"""Raises an exception if apk_path contains any density-specifc files."""
triggers = ['-%s' % density for density in DENSITY_SPLITS]
with zipfile.ZipFile(apk_path) as main_apk_zip:
for name in main_apk_zip.namelist():
for trigger in triggers:
if trigger in name and not 'mipmap-' in name:
raise Exception(('Found density in main apk that should have been ' +
'put into a split: %s\nYou need to update ' +
'package_resources.py to include this new ' +
'config.') % name)
def main():
options = ParseArgs()
android_jar = os.path.join(options.android_sdk, 'android.jar')
@ -128,7 +198,6 @@ def main():
'--no-crunch',
'-f',
'--auto-add-overlay',
'-I', android_jar,
'-F', options.apk_path,
'--ignore-assets', build_utils.AAPT_IGNORE_PATTERN,
@ -152,12 +221,20 @@ def main():
build_utils.ExtractAll(z, path=subdir)
package_command += PackageArgsForExtractedZip(subdir)
if options.create_density_splits:
for config in DENSITY_SPLITS.itervalues():
package_command.extend(('--split', ','.join(config)))
if 'Debug' in options.configuration_name:
package_command += ['--debug-mode']
build_utils.CheckOutput(
package_command, print_stdout=False, print_stderr=False)
if options.create_density_splits:
CheckDensityMissedConfigs(options.apk_path)
RenameDensitySplits(options.apk_path)
if options.depfile:
build_utils.WriteDepfile(
options.depfile,

Просмотреть файл

@ -12,6 +12,8 @@
# app_manifest_version_code - set the apps version number.
# Optional variables:
# asset_location - The directory where assets are located (if any).
# create_density_splits - Whether to create density-based apk splits. Splits
# are supported only for minSdkVersion >= 21.
# resource_zips - List of paths to resource zip files.
# shared_resources - Make a resource package that can be loaded by a different
# application at runtime to access the package's resources.
@ -20,6 +22,7 @@
{
'variables': {
'asset_location%': '',
'create_density_splits%': 0,
'resource_zips%': [],
'shared_resources%': 0,
'extensions_to_not_compress%': '',
@ -61,6 +64,17 @@
'--asset-dir', '<(asset_location)',
],
}],
['create_density_splits == 1', {
'action': [
'--create-density-splits',
],
'outputs': [
'<(resource_packaged_apk_path)-hdpi',
'<(resource_packaged_apk_path)-xhdpi',
'<(resource_packaged_apk_path)-xxhdpi',
'<(resource_packaged_apk_path)-tvdpi',
],
}],
['resource_zips != []', {
'action': [
'--resource-zips', '>(resource_zips)',

Просмотреть файл

@ -438,6 +438,50 @@ template("process_java_prebuilt") {
}
}
template("finalize_apk") {
action(target_name) {
script = "//build/android/gyp/finalize_apk.py"
depfile = "$target_gen_dir/$target_name.d"
sources = [
invoker.input_apk_path,
]
inputs = [
invoker.keystore_path,
]
outputs = [
depfile,
invoker.output_apk_path,
]
args = [
"--depfile",
rebase_path(depfile, root_build_dir),
"--zipalign-path",
rebase_path(zipalign_path, root_build_dir),
"--unsigned-apk-path",
rebase_path(invoker.input_apk_path, root_build_dir),
"--final-apk-path",
rebase_path(invoker.output_apk_path, root_build_dir),
"--key-path",
rebase_path(invoker.keystore_path, root_build_dir),
"--key-name",
invoker.keystore_name,
"--key-passwd",
invoker.keystore_password,
]
if (defined(invoker.rezip_apk) && invoker.rezip_apk) {
_rezip_jar_path = "$root_build_dir/lib.java/rezip_apk.jar"
inputs += [ _rezip_jar_path ]
args += [
"--load-library-from-zip=1",
"--rezip-apk-jar-path",
rebase_path(_rezip_jar_path, root_build_dir),
]
}
}
}
# Packages resources, assets, dex, and native libraries into an apk. Signs and
# zipaligns the apk.
template("create_apk") {
@ -456,14 +500,11 @@ template("create_apk") {
if (defined(invoker.dex_path)) {
_dex_path = invoker.dex_path
}
_keystore_path = invoker.keystore_path
_keystore_name = invoker.keystore_name
_keystore_password = invoker.keystore_password
_load_library_from_apk = invoker.load_library_from_apk
_deps = []
_package_deps = []
if (defined(invoker.deps)) {
_deps = invoker.deps
_package_deps = invoker.deps
}
_native_libs_dir = "//build/android/empty/res"
@ -490,8 +531,20 @@ template("create_apk") {
_configuration_name = "Debug"
}
action("${target_name}__package_resources") {
deps = _deps
_create_density_splits =
defined(invoker.create_density_splits) && invoker.create_density_splits
if (_create_density_splits) {
_split_densities = [
"hdpi",
"xhdpi",
"xxhdpi",
"tvdpi",
]
}
_package_resources_target_name = "${target_name}__package_resources"
action(_package_resources_target_name) {
deps = _package_deps
script = "//build/android/gyp/package_resources.py"
depfile = "${target_gen_dir}/${target_name}.d"
@ -539,12 +592,21 @@ template("create_apk") {
if (_shared_resources) {
args += [ "--shared-resources" ]
}
if (_create_density_splits) {
args += [ "--create-density-splits" ]
foreach(_density, _split_densities) {
outputs += [ "${_resource_packaged_apk_path}-${_density}" ]
}
}
}
action("${target_name}__package") {
script = "//build/android/gyp/ant.py"
_ant_script = "//build/android/ant/apk-package.xml"
deps = [
":${_package_resources_target_name}",
]
depfile = "$target_gen_dir/$target_name.d"
inputs = [
@ -594,53 +656,37 @@ template("create_apk") {
}
}
action("${target_name}__finalize") {
script = "//build/android/gyp/finalize_apk.py"
depfile = "$target_gen_dir/$target_name.d"
_finalize_apk_rule_name = "${target_name}__finalize"
finalize_apk(_finalize_apk_rule_name) {
input_apk_path = _packaged_apk_path
output_apk_path = _final_apk_path
keystore_path = invoker.keystore_path
keystore_name = invoker.keystore_name
keystore_password = invoker.keystore_password
rezip_apk = _load_library_from_apk
}
sources = [
_packaged_apk_path,
]
inputs = [
_keystore_path,
]
outputs = [
depfile,
_final_apk_path,
]
_final_deps = [ ":${_finalize_apk_rule_name}" ]
args = [
"--depfile",
rebase_path(depfile, root_build_dir),
"--zipalign-path",
rebase_path(zipalign_path, root_build_dir),
"--unsigned-apk-path",
rebase_path(_packaged_apk_path, root_build_dir),
"--final-apk-path",
rebase_path(_final_apk_path, root_build_dir),
"--key-path",
rebase_path(_keystore_path, root_build_dir),
"--key-name",
_keystore_name,
"--key-passwd",
_keystore_password,
]
if (_load_library_from_apk) {
_rezip_jar_path = "$root_build_dir/lib.java/rezip_apk.jar"
inputs += [ _rezip_jar_path ]
args += [
"--load-library-from-zip=1",
"--rezip-apk-jar-path",
rebase_path(_rezip_jar_path, root_build_dir),
]
if (_create_density_splits) {
foreach(_density, _split_densities) {
_finalize_split_rule_name = "${target_name}__finalize_${_density}_split"
finalize_apk(_finalize_split_rule_name) {
input_apk_path = "${_resource_packaged_apk_path}-${_density}"
_output_paths = process_file_template(
[ _final_apk_path ],
"{{source_dir}}/{{source_name_part}}-${_density}.apk")
output_apk_path = _output_paths[0]
keystore_path = invoker.keystore_path
keystore_name = invoker.keystore_name
keystore_password = invoker.keystore_password
}
_final_deps += [ ":${_finalize_split_rule_name}" ]
}
}
group(target_name) {
deps = [
":${target_name}__finalize",
":${target_name}__package_resources",
]
deps = _final_deps
}
}

Просмотреть файл

@ -1297,6 +1297,8 @@ template("android_apk") {
_rebased_build_config = rebase_path(_build_config, root_build_dir)
_create_abi_split =
defined(invoker.create_abi_split) && invoker.create_abi_split
_create_density_splits =
defined(invoker.create_density_splits) && invoker.create_density_splits
# Help GN understand that _create_abi_split is not unused (bug in GN).
assert(_create_abi_split || true)
@ -1488,6 +1490,7 @@ template("android_apk") {
resources_zip = _all_resources_zip_path
dex_path = final_dex_path
load_library_from_apk = _load_library_from_apk
create_density_splits = _create_density_splits
version_code = _version_code
version_name = _version_name

Просмотреть файл

@ -31,6 +31,8 @@
# additional_bundled_libs - Additional libraries what will be stripped and
# bundled in the apk.
# asset_location - The directory where assets are located.
# create_density_splits - Whether to create density-based apk splits. Splits
# are supported only for minSdkVersion >= 21.
# generated_src_dirs - Same as additional_src_dirs except used for .java files
# that are generated at build time. This should be set automatically by a
# target's dependencies. The .java files in these directories are not
@ -67,6 +69,7 @@
'tested_apk_obfuscated_jar_path%': '/',
'tested_apk_dex_path%': '/',
'additional_input_paths': [],
'create_density_splits%': 0,
'input_jars_paths': [],
'library_dexed_jars_paths': [],
'additional_src_dirs': [],
@ -132,6 +135,7 @@
'resource_zip_path': '<(intermediate_dir)/<(_target_name).resources.zip',
'shared_resources%': 0,
'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk',
'final_apk_path_no_extension%': '<(PRODUCT_DIR)/apks/<(apk_name)',
'final_abi_split_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name)-abi-<(android_app_abi).apk',
'incomplete_apk_path': '<(intermediate_dir)/<(apk_name)-incomplete.apk',
'apk_install_record': '<(intermediate_dir)/apk_install.record.stamp',
@ -576,6 +580,7 @@
'apk_name': '<(main_apk_name)-abi-<(android_app_abi)',
'asset_location': '',
'android_manifest_path': '<(split_android_manifest_path)',
'create_density_splits': 0,
},
'includes': [ 'android/package_resources_action.gypi' ],
},
@ -651,11 +656,36 @@
'action': [
'--apk-path=<(incomplete_apk_path)',
],
}]
}],
['create_density_splits == 1', {
'inputs': [
'<(final_apk_path_no_extension)-density-hdpi.apk',
'<(final_apk_path_no_extension)-density-xhdpi.apk',
'<(final_apk_path_no_extension)-density-xxhdpi.apk',
'<(final_apk_path_no_extension)-density-tvdpi.apk',
],
'action': [
'--split-apk-path=<(final_apk_path_no_extension)-density-hdpi.apk',
'--split-apk-path=<(final_apk_path_no_extension)-density-xhdpi.apk',
'--split-apk-path=<(final_apk_path_no_extension)-density-xxhdpi.apk',
'--split-apk-path=<(final_apk_path_no_extension)-density-tvdpi.apk',
],
}],
],
},
],
}],
['create_density_splits == 1', {
'actions': [
{
'action_name': 'finalize_density_splits',
'variables': {
'density_splits': 1,
},
'includes': [ 'android/finalize_splits_action.gypi']
},
],
}],
['is_test_apk == 1', {
'dependencies': [
'<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',