am eb338efd: make sure package keys are consistent with shared users
Merge commit 'eb338efd2eae20962c7ca75baf161be540b3d664' * commit 'eb338efd2eae20962c7ca75baf161be540b3d664': make sure package keys are consistent with shared users
This commit is contained in:
commit
b4204699a4
|
@ -101,6 +101,85 @@ def GetApkCerts(tf_zip):
|
|||
return certmap
|
||||
|
||||
|
||||
def CheckAllApksSigned(input_tf_zip, apk_key_map):
|
||||
"""Check that all the APKs we want to sign have keys specified, and
|
||||
error out if they don't."""
|
||||
unknown_apks = []
|
||||
for info in input_tf_zip.infolist():
|
||||
if info.filename.endswith(".apk"):
|
||||
name = os.path.basename(info.filename)
|
||||
if name not in apk_key_map:
|
||||
unknown_apks.append(name)
|
||||
if unknown_apks:
|
||||
print "ERROR: no key specified for:\n\n ",
|
||||
print "\n ".join(unknown_apks)
|
||||
print "\nUse '-e <apkname>=' to specify a key (which may be an"
|
||||
print "empty string to not sign this apk)."
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def SharedUserForApk(data):
|
||||
tmp = tempfile.NamedTemporaryFile()
|
||||
tmp.write(data)
|
||||
tmp.flush()
|
||||
|
||||
p = common.Run(["aapt", "dump", "xmltree", tmp.name, "AndroidManifest.xml"],
|
||||
stdout=subprocess.PIPE)
|
||||
data, _ = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise ExternalError("failed to run aapt dump")
|
||||
lines = data.split("\n")
|
||||
for i in lines:
|
||||
m = re.match(r'^\s*A: android:sharedUserId\([0-9a-fx]*\)="([^"]*)" .*$', i)
|
||||
if m:
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def CheckSharedUserIdsConsistent(input_tf_zip, apk_key_map):
|
||||
"""Check that all packages that request the same shared user id are
|
||||
going to be signed with the same key."""
|
||||
|
||||
shared_user_apks = {}
|
||||
maxlen = 0
|
||||
|
||||
for info in input_tf_zip.infolist():
|
||||
if info.filename.endswith(".apk"):
|
||||
data = input_tf_zip.read(info.filename)
|
||||
|
||||
name = os.path.basename(info.filename)
|
||||
shared_user = SharedUserForApk(data)
|
||||
key = apk_key_map[name]
|
||||
maxlen = max(maxlen, len(key))
|
||||
|
||||
if shared_user is not None:
|
||||
shared_user_apks.setdefault(
|
||||
shared_user, {}).setdefault(key, []).append(name)
|
||||
|
||||
errors = []
|
||||
for k, v in shared_user_apks.iteritems():
|
||||
# each shared user should have exactly one key used for all the
|
||||
# apks that want that user.
|
||||
if len(v) > 1:
|
||||
errors.append((k, v))
|
||||
|
||||
if not errors: return
|
||||
|
||||
print "ERROR: shared user inconsistency. All apks wanting to use"
|
||||
print " a given shared user must be signed with the same key."
|
||||
print
|
||||
errors.sort()
|
||||
for user, keys in errors:
|
||||
print 'shared user id "%s":' % (user,)
|
||||
for key, apps in keys.iteritems():
|
||||
print ' %-*s %s' % (maxlen, key, apps[0])
|
||||
for a in apps[1:]:
|
||||
print (' ' * (maxlen+5)) + a
|
||||
print
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def SignApk(data, keyname, pw):
|
||||
unsigned = tempfile.NamedTemporaryFile()
|
||||
unsigned.write(data)
|
||||
|
@ -117,31 +196,11 @@ def SignApk(data, keyname, pw):
|
|||
return data
|
||||
|
||||
|
||||
def SignApks(input_tf_zip, output_tf_zip):
|
||||
apk_key_map = GetApkCerts(input_tf_zip)
|
||||
|
||||
def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords):
|
||||
maxsize = max([len(os.path.basename(i.filename))
|
||||
for i in input_tf_zip.infolist()
|
||||
if i.filename.endswith('.apk')])
|
||||
|
||||
# Check that all the APKs we want to sign have keys specified, and
|
||||
# error out if they don't. Do this before prompting for key
|
||||
# passwords in case we're going to fail anyway.
|
||||
unknown_apks = []
|
||||
for info in input_tf_zip.infolist():
|
||||
if info.filename.endswith(".apk"):
|
||||
name = os.path.basename(info.filename)
|
||||
if name not in apk_key_map:
|
||||
unknown_apks.append(name)
|
||||
if unknown_apks:
|
||||
print "ERROR: no key specified for:\n\n ",
|
||||
print "\n ".join(unknown_apks)
|
||||
print "\nUse '-e <apkname>=' to specify a key (which may be an"
|
||||
print "empty string to not sign this apk)."
|
||||
sys.exit(1)
|
||||
|
||||
key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
|
||||
|
||||
for info in input_tf_zip.infolist():
|
||||
data = input_tf_zip.read(info.filename)
|
||||
out_info = copy.copy(info)
|
||||
|
@ -289,7 +348,12 @@ def main(argv):
|
|||
input_zip = zipfile.ZipFile(args[0], "r")
|
||||
output_zip = zipfile.ZipFile(args[1], "w")
|
||||
|
||||
SignApks(input_zip, output_zip)
|
||||
apk_key_map = GetApkCerts(input_zip)
|
||||
CheckAllApksSigned(input_zip, apk_key_map)
|
||||
CheckSharedUserIdsConsistent(input_zip, apk_key_map)
|
||||
|
||||
key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
|
||||
SignApks(input_zip, output_zip, apk_key_map, key_passwords)
|
||||
|
||||
if OPTIONS.replace_ota_keys:
|
||||
ReplaceOtaKeys(input_zip, output_zip)
|
||||
|
|
Loading…
Reference in New Issue