sign_target_files_apks revision 43874f8c864972b9dae7e4927aa347455b774c94
1eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#!/usr/bin/env python
2eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
3eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Copyright (C) 2008 The Android Open Source Project
4eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
5eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Licensed under the Apache License, Version 2.0 (the "License");
6eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# you may not use this file except in compliance with the License.
7eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# You may obtain a copy of the License at
8eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
9eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#      http://www.apache.org/licenses/LICENSE-2.0
10eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
11eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Unless required by applicable law or agreed to in writing, software
12eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# distributed under the License is distributed on an "AS IS" BASIS,
13eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# See the License for the specific language governing permissions and
15eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# limitations under the License.
16eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
17eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
18eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerSigns all the APK files in a target-files zipfile, producing a new
19eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkertarget-files zip.
20eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
21eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerUsage:  sign_target_files_apks [flags] input_target_files output_target_files
22eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
23eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -s  (--signapk_jar)  <path>
24eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Path of the signapks.jar file used to sign an individual APK
25eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      file.
26eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
27eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -e  (--extra_apks)  <name,name,...=key>
28eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Add extra APK name/key pairs as though they appeared in
29ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      apkcerts.txt (so mappings specified by -k and -d are applied).
30ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      Keys specified in -e override any value for that app contained
31ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      in the apkcerts.txt file.  Option may be repeated to give
32ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      multiple extra packages.
33eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
34eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -k  (--key_mapping)  <src_key=dest_key>
35eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Add a mapping from the key name as specified in apkcerts.txt (the
36eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      src_key) to the real key you wish to sign the package with
37eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      (dest_key).  Option may be repeated to give multiple key
38eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      mappings.
39eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
40eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -d  (--default_key_mappings)  <dir>
41eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Set up the following key mappings:
42eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
43eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/testkey   ==>  $dir/releasekey
44eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/media     ==>  $dir/media
45eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/shared    ==>  $dir/shared
46eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/platform  ==>  $dir/platform
47eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
48eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      -d and -k options are added to the set of mappings in the order
49eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      in which they appear on the command line.
508e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
518e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  -o  (--replace_ota_keys)
528e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      Replace the certificate (public key) used by OTA package
538e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      verification with the one specified in the input target_files
548e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      zip (in the META/otakeys.txt file).  Key remapping (-k and -d)
558e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      is performed on this key.
56eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
57eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
58eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys
59eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
60eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000:
61eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print >> sys.stderr, "Python 2.4 or newer is required."
62eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  sys.exit(1)
63eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
648e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport cStringIO
658e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport copy
66eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os
67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re
68eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess
69eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile
70eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile
71eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
72eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common
73eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
74eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS
75eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
76eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.extra_apks = {}
77eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.key_map = {}
788e931bf999693cac54c99deb1ef668d0e6164ecfDoug ZongkerOPTIONS.replace_ota_keys = False
79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
80eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetApkCerts(tf_zip):
81ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker  certmap = {}
82eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for line in tf_zip.read("META/apkcerts.txt").split("\n"):
83eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    line = line.strip()
84eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if not line: continue
85eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    m = re.match(r'^name="(.*)"\s+certificate="(.*)\.x509\.pem"\s+'
86eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 r'private_key="\2\.pk8"$', line)
87eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if not m:
88eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      raise SigningError("failed to parse line from apkcerts.txt:\n" + line)
89eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    certmap[m.group(1)] = OPTIONS.key_map.get(m.group(2), m.group(2))
90ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker  for apk, cert in OPTIONS.extra_apks.iteritems():
91ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
92eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return certmap
93eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
94eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
95eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApk(data, keyname, pw):
96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned = tempfile.NamedTemporaryFile()
97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.write(data)
98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.flush()
99eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
100eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed = tempfile.NamedTemporaryFile()
101eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
102eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  common.SignFile(unsigned.name, signed.name, keyname, pw, align=4)
103eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
104eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  data = signed.read()
105eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.close()
106eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed.close()
107eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
108eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return data
109eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
110eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
111eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApks(input_tf_zip, output_tf_zip):
112eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  apk_key_map = GetApkCerts(input_tf_zip)
113eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
114eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  maxsize = max([len(os.path.basename(i.filename))
115eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 for i in input_tf_zip.infolist()
116eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 if i.filename.endswith('.apk')])
117eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
11843874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  # Check that all the APKs we want to sign have keys specified, and
11943874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  # error out if they don't.  Do this before prompting for key
12043874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  # passwords in case we're going to fail anyway.
12143874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  unknown_apks = []
12243874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  for info in input_tf_zip.infolist():
12343874f8c864972b9dae7e4927aa347455b774c94Doug Zongker    if info.filename.endswith(".apk"):
12443874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      name = os.path.basename(info.filename)
12543874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      if name not in apk_key_map:
12643874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        unknown_apks.append(name)
12743874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  if unknown_apks:
12843874f8c864972b9dae7e4927aa347455b774c94Doug Zongker    print "ERROR: no key specified for:\n\n ",
12943874f8c864972b9dae7e4927aa347455b774c94Doug Zongker    print "\n  ".join(unknown_apks)
13043874f8c864972b9dae7e4927aa347455b774c94Doug Zongker    print "\nUse '-e <apkname>=' to specify a key (which may be an"
13143874f8c864972b9dae7e4927aa347455b774c94Doug Zongker    print "empty string to not sign this apk)."
13243874f8c864972b9dae7e4927aa347455b774c94Doug Zongker    sys.exit(1)
13343874f8c864972b9dae7e4927aa347455b774c94Doug Zongker
13443874f8c864972b9dae7e4927aa347455b774c94Doug Zongker  key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
13543874f8c864972b9dae7e4927aa347455b774c94Doug Zongker
136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in input_tf_zip.infolist():
137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    data = input_tf_zip.read(info.filename)
1388e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    out_info = copy.copy(info)
139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if info.filename.endswith(".apk"):
140eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      name = os.path.basename(info.filename)
14143874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      key = apk_key_map[name]
14243874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      if key:
14343874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "    signing: %-*s (%s)" % (maxsize, name, key)
144eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        signed_data = SignApk(data, key, key_passwords[key])
1458e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, signed_data)
146eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
147eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        # an APK we're not supposed to sign.
14843874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "NOT signing: %s" % (name,)
1498e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, data)
1508e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif info.filename in ("SYSTEM/build.prop",
1518e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                           "RECOVERY/RAMDISK/default.prop"):
152eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # Change build fingerprint to reflect the fact that apps are signed.
153eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      m = re.search(r"ro\.build\.fingerprint=.*\b(test-keys)\b.*", data)
154eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if not m:
155eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        print 'WARNING: ro.build.fingerprint does not contain "test-keys"'
156eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
157eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        data = data[:m.start(1)] + "release-keys" + data[m.end(1):]
158eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      m = re.search(r"ro\.build\.description=.*\b(test-keys)\b.*", data)
159eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if not m:
160eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        print 'WARNING: ro.build.description does not contain "test-keys"'
161eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
162eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        data = data[:m.start(1)] + "release-keys" + data[m.end(1):]
1638e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      output_tf_zip.writestr(out_info, data)
164eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
165eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # a non-APK file; copy it verbatim
1668e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      output_tf_zip.writestr(out_info, data)
1678e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1688e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1698e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerdef ReplaceOtaKeys(input_tf_zip, output_tf_zip):
1708e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  try:
1718e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    keylist = input_tf_zip.read("META/otakeys.txt").split()
1728e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  except KeyError:
1738e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    raise ExternalError("can't read META/otakeys.txt from input")
1748e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1758e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  mapped_keys = []
1768e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in keylist:
1778e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    m = re.match(r"^(.*)\.x509\.pem$", k)
1788e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    if not m:
1798e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      raise ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,))
1808e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    k = m.group(1)
1818e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
1828e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1838e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  print "using:\n   ", "\n   ".join(mapped_keys)
1848e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  print "for OTA package verification"
1858e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1868e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # recovery uses a version of the key that has been slightly
1878e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # predigested (by DumpPublicKey.java) and put in res/keys.
1888e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1898e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  p = common.Run(["java", "-jar", OPTIONS.dumpkey_jar] + mapped_keys,
1908e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                 stdout=subprocess.PIPE)
1918e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  data, _ = p.communicate()
1928e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if p.returncode != 0:
1938e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    raise ExternalError("failed to run dumpkeys")
1948e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  output_tf_zip.writestr("RECOVERY/RAMDISK/res/keys", data)
1958e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1968e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # SystemUpdateActivity uses the x509.pem version of the keys, but
1978e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # put into a zipfile system/etc/security/otacerts.zip.
1988e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1998e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  tempfile = cStringIO.StringIO()
2008e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip = zipfile.ZipFile(tempfile, "w")
2018e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in mapped_keys:
2028e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    certs_zip.write(k)
2038e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip.close()
2048e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  output_tf_zip.writestr("SYSTEM/etc/security/otacerts.zip",
2058e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                         tempfile.getvalue())
206eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
207eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
208eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv):
209eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
210eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def option_handler(o, a):
211eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if o in ("-s", "--signapk_jar"):
212eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.signapk_jar = a
213eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-e", "--extra_apks"):
214eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names, key = a.split("=")
215eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names = names.split(",")
216eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      for n in names:
217eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        OPTIONS.extra_apks[n] = key
218eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-d", "--default_key_mappings"):
219eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.key_map.update({
220eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/testkey": "%s/releasekey" % (a,),
221eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/media": "%s/media" % (a,),
222eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/shared": "%s/shared" % (a,),
223eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/platform": "%s/platform" % (a,),
224eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          })
225eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-k", "--key_mapping"):
226eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      s, d = a.split("=")
227eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.key_map[s] = d
2288e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif o in ("-o", "--replace_ota_keys"):
2298e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      OPTIONS.replace_ota_keys = True
230eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
231eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      return False
232eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return True
233eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
234eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  args = common.ParseOptions(argv, __doc__,
2358e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                             extra_opts="s:e:d:k:o",
236eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_long_opts=["signapk_jar=",
237eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "extra_apks=",
238eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "default_key_mappings=",
2398e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                                              "key_mapping=",
2408e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                                              "replace_ota_keys"],
241eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_option_handler=option_handler)
242eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
243eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if len(args) != 2:
244eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    common.Usage(__doc__)
245eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
246eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
247eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip = zipfile.ZipFile(args[0], "r")
248eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip = zipfile.ZipFile(args[1], "w")
249eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
250eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  SignApks(input_zip, output_zip)
251eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2528e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if OPTIONS.replace_ota_keys:
2538e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    ReplaceOtaKeys(input_zip, output_zip)
2548e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
255eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip.close()
256eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip.close()
257eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
258eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "done."
259eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
260eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
261eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__':
262eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  try:
263eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    main(sys.argv[1:])
264eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  except common.ExternalError, e:
265eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
266eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "   ERROR: %s" % (e,)
267eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
268eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
269