Home | History | Annotate | Download | only in releasetools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2014 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #      http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """
     18 Given a target-files zipfile that does not contain images (ie, does
     19 not have an IMAGES/ top-level subdirectory), produce the images and
     20 add them to the zipfile.
     21 
     22 Usage:  add_img_to_target_files target_files
     23 """
     24 
     25 import sys
     26 
     27 if sys.hexversion < 0x02070000:
     28   print >> sys.stderr, "Python 2.7 or newer is required."
     29   sys.exit(1)
     30 
     31 import errno
     32 import os
     33 import re
     34 import shutil
     35 import subprocess
     36 import tempfile
     37 import zipfile
     38 
     39 # missing in Python 2.4 and before
     40 if not hasattr(os, "SEEK_SET"):
     41   os.SEEK_SET = 0
     42 
     43 import build_image
     44 import common
     45 
     46 OPTIONS = common.OPTIONS
     47 
     48 
     49 def AddSystem(output_zip, prefix="IMAGES/"):
     50   """Turn the contents of SYSTEM into a system image and store it in
     51   output_zip."""
     52   block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map")
     53   imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict,
     54                         block_list=block_list)
     55   with open(imgname, "rb") as f:
     56     common.ZipWriteStr(output_zip, prefix + "system.img", f.read())
     57   with open(block_list, "rb") as f:
     58     common.ZipWriteStr(output_zip, prefix + "system.map", f.read())
     59 
     60 
     61 def BuildSystem(input_dir, info_dict, block_list=None):
     62   """Build the (sparse) system image and return the name of a temp
     63   file containing it."""
     64   return CreateImage(input_dir, info_dict, "system", block_list=block_list)
     65 
     66 
     67 def AddVendor(output_zip, prefix="IMAGES/"):
     68   """Turn the contents of VENDOR into a vendor image and store in it
     69   output_zip."""
     70   block_list = common.MakeTempFile(prefix="vendor-blocklist-", suffix=".map")
     71   imgname = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict,
     72                      block_list=block_list)
     73   with open(imgname, "rb") as f:
     74     common.ZipWriteStr(output_zip, prefix + "vendor.img", f.read())
     75   with open(block_list, "rb") as f:
     76     common.ZipWriteStr(output_zip, prefix + "vendor.map", f.read())
     77 
     78 
     79 def BuildVendor(input_dir, info_dict, block_list=None):
     80   """Build the (sparse) vendor image and return the name of a temp
     81   file containing it."""
     82   return CreateImage(input_dir, info_dict, "vendor", block_list=block_list)
     83 
     84 
     85 def CreateImage(input_dir, info_dict, what, block_list=None):
     86   print "creating " + what + ".img..."
     87 
     88   img = common.MakeTempFile(prefix=what + "-", suffix=".img")
     89 
     90   # The name of the directory it is making an image out of matters to
     91   # mkyaffs2image.  It wants "system" but we have a directory named
     92   # "SYSTEM", so create a symlink.
     93   try:
     94     os.symlink(os.path.join(input_dir, what.upper()),
     95                os.path.join(input_dir, what))
     96   except OSError, e:
     97       # bogus error on my mac version?
     98       #   File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
     99       #     os.path.join(OPTIONS.input_tmp, "system"))
    100       # OSError: [Errno 17] File exists
    101     if (e.errno == errno.EEXIST):
    102       pass
    103 
    104   image_props = build_image.ImagePropFromGlobalDict(info_dict, what)
    105   fstab = info_dict["fstab"]
    106   if fstab:
    107     image_props["fs_type" ] = fstab["/" + what].fs_type
    108 
    109   if what == "system":
    110     fs_config_prefix = ""
    111   else:
    112     fs_config_prefix = what + "_"
    113 
    114   fs_config = os.path.join(
    115       input_dir, "META/" + fs_config_prefix + "filesystem_config.txt")
    116   if not os.path.exists(fs_config): fs_config = None
    117 
    118   fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts")
    119   if not os.path.exists(fc_config): fc_config = None
    120 
    121   succ = build_image.BuildImage(os.path.join(input_dir, what),
    122                                 image_props, img,
    123                                 fs_config=fs_config,
    124                                 fc_config=fc_config,
    125                                 block_list=block_list)
    126   assert succ, "build " + what + ".img image failed"
    127 
    128   return img
    129 
    130 
    131 def AddUserdata(output_zip, prefix="IMAGES/"):
    132   """Create an empty userdata image and store it in output_zip."""
    133 
    134   image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
    135                                                     "data")
    136   # We only allow yaffs to have a 0/missing partition_size.
    137   # Extfs, f2fs must have a size. Skip userdata.img if no size.
    138   if (not image_props.get("fs_type", "").startswith("yaffs") and
    139       not image_props.get("partition_size")):
    140     return
    141 
    142   print "creating userdata.img..."
    143 
    144   # The name of the directory it is making an image out of matters to
    145   # mkyaffs2image.  So we create a temp dir, and within it we create an
    146   # empty dir named "data", and build the image from that.
    147   temp_dir = tempfile.mkdtemp()
    148   user_dir = os.path.join(temp_dir, "data")
    149   os.mkdir(user_dir)
    150   img = tempfile.NamedTemporaryFile()
    151 
    152   fstab = OPTIONS.info_dict["fstab"]
    153   if fstab:
    154     image_props["fs_type" ] = fstab["/data"].fs_type
    155   succ = build_image.BuildImage(user_dir, image_props, img.name)
    156   assert succ, "build userdata.img image failed"
    157 
    158   common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
    159   output_zip.write(img.name, prefix + "userdata.img")
    160   img.close()
    161   os.rmdir(user_dir)
    162   os.rmdir(temp_dir)
    163 
    164 
    165 def AddCache(output_zip, prefix="IMAGES/"):
    166   """Create an empty cache image and store it in output_zip."""
    167 
    168   image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
    169                                                     "cache")
    170   # The build system has to explicitly request for cache.img.
    171   if "fs_type" not in image_props:
    172     return
    173 
    174   print "creating cache.img..."
    175 
    176   # The name of the directory it is making an image out of matters to
    177   # mkyaffs2image.  So we create a temp dir, and within it we create an
    178   # empty dir named "cache", and build the image from that.
    179   temp_dir = tempfile.mkdtemp()
    180   user_dir = os.path.join(temp_dir, "cache")
    181   os.mkdir(user_dir)
    182   img = tempfile.NamedTemporaryFile()
    183 
    184   fstab = OPTIONS.info_dict["fstab"]
    185   if fstab:
    186     image_props["fs_type" ] = fstab["/cache"].fs_type
    187   succ = build_image.BuildImage(user_dir, image_props, img.name)
    188   assert succ, "build cache.img image failed"
    189 
    190   common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
    191   output_zip.write(img.name, prefix + "cache.img")
    192   img.close()
    193   os.rmdir(user_dir)
    194   os.rmdir(temp_dir)
    195 
    196 
    197 def AddImagesToTargetFiles(filename):
    198   OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename)
    199 
    200   for n in input_zip.namelist():
    201     if n.startswith("IMAGES/"):
    202       print "target_files appears to already contain images."
    203       sys.exit(1)
    204 
    205   try:
    206     input_zip.getinfo("VENDOR/")
    207     has_vendor = True
    208   except KeyError:
    209     has_vendor = False
    210 
    211   OPTIONS.info_dict = common.LoadInfoDict(input_zip)
    212   if "selinux_fc" in OPTIONS.info_dict:
    213     OPTIONS.info_dict["selinux_fc"] = os.path.join(
    214         OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
    215 
    216   input_zip.close()
    217   output_zip = zipfile.ZipFile(filename, "a",
    218                                compression=zipfile.ZIP_DEFLATED)
    219 
    220   def banner(s):
    221     print "\n\n++++ " + s + " ++++\n\n"
    222 
    223   banner("boot")
    224   boot_image = common.GetBootableImage(
    225       "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
    226   if boot_image:
    227     boot_image.AddToZip(output_zip)
    228 
    229   banner("recovery")
    230   recovery_image = common.GetBootableImage(
    231       "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
    232   if recovery_image:
    233     recovery_image.AddToZip(output_zip)
    234 
    235   banner("system")
    236   AddSystem(output_zip)
    237   if has_vendor:
    238     banner("vendor")
    239     AddVendor(output_zip)
    240   banner("userdata")
    241   AddUserdata(output_zip)
    242   banner("cache")
    243   AddCache(output_zip)
    244 
    245   output_zip.close()
    246 
    247 
    248 def main(argv):
    249   args = common.ParseOptions(argv, __doc__)
    250 
    251   if len(args) != 1:
    252     common.Usage(__doc__)
    253     sys.exit(1)
    254 
    255   AddImagesToTargetFiles(args[0])
    256   print "done."
    257 
    258 if __name__ == '__main__':
    259   try:
    260     common.CloseInheritedPipes()
    261     main(sys.argv[1:])
    262   except common.ExternalError, e:
    263     print
    264     print "   ERROR: %s" % (e,)
    265     print
    266     sys.exit(1)
    267   finally:
    268     common.Cleanup()
    269