Home | History | Annotate | Download | only in releasetools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2011 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 Build image output_image_file from input_directory and properties_file.
     19 
     20 Usage:  build_image input_directory properties_file output_image_file
     21 
     22 """
     23 import os
     24 import os.path
     25 import subprocess
     26 import sys
     27 
     28 def RunCommand(cmd):
     29   """ Echo and run the given command
     30 
     31   Args:
     32     cmd: the command represented as a list of strings.
     33   Returns:
     34     The exit code.
     35   """
     36   print "Running: ", " ".join(cmd)
     37   p = subprocess.Popen(cmd)
     38   p.communicate()
     39   return p.returncode
     40 
     41 def BuildImage(in_dir, prop_dict, out_file):
     42   """Build an image to out_file from in_dir with property prop_dict.
     43 
     44   Args:
     45     in_dir: path of input directory.
     46     prop_dict: property dictionary.
     47     out_file: path of the output image file.
     48 
     49   Returns:
     50     True iff the image is built successfully.
     51   """
     52   build_command = []
     53   fs_type = prop_dict.get("fs_type", "")
     54   run_fsck = False
     55   if fs_type.startswith("ext"):
     56     build_command = ["mkuserimg.sh"]
     57     if "extfs_sparse_flag" in prop_dict:
     58       build_command.append(prop_dict["extfs_sparse_flag"])
     59       run_fsck = True
     60     build_command.extend([in_dir, out_file, fs_type,
     61                           prop_dict["mount_point"]])
     62     if "partition_size" in prop_dict:
     63       build_command.append(prop_dict["partition_size"])
     64     if "selinux_fc" in prop_dict:
     65       build_command.append(prop_dict["selinux_fc"])
     66   else:
     67     build_command = ["mkyaffs2image", "-f"]
     68     if prop_dict.get("mkyaffs2_extra_flags", None):
     69       build_command.extend(prop_dict["mkyaffs2_extra_flags"].split())
     70     build_command.append(in_dir)
     71     build_command.append(out_file)
     72     if "selinux_fc" in prop_dict:
     73       build_command.append(prop_dict["selinux_fc"])
     74       build_command.append(prop_dict["mount_point"])
     75 
     76   exit_code = RunCommand(build_command)
     77   if exit_code != 0:
     78     return False
     79 
     80   if run_fsck and prop_dict.get("skip_fsck") != "true":
     81     # Inflate the sparse image
     82     unsparse_image = os.path.join(
     83         os.path.dirname(out_file), "unsparse_" + os.path.basename(out_file))
     84     inflate_command = ["simg2img", out_file, unsparse_image]
     85     exit_code = RunCommand(inflate_command)
     86     if exit_code != 0:
     87       os.remove(unsparse_image)
     88       return False
     89 
     90     # Run e2fsck on the inflated image file
     91     e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image]
     92     exit_code = RunCommand(e2fsck_command)
     93 
     94     os.remove(unsparse_image)
     95 
     96   return exit_code == 0
     97 
     98 
     99 def ImagePropFromGlobalDict(glob_dict, mount_point):
    100   """Build an image property dictionary from the global dictionary.
    101 
    102   Args:
    103     glob_dict: the global dictionary from the build system.
    104     mount_point: such as "system", "data" etc.
    105   """
    106   d = {}
    107 
    108   def copy_prop(src_p, dest_p):
    109     if src_p in glob_dict:
    110       d[dest_p] = str(glob_dict[src_p])
    111 
    112   common_props = (
    113       "extfs_sparse_flag",
    114       "mkyaffs2_extra_flags",
    115       "selinux_fc",
    116       "skip_fsck",
    117       )
    118   for p in common_props:
    119     copy_prop(p, p)
    120 
    121   d["mount_point"] = mount_point
    122   if mount_point == "system":
    123     copy_prop("fs_type", "fs_type")
    124     copy_prop("system_size", "partition_size")
    125   elif mount_point == "data":
    126     copy_prop("fs_type", "fs_type")
    127     copy_prop("userdata_size", "partition_size")
    128   elif mount_point == "cache":
    129     copy_prop("cache_fs_type", "fs_type")
    130     copy_prop("cache_size", "partition_size")
    131   elif mount_point == "vendor":
    132     copy_prop("vendor_fs_type", "fs_type")
    133     copy_prop("vendor_size", "partition_size")
    134 
    135   return d
    136 
    137 
    138 def LoadGlobalDict(filename):
    139   """Load "name=value" pairs from filename"""
    140   d = {}
    141   f = open(filename)
    142   for line in f:
    143     line = line.strip()
    144     if not line or line.startswith("#"):
    145       continue
    146     k, v = line.split("=", 1)
    147     d[k] = v
    148   f.close()
    149   return d
    150 
    151 
    152 def main(argv):
    153   if len(argv) != 3:
    154     print __doc__
    155     sys.exit(1)
    156 
    157   in_dir = argv[0]
    158   glob_dict_file = argv[1]
    159   out_file = argv[2]
    160 
    161   glob_dict = LoadGlobalDict(glob_dict_file)
    162   image_filename = os.path.basename(out_file)
    163   mount_point = ""
    164   if image_filename == "system.img":
    165     mount_point = "system"
    166   elif image_filename == "userdata.img":
    167     mount_point = "data"
    168   elif image_filename == "cache.img":
    169     mount_point = "cache"
    170   elif image_filename == "vendor.img":
    171     mount_point = "vendor"
    172   else:
    173     print >> sys.stderr, "error: unknown image file name ", image_filename
    174     exit(1)
    175 
    176   image_properties = ImagePropFromGlobalDict(glob_dict, mount_point)
    177   if not BuildImage(in_dir, image_properties, out_file):
    178     print >> sys.stderr, "error: failed to build %s from %s" % (out_file, in_dir)
    179     exit(1)
    180 
    181 
    182 if __name__ == '__main__':
    183   main(sys.argv[1:])
    184