Reland: Android: Use apksigner instead of jarsigner.

Reverted in: f4424029c0d3f43b64dcf5a04488e224229c5ec0.

Reason for reland:
 * Fixed apkmerger.py

Brings the finalize_apk step 19 seconds -> 4 seconds on
my machine (for ChromePublic.apk).

Also enables v2 signing of apks, which makes them install
faster on N+ devices.

Bug: 810890, 814350
Change-Id: I8bb010c2da59ace1450da79985e5f2a1111a9330
Reviewed-on: https://chromium-review.googlesource.com/929101
Reviewed-by: Tao Bai <michaelbai@chromium.org>
Reviewed-by: John Budorick <jbudorick@chromium.org>
Reviewed-by: agrieve <agrieve@chromium.org>
Commit-Queue: agrieve <agrieve@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#538433}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: bef0ce0b1f29658f9c86d89e6a1fbb33069d5754
This commit is contained in:
Andrew Grieve 2018-02-22 14:51:45 +00:00 коммит произвёл Commit Bot
Родитель 5e17532005
Коммит 3a79eed50c
5 изменённых файлов: 55 добавлений и 174 удалений

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

@ -242,9 +242,6 @@ def main(args):
def on_stale_md5():
tmp_apk = options.output_apk + '.tmp'
try:
# TODO(agrieve): It would be more efficient to combine this step
# with finalize_apk(), which sometimes aligns and uncompresses the
# native libraries.
with zipfile.ZipFile(options.resource_apk) as resource_apk, \
zipfile.ZipFile(tmp_apk, 'w', zipfile.ZIP_DEFLATED) as out_apk:
def copy_resource(zipinfo):

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

@ -3,121 +3,59 @@
# Copyright 2013 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 APK.
"""Signs and aligns an APK."""
"""
import optparse
import os
import argparse
import shutil
import sys
import subprocess
import tempfile
import zipfile
# resource_sizes modifies zipfile for zip64 compatibility. See
# https://bugs.python.org/issue14315.
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
import resource_sizes # pylint: disable=unused-import
from util import build_utils
def JarSigner(key_path, key_name, key_passwd, unsigned_path, signed_path):
shutil.copy(unsigned_path, signed_path)
sign_cmd = [
'jarsigner',
'-sigalg', 'MD5withRSA',
'-digestalg', 'SHA1',
'-keystore', key_path,
'-storepass', key_passwd,
signed_path,
key_name,
]
build_utils.CheckOutput(sign_cmd)
def FinalizeApk(apksigner_path, zipalign_path, unsigned_apk_path,
final_apk_path, key_path, key_passwd, key_name):
# Use a tempfile so that Ctrl-C does not leave the file with a fresh mtime
# and a corrupted state.
with tempfile.NamedTemporaryFile() as staging_file:
# v2 signing requires that zipalign happen first.
subprocess.check_output([
zipalign_path, '-p', '-f', '4',
unsigned_apk_path, staging_file.name])
subprocess.check_output([
apksigner_path, 'sign',
'--in', staging_file.name,
'--out', staging_file.name,
'--ks', key_path,
'--ks-key-alias', key_name,
'--ks-pass', 'pass:' + key_passwd,
# Force SHA-1 (makes signing faster; insecure is fine for local builds).
'--min-sdk-version', '1',
])
shutil.move(staging_file.name, final_apk_path)
staging_file.delete = False
def AlignApk(zipalign_path, unaligned_path, final_path):
# Note -p will page align native libraries (files ending with .so), but
# only those that are stored uncompressed.
align_cmd = [
zipalign_path,
'-p',
'-f',
]
def main():
parser = argparse.ArgumentParser()
align_cmd += [
'4', # 4 bytes
unaligned_path,
final_path,
]
build_utils.CheckOutput(align_cmd)
def main(args):
args = build_utils.ExpandFileArgs(args)
parser = optparse.OptionParser()
build_utils.AddDepfileOption(parser)
parser.add_option('--zipalign-path', help='Path to the zipalign tool.')
parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.')
parser.add_option('--final-apk-path',
help='Path to output signed and aligned APK.')
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')
options, _ = parser.parse_args()
input_paths = [
options.unsigned_apk_path,
options.key_path,
]
input_strings = [
options.key_name,
options.key_passwd,
]
build_utils.CallAndWriteDepfileIfStale(
lambda: FinalizeApk(options),
options,
record_path=options.unsigned_apk_path + '.finalize.md5.stamp',
input_paths=input_paths,
input_strings=input_strings,
output_paths=[options.final_apk_path])
def _NormalizeZip(path):
with tempfile.NamedTemporaryFile(suffix='.zip') as hermetic_signed_apk:
with zipfile.ZipFile(path, 'r') as zi:
with zipfile.ZipFile(hermetic_signed_apk, 'w') as zo:
for info in zi.infolist():
# Ignore 'extended local file headers'. Python doesn't write them
# properly (see https://bugs.python.org/issue1742205) which causes
# zipalign to miscalculate alignment. Since we don't use them except
# for alignment anyway, we write a stripped file here and let
# zipalign add them properly later. eLFHs are controlled by 'general
# purpose bit flag 03' (0x08) so we mask that out.
info.flag_bits = info.flag_bits & 0xF7
info.date_time = build_utils.HERMETIC_TIMESTAMP
zo.writestr(info, zi.read(info.filename))
shutil.copy(hermetic_signed_apk.name, path)
def FinalizeApk(options):
with tempfile.NamedTemporaryFile() as signed_apk_path_tmp:
signed_apk_path = signed_apk_path_tmp.name
JarSigner(options.key_path, options.key_name, options.key_passwd,
options.unsigned_apk_path, signed_apk_path)
# Make the newly added signing files hermetic.
_NormalizeZip(signed_apk_path)
AlignApk(options.zipalign_path, signed_apk_path, options.final_apk_path)
parser.add_argument('--apksigner-path', required=True,
help='Path to the apksigner executable.')
parser.add_argument('--zipalign-path', required=True,
help='Path to the zipalign executable.')
parser.add_argument('--unsigned-apk-path', required=True,
help='Path to input unsigned APK.')
parser.add_argument('--final-apk-path', required=True,
help='Path to output signed and aligned APK.')
parser.add_argument('--key-path', required=True,
help='Path to keystore for signing.')
parser.add_argument('--key-passwd', required=True,
help='Keystore password')
parser.add_argument('--key-name', required=True,
help='Keystore name')
options = parser.parse_args()
FinalizeApk(options.apksigner_path, options.zipalign_path,
options.unsigned_apk_path, options.final_apk_path,
options.key_path, options.key_passwd, options.key_name)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
main()

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

@ -1,52 +0,0 @@
#!/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
from util import build_utils
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.')
parser.add_option('--languages',
help='GYP list of language splits to 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)
if options.languages:
for lang in build_utils.ParseGnList(options.languages):
options.unsigned_apk_path = ("%s_%s" %
(options.resource_packaged_apk_path, lang))
options.final_apk_path = ("%s-lang-%s.apk" %
(options.base_output_path, lang))
finalize_apk.FinalizeApk(options)
if __name__ == '__main__':
sys.exit(main())

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

@ -263,8 +263,6 @@ if (is_android) {
# Path to the SDK's android.jar
android_sdk_jar = "$android_sdk/android.jar"
zipalign_path = "$android_sdk_build_tools/zipalign"
# Subdirectories inside android_ndk_root that contain the sysroot for the
# associated platform.
x86_android_sysroot_subdir =

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

@ -1866,9 +1866,6 @@ if (enable_java_templates) {
# keystore_password: Keystore password.
template("finalize_apk") {
action(target_name) {
deps = []
script = "//build/android/gyp/finalize_apk.py"
depfile = "$target_gen_dir/$target_name.d"
forward_variables_from(invoker,
[
"deps",
@ -1877,10 +1874,13 @@ if (enable_java_templates) {
"testonly",
])
sources = [
invoker.input_apk_path,
]
script = "//build/android/gyp/finalize_apk.py"
_apksigner = "$android_sdk_build_tools/apksigner"
_zipalign = "$android_sdk_build_tools/zipalign"
inputs = [
_apksigner,
_zipalign,
invoker.input_apk_path,
invoker.keystore_path,
]
outputs = [
@ -1891,14 +1891,14 @@ if (enable_java_templates) {
]
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),
"--apksigner-path",
rebase_path(_apksigner, root_build_dir),
"--zipalign-path",
rebase_path(_zipalign, root_build_dir),
"--key-path",
rebase_path(invoker.keystore_path, root_build_dir),
"--key-name",