diff options
author | Tao Bao | 2018-06-19 14:19:35 -0500 |
---|---|---|
committer | Tao Bao | 2018-06-19 16:50:23 -0500 |
commit | 11f955c5065c860cd27842b327c14be4e0766413 (patch) | |
tree | cc2e3f14df729a021b6d85ba45124e5543d17bee /tools/releasetools/sign_target_files_apks.py | |
parent | 2a07d562ac19a94268ec3ef18b2648fd74f5b237 (diff) | |
download | platform-build-11f955c5065c860cd27842b327c14be4e0766413.tar.gz platform-build-11f955c5065c860cd27842b327c14be4e0766413.tar.xz platform-build-11f955c5065c860cd27842b327c14be4e0766413.zip |
releasetools: Factor out the check for (compressed) APK file.
Test: Run sign_target_files.py to sign a target_files.zip.
Test: `python -m unittest test_sign_target_files_apks`
Change-Id: Ie795d1bce7bae6af427832283e3d10bfecad80c5
Diffstat (limited to 'tools/releasetools/sign_target_files_apks.py')
-rwxr-xr-x | tools/releasetools/sign_target_files_apks.py | 143 |
1 files changed, 87 insertions, 56 deletions
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py index fa62c8f63..756bc8a92 100755 --- a/tools/releasetools/sign_target_files_apks.py +++ b/tools/releasetools/sign_target_files_apks.py | |||
@@ -144,28 +144,69 @@ def GetApkCerts(certmap): | |||
144 | return certmap | 144 | return certmap |
145 | 145 | ||
146 | 146 | ||
147 | def GetApkFileInfo(filename, compressed_extension): | ||
148 | """Returns the APK info based on the given filename. | ||
149 | |||
150 | Checks if the given filename (with path) looks like an APK file, by taking the | ||
151 | compressed extension into consideration. | ||
152 | |||
153 | Args: | ||
154 | filename: Path to the file. | ||
155 | compressed_extension: The extension string of compressed APKs (e.g. ".gz"), | ||
156 | or None if there's no compressed APKs. | ||
157 | |||
158 | Returns: | ||
159 | (is_apk, is_compressed): is_apk indicates whether the given filename is an | ||
160 | APK file. is_compressed indicates whether the APK file is compressed (only | ||
161 | meaningful when is_apk is True). | ||
162 | |||
163 | Raises: | ||
164 | AssertionError: On invalid compressed_extension input. | ||
165 | """ | ||
166 | assert compressed_extension is None or compressed_extension.startswith('.'), \ | ||
167 | "Invalid compressed_extension arg: '{}'".format(compressed_extension) | ||
168 | |||
169 | compressed_apk_extension = ( | ||
170 | ".apk" + compressed_extension if compressed_extension else None) | ||
171 | is_apk = (filename.endswith(".apk") or | ||
172 | (compressed_apk_extension and | ||
173 | filename.endswith(compressed_apk_extension))) | ||
174 | if not is_apk: | ||
175 | return (False, False) | ||
176 | |||
177 | is_compressed = (compressed_apk_extension and | ||
178 | filename.endswith(compressed_apk_extension)) | ||
179 | return (True, is_compressed) | ||
180 | |||
181 | |||
147 | def CheckAllApksSigned(input_tf_zip, apk_key_map, compressed_extension): | 182 | def CheckAllApksSigned(input_tf_zip, apk_key_map, compressed_extension): |
148 | """Check that all the APKs we want to sign have keys specified, and | 183 | """Checks that all the APKs have keys specified, otherwise errors out. |
149 | error out if they don't.""" | 184 | |
185 | Args: | ||
186 | input_tf_zip: An open target_files zip file. | ||
187 | apk_key_map: A dict of known signing keys key'd by APK names. | ||
188 | compressed_extension: The extension string of compressed APKs, such as | ||
189 | ".gz", or None if there's no compressed APKs. | ||
190 | |||
191 | Raises: | ||
192 | AssertionError: On finding unknown APKs. | ||
193 | """ | ||
150 | unknown_apks = [] | 194 | unknown_apks = [] |
151 | compressed_apk_extension = None | ||
152 | if compressed_extension: | ||
153 | compressed_apk_extension = ".apk" + compressed_extension | ||
154 | for info in input_tf_zip.infolist(): | 195 | for info in input_tf_zip.infolist(): |
155 | if (info.filename.endswith(".apk") or | 196 | (is_apk, is_compressed) = GetApkFileInfo( |
156 | (compressed_apk_extension and | 197 | info.filename, compressed_extension) |
157 | info.filename.endswith(compressed_apk_extension))): | 198 | if not is_apk: |
158 | name = os.path.basename(info.filename) | 199 | continue |
159 | if compressed_apk_extension and name.endswith(compressed_apk_extension): | 200 | name = os.path.basename(info.filename) |
160 | name = name[:-len(compressed_extension)] | 201 | if is_compressed: |
161 | if name not in apk_key_map: | 202 | name = name[:-len(compressed_extension)] |
162 | unknown_apks.append(name) | 203 | if name not in apk_key_map: |
163 | if unknown_apks: | 204 | unknown_apks.append(name) |
164 | print("ERROR: no key specified for:\n") | 205 | |
165 | print(" " + "\n ".join(unknown_apks)) | 206 | assert not unknown_apks, \ |
166 | print("\nUse '-e <apkname>=' to specify a key (which may be an empty " | 207 | ("No key specified for:\n {}\n" |
167 | "string to not sign this apk).") | 208 | "Use '-e <apkname>=' to specify a key (which may be an empty string to " |
168 | sys.exit(1) | 209 | "not sign this apk).".format("\n ".join(unknown_apks))) |
169 | 210 | ||
170 | 211 | ||
171 | def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map, | 212 | def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map, |
@@ -235,32 +276,23 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | |||
235 | apk_key_map, key_passwords, platform_api_level, | 276 | apk_key_map, key_passwords, platform_api_level, |
236 | codename_to_api_level_map, | 277 | codename_to_api_level_map, |
237 | compressed_extension): | 278 | compressed_extension): |
238 | |||
239 | compressed_apk_extension = None | ||
240 | if compressed_extension: | ||
241 | compressed_apk_extension = ".apk" + compressed_extension | ||
242 | |||
243 | maxsize = max( | 279 | maxsize = max( |
244 | [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() | 280 | [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() |
245 | if (i.filename.endswith('.apk') or | 281 | if GetApkFileInfo(i.filename, compressed_extension)[0]]) |
246 | (compressed_apk_extension and | ||
247 | i.filename.endswith(compressed_apk_extension)))]) | ||
248 | system_root_image = misc_info.get("system_root_image") == "true" | 282 | system_root_image = misc_info.get("system_root_image") == "true" |
249 | 283 | ||
250 | for info in input_tf_zip.infolist(): | 284 | for info in input_tf_zip.infolist(): |
251 | if info.filename.startswith("IMAGES/"): | 285 | filename = info.filename |
286 | if filename.startswith("IMAGES/"): | ||
252 | continue | 287 | continue |
253 | 288 | ||
254 | data = input_tf_zip.read(info.filename) | 289 | data = input_tf_zip.read(filename) |
255 | out_info = copy.copy(info) | 290 | out_info = copy.copy(info) |
291 | (is_apk, is_compressed) = GetApkFileInfo(filename, compressed_extension) | ||
256 | 292 | ||
257 | # Sign APKs. | 293 | # Sign APKs. |
258 | if (info.filename.endswith(".apk") or | 294 | if is_apk: |
259 | (compressed_apk_extension and | 295 | name = os.path.basename(filename) |
260 | info.filename.endswith(compressed_apk_extension))): | ||
261 | is_compressed = (compressed_extension and | ||
262 | info.filename.endswith(compressed_apk_extension)) | ||
263 | name = os.path.basename(info.filename) | ||
264 | if is_compressed: | 296 | if is_compressed: |
265 | name = name[:-len(compressed_extension)] | 297 | name = name[:-len(compressed_extension)] |
266 | 298 | ||
@@ -276,15 +308,15 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | |||
276 | common.ZipWriteStr(output_tf_zip, out_info, data) | 308 | common.ZipWriteStr(output_tf_zip, out_info, data) |
277 | 309 | ||
278 | # System properties. | 310 | # System properties. |
279 | elif info.filename in ("SYSTEM/build.prop", | 311 | elif filename in ("SYSTEM/build.prop", |
280 | "VENDOR/build.prop", | 312 | "VENDOR/build.prop", |
281 | "SYSTEM/etc/prop.default", | 313 | "SYSTEM/etc/prop.default", |
282 | "BOOT/RAMDISK/prop.default", | 314 | "BOOT/RAMDISK/prop.default", |
283 | "BOOT/RAMDISK/default.prop", # legacy | 315 | "BOOT/RAMDISK/default.prop", # legacy |
284 | "ROOT/default.prop", # legacy | 316 | "ROOT/default.prop", # legacy |
285 | "RECOVERY/RAMDISK/prop.default", | 317 | "RECOVERY/RAMDISK/prop.default", |
286 | "RECOVERY/RAMDISK/default.prop"): # legacy | 318 | "RECOVERY/RAMDISK/default.prop"): # legacy |
287 | print("Rewriting %s:" % (info.filename,)) | 319 | print("Rewriting %s:" % (filename,)) |
288 | if stat.S_ISLNK(info.external_attr >> 16): | 320 | if stat.S_ISLNK(info.external_attr >> 16): |
289 | new_data = data | 321 | new_data = data |
290 | else: | 322 | else: |
@@ -293,20 +325,20 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | |||
293 | 325 | ||
294 | # Replace the certs in *mac_permissions.xml (there could be multiple, such | 326 | # Replace the certs in *mac_permissions.xml (there could be multiple, such |
295 | # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml). | 327 | # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml). |
296 | elif info.filename.endswith("mac_permissions.xml"): | 328 | elif filename.endswith("mac_permissions.xml"): |
297 | print("Rewriting %s with new keys." % (info.filename,)) | 329 | print("Rewriting %s with new keys." % (filename,)) |
298 | new_data = ReplaceCerts(data) | 330 | new_data = ReplaceCerts(data) |
299 | common.ZipWriteStr(output_tf_zip, out_info, new_data) | 331 | common.ZipWriteStr(output_tf_zip, out_info, new_data) |
300 | 332 | ||
301 | # Ask add_img_to_target_files to rebuild the recovery patch if needed. | 333 | # Ask add_img_to_target_files to rebuild the recovery patch if needed. |
302 | elif info.filename in ("SYSTEM/recovery-from-boot.p", | 334 | elif filename in ("SYSTEM/recovery-from-boot.p", |
303 | "SYSTEM/etc/recovery.img", | 335 | "SYSTEM/etc/recovery.img", |
304 | "SYSTEM/bin/install-recovery.sh"): | 336 | "SYSTEM/bin/install-recovery.sh"): |
305 | OPTIONS.rebuild_recovery = True | 337 | OPTIONS.rebuild_recovery = True |
306 | 338 | ||
307 | # Don't copy OTA keys if we're replacing them. | 339 | # Don't copy OTA keys if we're replacing them. |
308 | elif (OPTIONS.replace_ota_keys and | 340 | elif (OPTIONS.replace_ota_keys and |
309 | info.filename in ( | 341 | filename in ( |
310 | "BOOT/RAMDISK/res/keys", | 342 | "BOOT/RAMDISK/res/keys", |
311 | "BOOT/RAMDISK/etc/update_engine/update-payload-key.pub.pem", | 343 | "BOOT/RAMDISK/etc/update_engine/update-payload-key.pub.pem", |
312 | "RECOVERY/RAMDISK/res/keys", | 344 | "RECOVERY/RAMDISK/res/keys", |
@@ -315,22 +347,21 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | |||
315 | pass | 347 | pass |
316 | 348 | ||
317 | # Skip META/misc_info.txt since we will write back the new values later. | 349 | # Skip META/misc_info.txt since we will write back the new values later. |
318 | elif info.filename == "META/misc_info.txt": | 350 | elif filename == "META/misc_info.txt": |
319 | pass | 351 | pass |
320 | 352 | ||
321 | # Skip verity public key if we will replace it. | 353 | # Skip verity public key if we will replace it. |
322 | elif (OPTIONS.replace_verity_public_key and | 354 | elif (OPTIONS.replace_verity_public_key and |
323 | info.filename in ("BOOT/RAMDISK/verity_key", | 355 | filename in ("BOOT/RAMDISK/verity_key", |
324 | "ROOT/verity_key")): | 356 | "ROOT/verity_key")): |
325 | pass | 357 | pass |
326 | 358 | ||
327 | # Skip verity keyid (for system_root_image use) if we will replace it. | 359 | # Skip verity keyid (for system_root_image use) if we will replace it. |
328 | elif (OPTIONS.replace_verity_keyid and | 360 | elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline": |
329 | info.filename == "BOOT/cmdline"): | ||
330 | pass | 361 | pass |
331 | 362 | ||
332 | # Skip the care_map as we will regenerate the system/vendor images. | 363 | # Skip the care_map as we will regenerate the system/vendor images. |
333 | elif info.filename == "META/care_map.txt": | 364 | elif filename == "META/care_map.txt": |
334 | pass | 365 | pass |
335 | 366 | ||
336 | # A non-APK file; copy it verbatim. | 367 | # A non-APK file; copy it verbatim. |