1#!/usr/bin/env python 2# 3# Copyright 2013 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6"""Signs and zipaligns APK. 7 8""" 9 10import optparse 11import shutil 12import sys 13import tempfile 14 15from util import build_utils 16 17def RenameInflateAndAddPageAlignment( 18 rezip_apk_jar_path, in_zip_file, out_zip_file): 19 rezip_apk_cmd = [ 20 'java', 21 '-classpath', 22 rezip_apk_jar_path, 23 'RezipApk', 24 'renamealign', 25 in_zip_file, 26 out_zip_file, 27 ] 28 build_utils.CheckOutput(rezip_apk_cmd) 29 30 31def ReorderAndAlignApk(rezip_apk_jar_path, in_zip_file, out_zip_file): 32 rezip_apk_cmd = [ 33 'java', 34 '-classpath', 35 rezip_apk_jar_path, 36 'RezipApk', 37 'reorder', 38 in_zip_file, 39 out_zip_file, 40 ] 41 build_utils.CheckOutput(rezip_apk_cmd) 42 43 44def JarSigner(key_path, key_name, key_passwd, unsigned_path, signed_path): 45 shutil.copy(unsigned_path, signed_path) 46 sign_cmd = [ 47 'jarsigner', 48 '-sigalg', 'MD5withRSA', 49 '-digestalg', 'SHA1', 50 '-keystore', key_path, 51 '-storepass', key_passwd, 52 signed_path, 53 key_name, 54 ] 55 build_utils.CheckOutput(sign_cmd) 56 57 58def AlignApk(zipalign_path, package_align, unaligned_path, final_path): 59 align_cmd = [ 60 zipalign_path, 61 '-f' 62 ] 63 64 if package_align: 65 align_cmd += ['-p'] 66 67 align_cmd += [ 68 '4', # 4 bytes 69 unaligned_path, 70 final_path, 71 ] 72 build_utils.CheckOutput(align_cmd) 73 74 75def main(args): 76 args = build_utils.ExpandFileArgs(args) 77 78 parser = optparse.OptionParser() 79 build_utils.AddDepfileOption(parser) 80 81 parser.add_option('--rezip-apk-jar-path', 82 help='Path to the RezipApk jar file.') 83 parser.add_option('--zipalign-path', help='Path to the zipalign tool.') 84 parser.add_option('--page-align-shared-libraries', 85 action='store_true', 86 help='Page align shared libraries.') 87 parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.') 88 parser.add_option('--final-apk-path', 89 help='Path to output signed and aligned APK.') 90 parser.add_option('--key-path', help='Path to keystore for signing.') 91 parser.add_option('--key-passwd', help='Keystore password') 92 parser.add_option('--key-name', help='Keystore name') 93 parser.add_option('--stamp', help='Path to touch on success.') 94 parser.add_option('--load-library-from-zip', type='int', 95 help='If non-zero, build the APK such that the library can be loaded ' + 96 'directly from the zip file using the crazy linker. The library ' + 97 'will be renamed, uncompressed and page aligned.') 98 99 options, _ = parser.parse_args() 100 101 input_paths = [ 102 options.unsigned_apk_path, 103 options.key_path, 104 ] 105 106 if options.load_library_from_zip: 107 input_paths.append(options.rezip_apk_jar_path) 108 109 input_strings = [ 110 options.load_library_from_zip, 111 options.key_name, 112 options.key_passwd, 113 options.page_align_shared_libraries, 114 ] 115 116 build_utils.CallAndWriteDepfileIfStale( 117 lambda: FinalizeApk(options), 118 options, 119 record_path=options.unsigned_apk_path + '.finalize.md5.stamp', 120 input_paths=input_paths, 121 input_strings=input_strings, 122 output_paths=[options.final_apk_path]) 123 124 125def FinalizeApk(options): 126 with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \ 127 tempfile.NamedTemporaryFile() as apk_to_sign_tmp: 128 129 if options.load_library_from_zip: 130 # We alter the name of the library so that the Android Package Manager 131 # does not extract it into a separate file. This must be done before 132 # signing, as the filename is part of the signed manifest. At the same 133 # time we uncompress the library, which is necessary so that it can be 134 # loaded directly from the APK. 135 # Move the library to a page boundary by adding a page alignment file. 136 apk_to_sign = apk_to_sign_tmp.name 137 RenameInflateAndAddPageAlignment( 138 options.rezip_apk_jar_path, options.unsigned_apk_path, apk_to_sign) 139 else: 140 apk_to_sign = options.unsigned_apk_path 141 142 signed_apk_path = signed_apk_path_tmp.name 143 JarSigner(options.key_path, options.key_name, options.key_passwd, 144 apk_to_sign, signed_apk_path) 145 146 if options.load_library_from_zip: 147 # Reorder the contents of the APK. This re-establishes the canonical 148 # order which means the library will be back at its page aligned location. 149 # This step also aligns uncompressed items to 4 bytes. 150 ReorderAndAlignApk( 151 options.rezip_apk_jar_path, signed_apk_path, options.final_apk_path) 152 else: 153 # Align uncompressed items to 4 bytes 154 AlignApk(options.zipalign_path, 155 options.page_align_shared_libraries, 156 signed_apk_path, 157 options.final_apk_path) 158 159 160if __name__ == '__main__': 161 sys.exit(main(sys.argv[1:])) 162