OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """ Merges a 64-bit and a 32-bit APK into a single APK | 6 """ Merges a 64-bit and a 32-bit APK into a single APK |
7 | 7 |
8 This script is used to merge two APKs which have only 32-bit or 64-bit | 8 This script is used to merge two APKs which have only 32-bit or 64-bit |
9 binaries respectively into a APK that has both 32-bit and 64-bit binaries | 9 binaries respectively into a APK that has both 32-bit and 64-bit binaries |
10 for 64-bit Android platform. | 10 for 64-bit Android platform. |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 ' unexpected files: %s' % pprint.pformat(unexpected_file_set)) | 112 ' unexpected files: %s' % pprint.pformat(unexpected_file_set)) |
113 if missing_file_set: | 113 if missing_file_set: |
114 errors.append(' missing files: %s' % pprint.pformat(missing_file_set)) | 114 errors.append(' missing files: %s' % pprint.pformat(missing_file_set)) |
115 if duplicate_file_set: | 115 if duplicate_file_set: |
116 errors.append(' duplicate files: %s' % pprint.pformat(duplicate_file_set)) | 116 errors.append(' duplicate files: %s' % pprint.pformat(duplicate_file_set)) |
117 | 117 |
118 if errors: | 118 if errors: |
119 raise ApkMergeFailure( | 119 raise ApkMergeFailure( |
120 "Files don't match expectations:\n%s" % '\n'.join(errors)) | 120 "Files don't match expectations:\n%s" % '\n'.join(errors)) |
121 | 121 |
122 def AddDiffFiles(diff_files, tmp_dir_32, tmp_apk, expected_files, | 122 |
| 123 def AddDiffFiles(diff_files, tmp_dir_32, out_zip, expected_files, |
123 component_build, uncompress_shared_libraries): | 124 component_build, uncompress_shared_libraries): |
124 """ Insert files only present in 32-bit APK into 64-bit APK (tmp_apk). """ | 125 """ Insert files only present in 32-bit APK into 64-bit APK (tmp_apk). """ |
125 old_dir = os.getcwd() | 126 for diff_file in diff_files: |
126 # Move into 32-bit directory to make sure the files we insert have correct | 127 if component_build and diff_file.endswith('.so'): |
127 # relative paths. | 128 compress = not uncompress_shared_libraries |
128 os.chdir(tmp_dir_32) | 129 else: |
129 try: | 130 compress = expected_files[os.path.basename(diff_file)] |
130 for diff_file in diff_files: | 131 build_utils.AddToZipHermetic(out_zip, |
131 if component_build and diff_file.endswith('.so'): | 132 diff_file, |
132 extra_flags = [] | 133 os.path.join(tmp_dir_32, diff_file), |
133 if uncompress_shared_libraries: | 134 compress=compress) |
134 extra_flags = ['-0'] | |
135 else: | |
136 extra_flags = expected_files[os.path.basename(diff_file)] | |
137 build_utils.CheckOutput( | |
138 [ | |
139 'zip', '-r', '-X', '--no-dir-entries', tmp_apk, diff_file | |
140 ] + extra_flags) | |
141 except build_utils.CalledProcessError as e: | |
142 raise ApkMergeFailure( | |
143 'Failed to add file %s to APK: %s' % (diff_file, e.output)) | |
144 finally: | |
145 # Move out of 32-bit directory when done | |
146 os.chdir(old_dir) | |
147 | |
148 | |
149 def RemoveMetafiles(tmp_apk): | |
150 """ Remove all meta info to avoid certificate clashes """ | |
151 try: | |
152 build_utils.CheckOutput(['zip', '-d', tmp_apk, 'META-INF/*']) | |
153 except build_utils.CalledProcessError as e: | |
154 raise ApkMergeFailure('Failed to delete Meta folder: ' + e.output) | |
155 | 135 |
156 | 136 |
157 def SignAndAlignApk(tmp_apk, signed_tmp_apk, new_apk, zipalign_path, | 137 def SignAndAlignApk(tmp_apk, signed_tmp_apk, new_apk, zipalign_path, |
158 keystore_path, key_name, key_password, | 138 keystore_path, key_name, key_password, |
159 page_align_shared_libraries): | 139 page_align_shared_libraries): |
160 try: | 140 try: |
161 finalize_apk.JarSigner( | 141 finalize_apk.JarSigner( |
162 keystore_path, | 142 keystore_path, |
163 key_name, | 143 key_name, |
164 key_password, | 144 key_password, |
(...skipping 22 matching lines...) Expand all Loading... |
187 ret = 'mips64' | 167 ret = 'mips64' |
188 elif abi == 'x86': | 168 elif abi == 'x86': |
189 ret = 'x86_64' | 169 ret = 'x86_64' |
190 else: | 170 else: |
191 raise ApkMergeFailure('Unsupported abi ' + abi) | 171 raise ApkMergeFailure('Unsupported abi ' + abi) |
192 if ret == '': | 172 if ret == '': |
193 raise ApkMergeFailure('Failed to find secondary abi') | 173 raise ApkMergeFailure('Failed to find secondary abi') |
194 return ret | 174 return ret |
195 | 175 |
196 def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64): | 176 def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64): |
197 # Expected files to copy from 32- to 64-bit APK together with an extra flag | 177 # Expected files to copy from 32- to 64-bit APK together with whether to |
198 # setting the compression level of the file | 178 # compress within the .apk. |
199 expected_files = {'snapshot_blob_32.bin': ['-0']} | 179 expected_files = {'snapshot_blob_32.bin': False} |
200 if args.shared_library: | 180 if args.shared_library: |
201 expected_files[args.shared_library] = [] | 181 expected_files[args.shared_library] = not args.uncompress_shared_libraries |
202 | |
203 if args.debug: | 182 if args.debug: |
204 expected_files['gdbserver'] = [] | 183 expected_files['gdbserver'] = True |
205 if args.uncompress_shared_libraries and args.shared_library: | |
206 expected_files[args.shared_library] += ['-0'] | |
207 | |
208 shutil.copyfile(args.apk_64bit, tmp_apk) | |
209 | 184 |
210 # need to unpack APKs to compare their contents | 185 # need to unpack APKs to compare their contents |
211 UnpackApk(args.apk_64bit, tmp_dir_64) | 186 UnpackApk(args.apk_64bit, tmp_dir_64) |
212 UnpackApk(args.apk_32bit, tmp_dir_32) | 187 UnpackApk(args.apk_32bit, tmp_dir_32) |
213 | 188 |
214 ignores = ['META-INF', 'AndroidManifest.xml'] | 189 ignores = ['META-INF', 'AndroidManifest.xml'] |
215 if args.ignore_classes_dex: | 190 if args.ignore_classes_dex: |
216 ignores += ['classes.dex', 'classes2.dex'] | 191 ignores += ['classes.dex', 'classes2.dex'] |
217 if args.debug: | 192 if args.debug: |
218 # see http://crbug.com/648720 | 193 # see http://crbug.com/648720 |
219 ignores += ['webview_licenses.notice'] | 194 ignores += ['webview_licenses.notice'] |
220 | 195 |
221 dcmp = filecmp.dircmp( | 196 dcmp = filecmp.dircmp( |
222 tmp_dir_64, | 197 tmp_dir_64, |
223 tmp_dir_32, | 198 tmp_dir_32, |
224 ignore=ignores) | 199 ignore=ignores) |
225 | 200 |
226 diff_files = GetDiffFiles(dcmp, tmp_dir_32) | 201 diff_files = GetDiffFiles(dcmp, tmp_dir_32) |
227 | 202 |
228 # Check that diff_files match exactly those files we want to insert into | 203 # Check that diff_files match exactly those files we want to insert into |
229 # the 64-bit APK. | 204 # the 64-bit APK. |
230 CheckFilesExpected(diff_files, expected_files, args.component_build) | 205 CheckFilesExpected(diff_files, expected_files, args.component_build) |
231 | 206 |
232 RemoveMetafiles(tmp_apk) | 207 with zipfile.ZipFile(tmp_apk, 'w') as out_zip: |
233 | 208 build_utils.MergeZips(out_zip, [args.apk_64bit], |
234 AddDiffFiles(diff_files, tmp_dir_32, tmp_apk, expected_files, | 209 exclude_patterns=['META-INF/*']) |
235 args.component_build, args.uncompress_shared_libraries) | 210 AddDiffFiles(diff_files, tmp_dir_32, out_zip, expected_files, |
| 211 args.component_build, args.uncompress_shared_libraries) |
236 | 212 |
237 | 213 |
238 def main(): | 214 def main(): |
239 parser = argparse.ArgumentParser( | 215 parser = argparse.ArgumentParser( |
240 description='Merge a 32-bit APK into a 64-bit APK') | 216 description='Merge a 32-bit APK into a 64-bit APK') |
241 # Using type=os.path.abspath converts file paths to absolute paths so that | 217 # Using type=os.path.abspath converts file paths to absolute paths so that |
242 # we can change working directory without affecting these paths | 218 # we can change working directory without affecting these paths |
243 parser.add_argument('--apk_32bit', required=True, type=os.path.abspath) | 219 parser.add_argument('--apk_32bit', required=True, type=os.path.abspath) |
244 parser.add_argument('--apk_64bit', required=True, type=os.path.abspath) | 220 parser.add_argument('--apk_64bit', required=True, type=os.path.abspath) |
245 parser.add_argument('--out_apk', required=True, type=os.path.abspath) | 221 parser.add_argument('--out_apk', required=True, type=os.path.abspath) |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 except ApkMergeFailure as e: | 256 except ApkMergeFailure as e: |
281 print e | 257 print e |
282 return 1 | 258 return 1 |
283 finally: | 259 finally: |
284 shutil.rmtree(tmp_dir) | 260 shutil.rmtree(tmp_dir) |
285 return 0 | 261 return 0 |
286 | 262 |
287 | 263 |
288 if __name__ == '__main__': | 264 if __name__ == '__main__': |
289 sys.exit(main()) | 265 sys.exit(main()) |
OLD | NEW |