Loading core/definitions.mk +12 −0 Original line number Diff line number Diff line Loading @@ -2284,11 +2284,23 @@ define add-carried-jack-resources fi endef # Returns the minSdkVersion of the specified APK as a decimal number. If the # version is a codename, returns the current platform SDK version (always a # decimal number) instead. If the APK does not specify a minSdkVersion, returns # 0 to match how the Android platform interprets this situation at runtime. # define get-package-min-sdk-version-int $$(($(AAPT) dump badging $(1) 2>&1 | grep '^sdkVersion' || echo "sdkVersion:'0'") \ | cut -d"'" -f2 | \ sed -e s/^$(PLATFORM_VERSION_CODENAME)$$/$(PLATFORM_SDK_VERSION)/) endef # Sign a package using the specified key/cert. # define sign-package $(hide) mv $@ $@.unsigned $(hide) java -Djava.library.path=$(SIGNAPK_JNI_LIBRARY_PATH) -jar $(SIGNAPK_JAR) \ --min-sdk-version $(call get-package-min-sdk-version-int,$@.unsigned) \ $(PRIVATE_CERTIFICATE) $(PRIVATE_PRIVATE_KEY) \ $(PRIVATE_ADDITIONAL_CERTIFICATES) $@.unsigned $@.signed $(hide) mv $@.signed $@ Loading core/prebuilt_internal.mk +2 −2 Original line number Diff line number Diff line Loading @@ -216,7 +216,7 @@ embedded_prebuilt_jni_libs := 'lib/*.so' endif $(built_module): PRIVATE_EMBEDDED_JNI_LIBS := $(embedded_prebuilt_jni_libs) $(built_module) : $(my_prebuilt_src_file) | $(ACP) $(ZIPALIGN) $(SIGNAPK_JAR) $(built_module) : $(my_prebuilt_src_file) | $(ACP) $(ZIPALIGN) $(SIGNAPK_JAR) $(AAPT) $(transform-prebuilt-to-target) $(uncompress-shared-libs) ifneq ($(LOCAL_CERTIFICATE),PRESIGNED) Loading Loading @@ -255,7 +255,7 @@ my_src_dir := $(LOCAL_PATH)/$(my_src_dir) $(built_apk_splits) : PRIVATE_PRIVATE_KEY := $(LOCAL_CERTIFICATE).pk8 $(built_apk_splits) : PRIVATE_CERTIFICATE := $(LOCAL_CERTIFICATE).x509.pem $(built_apk_splits) : $(built_module_path)/%.apk : $(my_src_dir)/%.apk | $(ACP) $(built_apk_splits) : $(built_module_path)/%.apk : $(my_src_dir)/%.apk | $(ACP) $(AAPT) $(copy-file-to-new-target) $(sign-package) Loading tools/releasetools/common.py +56 −1 Original line number Diff line number Diff line Loading @@ -591,7 +591,46 @@ def GetKeyPasswords(keylist): return key_passwords def SignFile(input_name, output_name, key, password, whole_file=False): def GetMinSdkVersion(apk_name): """Get the minSdkVersion delared in the APK. This can be both a decimal number (API Level) or a codename. """ p = Run(["aapt", "dump", "badging", apk_name], stdout=subprocess.PIPE) output, err = p.communicate() if err: raise ExternalError("Failed to obtain minSdkVersion: aapt return code %s" % (p.returncode,)) for line in output.split("\n"): # Looking for lines such as sdkVersion:'23' or sdkVersion:'M' m = re.match(r'sdkVersion:\'([^\']*)\'', line) if m: return m.group(1) raise ExternalError("No minSdkVersion returned by aapt") def GetMinSdkVersionInt(apk_name, codename_to_api_level_map): """Get the minSdkVersion declared in the APK as a number (API Level). If minSdkVersion is set to a codename, it is translated to a number using the provided map. """ version = GetMinSdkVersion(apk_name) try: return int(version) except ValueError: # Not a decimal number. Codename? if version in codename_to_api_level_map: return codename_to_api_level_map[version] else: raise ExternalError("Unknown minSdkVersion: '%s'. Known codenames: %s" % (version, codename_to_api_level_map)) def SignFile(input_name, output_name, key, password, min_api_level=None, codename_to_api_level_map=dict(), whole_file=False): """Sign the input_name zip/jar/apk, producing output_name. Use the given key and password (the latter may be None if the key does not have a password. Loading @@ -599,6 +638,13 @@ def SignFile(input_name, output_name, key, password, whole_file=False): If whole_file is true, use the "-w" option to SignApk to embed a signature that covers the whole file in the archive comment of the zip file. min_api_level is the API Level (int) of the oldest platform this file may end up on. If not specified for an APK, the API Level is obtained by interpreting the minSdkVersion attribute of the APK's AndroidManifest.xml. codename_to_api_level_map is needed to translate the codename which may be encountered as the APK's minSdkVersion. """ java_library_path = os.path.join( Loading @@ -611,6 +657,15 @@ def SignFile(input_name, output_name, key, password, whole_file=False): cmd.extend(OPTIONS.extra_signapk_args) if whole_file: cmd.append("-w") min_sdk_version = min_api_level if min_sdk_version is None: if not whole_file: min_sdk_version = GetMinSdkVersionInt( input_name, codename_to_api_level_map) if min_sdk_version is not None: cmd.extend(["--min-sdk-version", str(min_sdk_version)]) cmd.extend([key + OPTIONS.public_key_suffix, key + OPTIONS.private_key_suffix, input_name, output_name]) Loading tools/releasetools/sign_target_files_apks.py +87 −5 Original line number Diff line number Diff line Loading @@ -127,14 +127,34 @@ def CheckAllApksSigned(input_tf_zip, apk_key_map): sys.exit(1) def SignApk(data, keyname, pw): def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): unsigned = tempfile.NamedTemporaryFile() unsigned.write(data) unsigned.flush() signed = tempfile.NamedTemporaryFile() common.SignFile(unsigned.name, signed.name, keyname, pw) # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK # didn't change, we don't want its signature to change due to the switch # from SHA-1 to SHA-256. # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion # is 18 or higher. For pre-N builds we disable this mechanism by pretending # that the APK's minSdkVersion is 1. # For N+ builds, we let APK signer rely on the APK's minSdkVersion to # determine whether to use SHA-256. min_api_level = None if platform_api_level > 23: # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's # minSdkVersion attribute min_api_level = None else: # Force APK signer to use SHA-1 min_api_level = 1 common.SignFile(unsigned.name, signed.name, keyname, pw, min_api_level=min_api_level, codename_to_api_level_map=codename_to_api_level_map) data = signed.read() unsigned.close() Loading @@ -144,7 +164,8 @@ def SignApk(data, keyname, pw): def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map, key_passwords): apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map): maxsize = max([len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() Loading Loading @@ -200,7 +221,8 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, key = apk_key_map[name] if key not in common.SPECIAL_CERT_STRINGS: print " signing: %-*s (%s)" % (maxsize, name, key) signed_data = SignApk(data, key, key_passwords[key]) signed_data = SignApk(data, key, key_passwords[key], platform_api_level, codename_to_api_level_map) common.ZipWriteStr(output_tf_zip, out_info, signed_data) else: # an APK we're not supposed to sign. Loading Loading @@ -440,6 +462,57 @@ def BuildKeyMap(misc_info, key_mapping_options): OPTIONS.key_map[s] = d def GetApiLevelAndCodename(input_tf_zip): data = input_tf_zip.read("SYSTEM/build.prop") api_level = None codename = None for line in data.split("\n"): line = line.strip() original_line = line if line and line[0] != '#' and "=" in line: key, value = line.split("=", 1) key = key.strip() if key == "ro.build.version.sdk": api_level = int(value.strip()) elif key == "ro.build.version.codename": codename = value.strip() if api_level is None: raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") if codename is None: raise ValueError("No ro.build.version.codename in SYSTEM/build.prop") return (api_level, codename) def GetCodenameToApiLevelMap(input_tf_zip): data = input_tf_zip.read("SYSTEM/build.prop") api_level = None codenames = None for line in data.split("\n"): line = line.strip() original_line = line if line and line[0] != '#' and "=" in line: key, value = line.split("=", 1) key = key.strip() if key == "ro.build.version.sdk": api_level = int(value.strip()) elif key == "ro.build.version.all_codenames": codenames = value.strip().split(",") if api_level is None: raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") if codenames is None: raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop") result = dict() for codename in codenames: codename = codename.strip() if len(codename) > 0: result[codename] = api_level return result def main(argv): key_mapping_options = [] Loading Loading @@ -498,8 +571,17 @@ def main(argv): CheckAllApksSigned(input_zip, apk_key_map) key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) platform_api_level, platform_codename = GetApiLevelAndCodename(input_zip) codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip) # Android N will be API Level 24, but isn't yet. # TODO: Remove this workaround once Android N is officially API Level 24. if platform_api_level == 23 and platform_codename == "N": platform_api_level = 24 ProcessTargetFiles(input_zip, output_zip, misc_info, apk_key_map, key_passwords) apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map) common.ZipClose(input_zip) common.ZipClose(output_zip) Loading Loading
core/definitions.mk +12 −0 Original line number Diff line number Diff line Loading @@ -2284,11 +2284,23 @@ define add-carried-jack-resources fi endef # Returns the minSdkVersion of the specified APK as a decimal number. If the # version is a codename, returns the current platform SDK version (always a # decimal number) instead. If the APK does not specify a minSdkVersion, returns # 0 to match how the Android platform interprets this situation at runtime. # define get-package-min-sdk-version-int $$(($(AAPT) dump badging $(1) 2>&1 | grep '^sdkVersion' || echo "sdkVersion:'0'") \ | cut -d"'" -f2 | \ sed -e s/^$(PLATFORM_VERSION_CODENAME)$$/$(PLATFORM_SDK_VERSION)/) endef # Sign a package using the specified key/cert. # define sign-package $(hide) mv $@ $@.unsigned $(hide) java -Djava.library.path=$(SIGNAPK_JNI_LIBRARY_PATH) -jar $(SIGNAPK_JAR) \ --min-sdk-version $(call get-package-min-sdk-version-int,$@.unsigned) \ $(PRIVATE_CERTIFICATE) $(PRIVATE_PRIVATE_KEY) \ $(PRIVATE_ADDITIONAL_CERTIFICATES) $@.unsigned $@.signed $(hide) mv $@.signed $@ Loading
core/prebuilt_internal.mk +2 −2 Original line number Diff line number Diff line Loading @@ -216,7 +216,7 @@ embedded_prebuilt_jni_libs := 'lib/*.so' endif $(built_module): PRIVATE_EMBEDDED_JNI_LIBS := $(embedded_prebuilt_jni_libs) $(built_module) : $(my_prebuilt_src_file) | $(ACP) $(ZIPALIGN) $(SIGNAPK_JAR) $(built_module) : $(my_prebuilt_src_file) | $(ACP) $(ZIPALIGN) $(SIGNAPK_JAR) $(AAPT) $(transform-prebuilt-to-target) $(uncompress-shared-libs) ifneq ($(LOCAL_CERTIFICATE),PRESIGNED) Loading Loading @@ -255,7 +255,7 @@ my_src_dir := $(LOCAL_PATH)/$(my_src_dir) $(built_apk_splits) : PRIVATE_PRIVATE_KEY := $(LOCAL_CERTIFICATE).pk8 $(built_apk_splits) : PRIVATE_CERTIFICATE := $(LOCAL_CERTIFICATE).x509.pem $(built_apk_splits) : $(built_module_path)/%.apk : $(my_src_dir)/%.apk | $(ACP) $(built_apk_splits) : $(built_module_path)/%.apk : $(my_src_dir)/%.apk | $(ACP) $(AAPT) $(copy-file-to-new-target) $(sign-package) Loading
tools/releasetools/common.py +56 −1 Original line number Diff line number Diff line Loading @@ -591,7 +591,46 @@ def GetKeyPasswords(keylist): return key_passwords def SignFile(input_name, output_name, key, password, whole_file=False): def GetMinSdkVersion(apk_name): """Get the minSdkVersion delared in the APK. This can be both a decimal number (API Level) or a codename. """ p = Run(["aapt", "dump", "badging", apk_name], stdout=subprocess.PIPE) output, err = p.communicate() if err: raise ExternalError("Failed to obtain minSdkVersion: aapt return code %s" % (p.returncode,)) for line in output.split("\n"): # Looking for lines such as sdkVersion:'23' or sdkVersion:'M' m = re.match(r'sdkVersion:\'([^\']*)\'', line) if m: return m.group(1) raise ExternalError("No minSdkVersion returned by aapt") def GetMinSdkVersionInt(apk_name, codename_to_api_level_map): """Get the minSdkVersion declared in the APK as a number (API Level). If minSdkVersion is set to a codename, it is translated to a number using the provided map. """ version = GetMinSdkVersion(apk_name) try: return int(version) except ValueError: # Not a decimal number. Codename? if version in codename_to_api_level_map: return codename_to_api_level_map[version] else: raise ExternalError("Unknown minSdkVersion: '%s'. Known codenames: %s" % (version, codename_to_api_level_map)) def SignFile(input_name, output_name, key, password, min_api_level=None, codename_to_api_level_map=dict(), whole_file=False): """Sign the input_name zip/jar/apk, producing output_name. Use the given key and password (the latter may be None if the key does not have a password. Loading @@ -599,6 +638,13 @@ def SignFile(input_name, output_name, key, password, whole_file=False): If whole_file is true, use the "-w" option to SignApk to embed a signature that covers the whole file in the archive comment of the zip file. min_api_level is the API Level (int) of the oldest platform this file may end up on. If not specified for an APK, the API Level is obtained by interpreting the minSdkVersion attribute of the APK's AndroidManifest.xml. codename_to_api_level_map is needed to translate the codename which may be encountered as the APK's minSdkVersion. """ java_library_path = os.path.join( Loading @@ -611,6 +657,15 @@ def SignFile(input_name, output_name, key, password, whole_file=False): cmd.extend(OPTIONS.extra_signapk_args) if whole_file: cmd.append("-w") min_sdk_version = min_api_level if min_sdk_version is None: if not whole_file: min_sdk_version = GetMinSdkVersionInt( input_name, codename_to_api_level_map) if min_sdk_version is not None: cmd.extend(["--min-sdk-version", str(min_sdk_version)]) cmd.extend([key + OPTIONS.public_key_suffix, key + OPTIONS.private_key_suffix, input_name, output_name]) Loading
tools/releasetools/sign_target_files_apks.py +87 −5 Original line number Diff line number Diff line Loading @@ -127,14 +127,34 @@ def CheckAllApksSigned(input_tf_zip, apk_key_map): sys.exit(1) def SignApk(data, keyname, pw): def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): unsigned = tempfile.NamedTemporaryFile() unsigned.write(data) unsigned.flush() signed = tempfile.NamedTemporaryFile() common.SignFile(unsigned.name, signed.name, keyname, pw) # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK # didn't change, we don't want its signature to change due to the switch # from SHA-1 to SHA-256. # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion # is 18 or higher. For pre-N builds we disable this mechanism by pretending # that the APK's minSdkVersion is 1. # For N+ builds, we let APK signer rely on the APK's minSdkVersion to # determine whether to use SHA-256. min_api_level = None if platform_api_level > 23: # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's # minSdkVersion attribute min_api_level = None else: # Force APK signer to use SHA-1 min_api_level = 1 common.SignFile(unsigned.name, signed.name, keyname, pw, min_api_level=min_api_level, codename_to_api_level_map=codename_to_api_level_map) data = signed.read() unsigned.close() Loading @@ -144,7 +164,8 @@ def SignApk(data, keyname, pw): def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map, key_passwords): apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map): maxsize = max([len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() Loading Loading @@ -200,7 +221,8 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, key = apk_key_map[name] if key not in common.SPECIAL_CERT_STRINGS: print " signing: %-*s (%s)" % (maxsize, name, key) signed_data = SignApk(data, key, key_passwords[key]) signed_data = SignApk(data, key, key_passwords[key], platform_api_level, codename_to_api_level_map) common.ZipWriteStr(output_tf_zip, out_info, signed_data) else: # an APK we're not supposed to sign. Loading Loading @@ -440,6 +462,57 @@ def BuildKeyMap(misc_info, key_mapping_options): OPTIONS.key_map[s] = d def GetApiLevelAndCodename(input_tf_zip): data = input_tf_zip.read("SYSTEM/build.prop") api_level = None codename = None for line in data.split("\n"): line = line.strip() original_line = line if line and line[0] != '#' and "=" in line: key, value = line.split("=", 1) key = key.strip() if key == "ro.build.version.sdk": api_level = int(value.strip()) elif key == "ro.build.version.codename": codename = value.strip() if api_level is None: raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") if codename is None: raise ValueError("No ro.build.version.codename in SYSTEM/build.prop") return (api_level, codename) def GetCodenameToApiLevelMap(input_tf_zip): data = input_tf_zip.read("SYSTEM/build.prop") api_level = None codenames = None for line in data.split("\n"): line = line.strip() original_line = line if line and line[0] != '#' and "=" in line: key, value = line.split("=", 1) key = key.strip() if key == "ro.build.version.sdk": api_level = int(value.strip()) elif key == "ro.build.version.all_codenames": codenames = value.strip().split(",") if api_level is None: raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") if codenames is None: raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop") result = dict() for codename in codenames: codename = codename.strip() if len(codename) > 0: result[codename] = api_level return result def main(argv): key_mapping_options = [] Loading Loading @@ -498,8 +571,17 @@ def main(argv): CheckAllApksSigned(input_zip, apk_key_map) key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) platform_api_level, platform_codename = GetApiLevelAndCodename(input_zip) codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip) # Android N will be API Level 24, but isn't yet. # TODO: Remove this workaround once Android N is officially API Level 24. if platform_api_level == 23 and platform_codename == "N": platform_api_level = 24 ProcessTargetFiles(input_zip, output_zip, misc_info, apk_key_map, key_passwords) apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map) common.ZipClose(input_zip) common.ZipClose(output_zip) Loading