| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 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 | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 24 | import os.path | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 25 | import re | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 26 | import subprocess | 
 | 27 | import sys | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 28 | import commands | 
| Baligh Uddin | 601ddea | 2015-06-09 15:48:14 -0700 | [diff] [blame] | 29 | import common | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 30 | import shutil | 
| Sami Tolvanen | 405e71d | 2016-02-09 12:28:58 -0800 | [diff] [blame] | 31 | import sparse_img | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 32 | import tempfile | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 33 |  | 
| Baligh Uddin | 601ddea | 2015-06-09 15:48:14 -0700 | [diff] [blame] | 34 | OPTIONS = common.OPTIONS | 
 | 35 |  | 
| Geremy Condra | e8e982a | 2014-05-16 19:14:30 -0700 | [diff] [blame] | 36 | FIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7" | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 37 | BLOCK_SIZE = 4096 | 
| Geremy Condra | e8e982a | 2014-05-16 19:14:30 -0700 | [diff] [blame] | 38 |  | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 39 | def RunCommand(cmd): | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 40 |   """Echo and run the given command. | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 41 |  | 
 | 42 |   Args: | 
 | 43 |     cmd: the command represented as a list of strings. | 
 | 44 |   Returns: | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 45 |     A tuple of the output and the exit code. | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 46 |   """ | 
 | 47 |   print "Running: ", " ".join(cmd) | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 48 |   p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 
 | 49 |   output, _ = p.communicate() | 
 | 50 |   print "%s" % (output.rstrip(),) | 
 | 51 |   return (output, p.returncode) | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 52 |  | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 53 | def GetVerityFECSize(partition_size): | 
 | 54 |   cmd = "fec -s %d" % partition_size | 
 | 55 |   status, output = commands.getstatusoutput(cmd) | 
 | 56 |   if status: | 
 | 57 |     print output | 
 | 58 |     return False, 0 | 
 | 59 |   return True, int(output) | 
 | 60 |  | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 61 | def GetVerityTreeSize(partition_size): | 
| Colin Cross | 477cf2b | 2014-04-16 18:49:56 -0700 | [diff] [blame] | 62 |   cmd = "build_verity_tree -s %d" | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 63 |   cmd %= partition_size | 
 | 64 |   status, output = commands.getstatusoutput(cmd) | 
 | 65 |   if status: | 
 | 66 |     print output | 
 | 67 |     return False, 0 | 
 | 68 |   return True, int(output) | 
 | 69 |  | 
 | 70 | def GetVerityMetadataSize(partition_size): | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 71 |   cmd = "system/extras/verity/build_verity_metadata.py size %d" | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 72 |   cmd %= partition_size | 
| Baligh Uddin | 601ddea | 2015-06-09 15:48:14 -0700 | [diff] [blame] | 73 |  | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 74 |   status, output = commands.getstatusoutput(cmd) | 
 | 75 |   if status: | 
 | 76 |     print output | 
 | 77 |     return False, 0 | 
 | 78 |   return True, int(output) | 
 | 79 |  | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 80 | def GetVeritySize(partition_size, fec_supported): | 
 | 81 |   success, verity_tree_size = GetVerityTreeSize(partition_size) | 
 | 82 |   if not success: | 
 | 83 |     return 0 | 
 | 84 |   success, verity_metadata_size = GetVerityMetadataSize(partition_size) | 
 | 85 |   if not success: | 
 | 86 |     return 0 | 
 | 87 |   verity_size = verity_tree_size + verity_metadata_size | 
 | 88 |   if fec_supported: | 
 | 89 |     success, fec_size = GetVerityFECSize(partition_size + verity_size) | 
 | 90 |     if not success: | 
 | 91 |       return 0 | 
 | 92 |     return verity_size + fec_size | 
 | 93 |   return verity_size | 
 | 94 |  | 
| Sami Tolvanen | 405e71d | 2016-02-09 12:28:58 -0800 | [diff] [blame] | 95 | def GetSimgSize(image_file): | 
 | 96 |   simg = sparse_img.SparseImage(image_file, build_map=False) | 
 | 97 |   return simg.blocksize * simg.total_blocks | 
 | 98 |  | 
 | 99 | def ZeroPadSimg(image_file, pad_size): | 
 | 100 |   blocks = pad_size // BLOCK_SIZE | 
 | 101 |   print("Padding %d blocks (%d bytes)" % (blocks, pad_size)) | 
 | 102 |   simg = sparse_img.SparseImage(image_file, mode="r+b", build_map=False) | 
 | 103 |   simg.AppendFillChunk(0, blocks) | 
 | 104 |  | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 105 | def AdjustPartitionSizeForVerity(partition_size, fec_supported): | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 106 |   """Modifies the provided partition size to account for the verity metadata. | 
 | 107 |  | 
 | 108 |   This information is used to size the created image appropriately. | 
 | 109 |   Args: | 
 | 110 |     partition_size: the size of the partition to be verified. | 
 | 111 |   Returns: | 
 | 112 |     The size of the partition adjusted for verity metadata. | 
 | 113 |   """ | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 114 |   key = "%d %d" % (partition_size, fec_supported) | 
 | 115 |   if key in AdjustPartitionSizeForVerity.results: | 
 | 116 |     return AdjustPartitionSizeForVerity.results[key] | 
 | 117 |  | 
 | 118 |   hi = partition_size | 
 | 119 |   if hi % BLOCK_SIZE != 0: | 
 | 120 |     hi = (hi // BLOCK_SIZE) * BLOCK_SIZE | 
 | 121 |  | 
 | 122 |   # verity tree and fec sizes depend on the partition size, which | 
 | 123 |   # means this estimate is always going to be unnecessarily small | 
 | 124 |   lo = partition_size - GetVeritySize(hi, fec_supported) | 
 | 125 |   result = lo | 
 | 126 |  | 
 | 127 |   # do a binary search for the optimal size | 
 | 128 |   while lo < hi: | 
 | 129 |     i = ((lo + hi) // (2 * BLOCK_SIZE)) * BLOCK_SIZE | 
 | 130 |     size = i + GetVeritySize(i, fec_supported) | 
 | 131 |     if size <= partition_size: | 
 | 132 |       if result < i: | 
 | 133 |         result = i | 
 | 134 |       lo = i + BLOCK_SIZE | 
 | 135 |     else: | 
 | 136 |       hi = i | 
 | 137 |  | 
 | 138 |   AdjustPartitionSizeForVerity.results[key] = result | 
 | 139 |   return result | 
 | 140 |  | 
 | 141 | AdjustPartitionSizeForVerity.results = {} | 
 | 142 |  | 
| Sami Tolvanen | 4a06004 | 2015-12-18 15:50:25 +0000 | [diff] [blame] | 143 | def BuildVerityFEC(sparse_image_path, verity_path, verity_fec_path): | 
 | 144 |   cmd = "fec -e %s %s %s" % (sparse_image_path, verity_path, verity_fec_path) | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 145 |   print cmd | 
 | 146 |   status, output = commands.getstatusoutput(cmd) | 
 | 147 |   if status: | 
 | 148 |     print "Could not build FEC data! Error: %s" % output | 
 | 149 |     return False | 
 | 150 |   return True | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 151 |  | 
| Colin Cross | 477cf2b | 2014-04-16 18:49:56 -0700 | [diff] [blame] | 152 | def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict): | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 153 |   cmd = "build_verity_tree -A %s %s %s" % ( | 
 | 154 |       FIXED_SALT, sparse_image_path, verity_image_path) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 155 |   print cmd | 
 | 156 |   status, output = commands.getstatusoutput(cmd) | 
 | 157 |   if status: | 
 | 158 |     print "Could not build verity tree! Error: %s" % output | 
 | 159 |     return False | 
 | 160 |   root, salt = output.split() | 
 | 161 |   prop_dict["verity_root_hash"] = root | 
 | 162 |   prop_dict["verity_salt"] = salt | 
 | 163 |   return True | 
 | 164 |  | 
 | 165 | def BuildVerityMetadata(image_size, verity_metadata_path, root_hash, salt, | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 166 |                         block_device, signer_path, key, signer_args): | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 167 |   cmd_template = ( | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 168 |       "system/extras/verity/build_verity_metadata.py build " + | 
 | 169 |       "%s %s %s %s %s %s %s") | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 170 |   cmd = cmd_template % (image_size, verity_metadata_path, root_hash, salt, | 
 | 171 |                         block_device, signer_path, key) | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 172 |   if signer_args: | 
 | 173 |     cmd += " --signer_args=\"%s\"" % (' '.join(signer_args),) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 174 |   print cmd | 
 | 175 |   status, output = commands.getstatusoutput(cmd) | 
 | 176 |   if status: | 
 | 177 |     print "Could not build verity metadata! Error: %s" % output | 
 | 178 |     return False | 
 | 179 |   return True | 
 | 180 |  | 
 | 181 | def Append2Simg(sparse_image_path, unsparse_image_path, error_message): | 
 | 182 |   """Appends the unsparse image to the given sparse image. | 
 | 183 |  | 
 | 184 |   Args: | 
 | 185 |     sparse_image_path: the path to the (sparse) image | 
 | 186 |     unsparse_image_path: the path to the (unsparse) image | 
 | 187 |   Returns: | 
 | 188 |     True on success, False on failure. | 
 | 189 |   """ | 
 | 190 |   cmd = "append2simg %s %s" | 
 | 191 |   cmd %= (sparse_image_path, unsparse_image_path) | 
 | 192 |   print cmd | 
 | 193 |   status, output = commands.getstatusoutput(cmd) | 
 | 194 |   if status: | 
 | 195 |     print "%s: %s" % (error_message, output) | 
 | 196 |     return False | 
 | 197 |   return True | 
 | 198 |  | 
| Sami Tolvanen | ff914f5 | 2015-12-18 13:24:56 +0000 | [diff] [blame] | 199 | def Append(target, file_to_append, error_message): | 
 | 200 |   cmd = 'cat %s >> %s' % (file_to_append, target) | 
 | 201 |   print cmd | 
 | 202 |   status, output = commands.getstatusoutput(cmd) | 
 | 203 |   if status: | 
 | 204 |     print "%s: %s" % (error_message, output) | 
 | 205 |     return False | 
 | 206 |   return True | 
 | 207 |  | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 208 | def BuildVerifiedImage(data_image_path, verity_image_path, | 
| Sami Tolvanen | 4a06004 | 2015-12-18 15:50:25 +0000 | [diff] [blame] | 209 |                        verity_metadata_path, verity_fec_path, | 
 | 210 |                        fec_supported): | 
| Sami Tolvanen | ff914f5 | 2015-12-18 13:24:56 +0000 | [diff] [blame] | 211 |   if not Append(verity_image_path, verity_metadata_path, | 
 | 212 |                 "Could not append verity metadata!"): | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 213 |     return False | 
| Sami Tolvanen | 4a06004 | 2015-12-18 15:50:25 +0000 | [diff] [blame] | 214 |  | 
 | 215 |   if fec_supported: | 
 | 216 |     # build FEC for the entire partition, including metadata | 
 | 217 |     if not BuildVerityFEC(data_image_path, verity_image_path, | 
 | 218 |                           verity_fec_path): | 
 | 219 |       return False | 
 | 220 |  | 
 | 221 |     if not Append(verity_image_path, verity_fec_path, "Could not append FEC!"): | 
 | 222 |       return False | 
 | 223 |  | 
| Sami Tolvanen | ff914f5 | 2015-12-18 13:24:56 +0000 | [diff] [blame] | 224 |   if not Append2Simg(data_image_path, verity_image_path, | 
 | 225 |                      "Could not append verity data!"): | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 226 |     return False | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 227 |   return True | 
 | 228 |  | 
| Geremy Condra | 6e8f53c | 2013-12-05 17:09:18 -0800 | [diff] [blame] | 229 | def UnsparseImage(sparse_image_path, replace=True): | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 230 |   img_dir = os.path.dirname(sparse_image_path) | 
 | 231 |   unsparse_image_path = "unsparse_" + os.path.basename(sparse_image_path) | 
 | 232 |   unsparse_image_path = os.path.join(img_dir, unsparse_image_path) | 
 | 233 |   if os.path.exists(unsparse_image_path): | 
| Geremy Condra | 6e8f53c | 2013-12-05 17:09:18 -0800 | [diff] [blame] | 234 |     if replace: | 
 | 235 |       os.unlink(unsparse_image_path) | 
 | 236 |     else: | 
 | 237 |       return True, unsparse_image_path | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 238 |   inflate_command = ["simg2img", sparse_image_path, unsparse_image_path] | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 239 |   (_, exit_code) = RunCommand(inflate_command) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 240 |   if exit_code != 0: | 
 | 241 |     os.remove(unsparse_image_path) | 
 | 242 |     return False, None | 
 | 243 |   return True, unsparse_image_path | 
 | 244 |  | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 245 | def MakeVerityEnabledImage(out_file, fec_supported, prop_dict): | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 246 |   """Creates an image that is verifiable using dm-verity. | 
 | 247 |  | 
 | 248 |   Args: | 
 | 249 |     out_file: the location to write the verifiable image at | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 250 |     prop_dict: a dictionary of properties required for image creation and | 
 | 251 |                verification | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 252 |   Returns: | 
 | 253 |     True on success, False otherwise. | 
 | 254 |   """ | 
 | 255 |   # get properties | 
 | 256 |   image_size = prop_dict["partition_size"] | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 257 |   block_dev = prop_dict["verity_block_device"] | 
| Paul Lawrence | a37b2bb | 2014-11-13 17:54:30 -0800 | [diff] [blame] | 258 |   signer_key = prop_dict["verity_key"] + ".pk8" | 
| Baligh Uddin | 601ddea | 2015-06-09 15:48:14 -0700 | [diff] [blame] | 259 |   if OPTIONS.verity_signer_path is not None: | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 260 |     signer_path = OPTIONS.verity_signer_path | 
| Baligh Uddin | 601ddea | 2015-06-09 15:48:14 -0700 | [diff] [blame] | 261 |   else: | 
 | 262 |     signer_path = prop_dict["verity_signer_cmd"] | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 263 |   signer_args = OPTIONS.verity_signer_args | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 264 |  | 
 | 265 |   # make a tempdir | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 266 |   tempdir_name = tempfile.mkdtemp(suffix="_verity_images") | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 267 |  | 
 | 268 |   # get partial image paths | 
 | 269 |   verity_image_path = os.path.join(tempdir_name, "verity.img") | 
 | 270 |   verity_metadata_path = os.path.join(tempdir_name, "verity_metadata.img") | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 271 |   verity_fec_path = os.path.join(tempdir_name, "verity_fec.img") | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 272 |  | 
 | 273 |   # build the verity tree and get the root hash and salt | 
| Colin Cross | 477cf2b | 2014-04-16 18:49:56 -0700 | [diff] [blame] | 274 |   if not BuildVerityTree(out_file, verity_image_path, prop_dict): | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 275 |     shutil.rmtree(tempdir_name, ignore_errors=True) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 276 |     return False | 
 | 277 |  | 
 | 278 |   # build the metadata blocks | 
 | 279 |   root_hash = prop_dict["verity_root_hash"] | 
 | 280 |   salt = prop_dict["verity_salt"] | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 281 |   if not BuildVerityMetadata(image_size, verity_metadata_path, root_hash, salt, | 
| Tao Bao | c781483 | 2016-10-17 16:20:12 -0700 | [diff] [blame] | 282 |                              block_dev, signer_path, signer_key, signer_args): | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 283 |     shutil.rmtree(tempdir_name, ignore_errors=True) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 284 |     return False | 
 | 285 |  | 
 | 286 |   # build the full verified image | 
 | 287 |   if not BuildVerifiedImage(out_file, | 
 | 288 |                             verity_image_path, | 
| Sami Tolvanen | 4a06004 | 2015-12-18 15:50:25 +0000 | [diff] [blame] | 289 |                             verity_metadata_path, | 
 | 290 |                             verity_fec_path, | 
 | 291 |                             fec_supported): | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 292 |     shutil.rmtree(tempdir_name, ignore_errors=True) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 293 |     return False | 
 | 294 |  | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 295 |   shutil.rmtree(tempdir_name, ignore_errors=True) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 296 |   return True | 
 | 297 |  | 
| Mohamad Ayyash | f876555 | 2016-03-02 21:07:23 -0800 | [diff] [blame] | 298 | def ConvertBlockMapToBaseFs(block_map_file): | 
 | 299 |   fd, base_fs_file = tempfile.mkstemp(prefix="script_gen_", | 
 | 300 |                                       suffix=".base_fs") | 
 | 301 |   os.close(fd) | 
 | 302 |  | 
 | 303 |   convert_command = ["blk_alloc_to_base_fs", block_map_file, base_fs_file] | 
 | 304 |   (_, exit_code) = RunCommand(convert_command) | 
 | 305 |   if exit_code != 0: | 
 | 306 |     os.remove(base_fs_file) | 
 | 307 |     return None | 
 | 308 |   return base_fs_file | 
 | 309 |  | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 310 | def BuildImage(in_dir, prop_dict, out_file, target_out=None): | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 311 |   """Build an image to out_file from in_dir with property prop_dict. | 
 | 312 |  | 
 | 313 |   Args: | 
 | 314 |     in_dir: path of input directory. | 
 | 315 |     prop_dict: property dictionary. | 
 | 316 |     out_file: path of the output image file. | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 317 |     target_out: path of the product out directory to read device specific FS config files. | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 318 |  | 
 | 319 |   Returns: | 
 | 320 |     True iff the image is built successfully. | 
 | 321 |   """ | 
| Tao Bao | f3282b4 | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 322 |   # system_root_image=true: build a system.img that combines the contents of | 
 | 323 |   # /system and the ramdisk, and can be mounted at the root of the file system. | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 324 |   origin_in = in_dir | 
 | 325 |   fs_config = prop_dict.get("fs_config") | 
| Mohamad Ayyash | f876555 | 2016-03-02 21:07:23 -0800 | [diff] [blame] | 326 |   base_fs_file = None | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 327 |   if (prop_dict.get("system_root_image") == "true" | 
 | 328 |       and prop_dict["mount_point"] == "system"): | 
 | 329 |     in_dir = tempfile.mkdtemp() | 
 | 330 |     # Change the mount point to "/" | 
 | 331 |     prop_dict["mount_point"] = "/" | 
 | 332 |     if fs_config: | 
 | 333 |       # We need to merge the fs_config files of system and ramdisk. | 
 | 334 |       fd, merged_fs_config = tempfile.mkstemp(prefix="root_fs_config", | 
 | 335 |                                               suffix=".txt") | 
 | 336 |       os.close(fd) | 
 | 337 |       with open(merged_fs_config, "w") as fw: | 
 | 338 |         if "ramdisk_fs_config" in prop_dict: | 
 | 339 |           with open(prop_dict["ramdisk_fs_config"]) as fr: | 
 | 340 |             fw.writelines(fr.readlines()) | 
 | 341 |         with open(fs_config) as fr: | 
 | 342 |           fw.writelines(fr.readlines()) | 
 | 343 |       fs_config = merged_fs_config | 
 | 344 |  | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 345 |   build_command = [] | 
 | 346 |   fs_type = prop_dict.get("fs_type", "") | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 347 |   run_fsck = False | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 348 |  | 
| Mohamad Ayyash | dd06352 | 2015-03-24 12:42:03 -0700 | [diff] [blame] | 349 |   fs_spans_partition = True | 
 | 350 |   if fs_type.startswith("squash"): | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 351 |     fs_spans_partition = False | 
| Mohamad Ayyash | dd06352 | 2015-03-24 12:42:03 -0700 | [diff] [blame] | 352 |  | 
| Daniel Rosenberg | f4eabc3 | 2014-07-10 15:42:38 -0700 | [diff] [blame] | 353 |   is_verity_partition = "verity_block_device" in prop_dict | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 354 |   verity_supported = prop_dict.get("verity") == "true" | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 355 |   verity_fec_supported = prop_dict.get("verity_fec") == "true" | 
 | 356 |  | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 357 |   # Adjust the partition size to make room for the hashes if this is to be | 
 | 358 |   # verified. | 
| Sami Tolvanen | 405e71d | 2016-02-09 12:28:58 -0800 | [diff] [blame] | 359 |   if verity_supported and is_verity_partition: | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 360 |     partition_size = int(prop_dict.get("partition_size")) | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 361 |     adjusted_size = AdjustPartitionSizeForVerity(partition_size, | 
 | 362 |                                                  verity_fec_supported) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 363 |     if not adjusted_size: | 
 | 364 |       return False | 
 | 365 |     prop_dict["partition_size"] = str(adjusted_size) | 
 | 366 |     prop_dict["original_partition_size"] = str(partition_size) | 
 | 367 |  | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 368 |   if fs_type.startswith("ext"): | 
 | 369 |     build_command = ["mkuserimg.sh"] | 
 | 370 |     if "extfs_sparse_flag" in prop_dict: | 
 | 371 |       build_command.append(prop_dict["extfs_sparse_flag"]) | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 372 |       run_fsck = True | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 373 |     build_command.extend([in_dir, out_file, fs_type, | 
 | 374 |                           prop_dict["mount_point"]]) | 
| Doug Zongker | 850b807 | 2013-12-05 15:54:55 -0800 | [diff] [blame] | 375 |     build_command.append(prop_dict["partition_size"]) | 
| Ying Wang | f3b8635 | 2014-11-18 18:03:13 -0800 | [diff] [blame] | 376 |     if "journal_size" in prop_dict: | 
 | 377 |       build_command.extend(["-j", prop_dict["journal_size"]]) | 
| Doug Zongker | 850b807 | 2013-12-05 15:54:55 -0800 | [diff] [blame] | 378 |     if "timestamp" in prop_dict: | 
 | 379 |       build_command.extend(["-T", str(prop_dict["timestamp"])]) | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 380 |     if fs_config: | 
| Doug Zongker | 8282282 | 2014-06-16 09:10:55 -0700 | [diff] [blame] | 381 |       build_command.extend(["-C", fs_config]) | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 382 |     if target_out: | 
 | 383 |       build_command.extend(["-D", target_out]) | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 384 |     if "block_list" in prop_dict: | 
 | 385 |       build_command.extend(["-B", prop_dict["block_list"]]) | 
| Mohamad Ayyash | f876555 | 2016-03-02 21:07:23 -0800 | [diff] [blame] | 386 |     if "base_fs_file" in prop_dict: | 
 | 387 |       base_fs_file = ConvertBlockMapToBaseFs(prop_dict["base_fs_file"]) | 
 | 388 |       if base_fs_file is None: | 
 | 389 |         return False | 
 | 390 |       build_command.extend(["-d", base_fs_file]) | 
| Christoffer Dall | 8ed01f3 | 2014-12-17 21:34:12 +0100 | [diff] [blame] | 391 |     build_command.extend(["-L", prop_dict["mount_point"]]) | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 392 |     if "selinux_fc" in prop_dict: | 
| Kenny Root | f32dc71 | 2012-04-08 10:42:34 -0700 | [diff] [blame] | 393 |       build_command.append(prop_dict["selinux_fc"]) | 
| Mohamad Ayyash | b97746e | 2015-03-03 12:30:37 -0800 | [diff] [blame] | 394 |   elif fs_type.startswith("squash"): | 
 | 395 |     build_command = ["mksquashfsimage.sh"] | 
 | 396 |     build_command.extend([in_dir, out_file]) | 
| Todd Poynor | b2a555e | 2015-12-15 18:00:14 -0800 | [diff] [blame] | 397 |     if "squashfs_sparse_flag" in prop_dict: | 
 | 398 |       build_command.extend([prop_dict["squashfs_sparse_flag"]]) | 
| Mohamad Ayyash | b97746e | 2015-03-03 12:30:37 -0800 | [diff] [blame] | 399 |     build_command.extend(["-m", prop_dict["mount_point"]]) | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 400 |     if target_out: | 
 | 401 |       build_command.extend(["-d", target_out]) | 
| Mohamad Ayyash | 8837882 | 2016-04-07 22:10:51 -0700 | [diff] [blame] | 402 |     if fs_config: | 
 | 403 |       build_command.extend(["-C", fs_config]) | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 404 |     if "selinux_fc" in prop_dict: | 
| Mohamad Ayyash | b97746e | 2015-03-03 12:30:37 -0800 | [diff] [blame] | 405 |       build_command.extend(["-c", prop_dict["selinux_fc"]]) | 
| Mohamad Ayyash | c3484f7 | 2016-06-13 09:46:58 -0700 | [diff] [blame] | 406 |     if "block_list" in prop_dict: | 
 | 407 |       build_command.extend(["-B", prop_dict["block_list"]]) | 
| Simon Wilson | f86e7ee | 2015-06-17 12:35:15 -0700 | [diff] [blame] | 408 |     if "squashfs_compressor" in prop_dict: | 
 | 409 |       build_command.extend(["-z", prop_dict["squashfs_compressor"]]) | 
 | 410 |     if "squashfs_compressor_opt" in prop_dict: | 
 | 411 |       build_command.extend(["-zo", prop_dict["squashfs_compressor_opt"]]) | 
| Mohamad Ayyash | 1b6d348 | 2016-06-15 15:53:07 -0700 | [diff] [blame] | 412 |     if "squashfs_disable_4k_align" in prop_dict and prop_dict.get("squashfs_disable_4k_align") == "true": | 
 | 413 |       build_command.extend(["-a"]) | 
| JP Abgrall | 5bfed5a | 2014-06-16 14:17:40 -0700 | [diff] [blame] | 414 |   elif fs_type.startswith("f2fs"): | 
 | 415 |     build_command = ["mkf2fsuserimg.sh"] | 
 | 416 |     build_command.extend([out_file, prop_dict["partition_size"]]) | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 417 |   else: | 
 | 418 |     build_command = ["mkyaffs2image", "-f"] | 
 | 419 |     if prop_dict.get("mkyaffs2_extra_flags", None): | 
 | 420 |       build_command.extend(prop_dict["mkyaffs2_extra_flags"].split()) | 
 | 421 |     build_command.append(in_dir) | 
 | 422 |     build_command.append(out_file) | 
| Kenny Root | f32dc71 | 2012-04-08 10:42:34 -0700 | [diff] [blame] | 423 |     if "selinux_fc" in prop_dict: | 
 | 424 |       build_command.append(prop_dict["selinux_fc"]) | 
 | 425 |       build_command.append(prop_dict["mount_point"]) | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 426 |  | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 427 |   if in_dir != origin_in: | 
 | 428 |     # Construct a staging directory of the root file system. | 
 | 429 |     ramdisk_dir = prop_dict.get("ramdisk_dir") | 
 | 430 |     if ramdisk_dir: | 
 | 431 |       shutil.rmtree(in_dir) | 
 | 432 |       shutil.copytree(ramdisk_dir, in_dir, symlinks=True) | 
 | 433 |     staging_system = os.path.join(in_dir, "system") | 
 | 434 |     shutil.rmtree(staging_system, ignore_errors=True) | 
 | 435 |     shutil.copytree(origin_in, staging_system, symlinks=True) | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 436 |  | 
 | 437 |   reserved_blocks = prop_dict.get("has_ext4_reserved_blocks") == "true" | 
 | 438 |   ext4fs_output = None | 
 | 439 |  | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 440 |   try: | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 441 |     if reserved_blocks and fs_type.startswith("ext4"): | 
 | 442 |       (ext4fs_output, exit_code) = RunCommand(build_command) | 
 | 443 |     else: | 
 | 444 |       (_, exit_code) = RunCommand(build_command) | 
| Ying Wang | a2292c9 | 2015-03-24 19:07:40 -0700 | [diff] [blame] | 445 |   finally: | 
 | 446 |     if in_dir != origin_in: | 
 | 447 |       # Clean up temporary directories and files. | 
 | 448 |       shutil.rmtree(in_dir, ignore_errors=True) | 
 | 449 |       if fs_config: | 
 | 450 |         os.remove(fs_config) | 
| Mohamad Ayyash | f876555 | 2016-03-02 21:07:23 -0800 | [diff] [blame] | 451 |     if base_fs_file is not None: | 
 | 452 |       os.remove(base_fs_file) | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 453 |   if exit_code != 0: | 
 | 454 |     return False | 
 | 455 |  | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 456 |   # Bug: 21522719, 22023465 | 
 | 457 |   # There are some reserved blocks on ext4 FS (lesser of 4096 blocks and 2%). | 
 | 458 |   # We need to deduct those blocks from the available space, since they are | 
 | 459 |   # not writable even with root privilege. It only affects devices using | 
 | 460 |   # file-based OTA and a kernel version of 3.10 or greater (currently just | 
 | 461 |   # sprout). | 
 | 462 |   if reserved_blocks and fs_type.startswith("ext4"): | 
 | 463 |     assert ext4fs_output is not None | 
 | 464 |     ext4fs_stats = re.compile( | 
 | 465 |         r'Created filesystem with .* (?P<used_blocks>[0-9]+)/' | 
 | 466 |         r'(?P<total_blocks>[0-9]+) blocks') | 
 | 467 |     m = ext4fs_stats.match(ext4fs_output.strip().split('\n')[-1]) | 
 | 468 |     used_blocks = int(m.groupdict().get('used_blocks')) | 
 | 469 |     total_blocks = int(m.groupdict().get('total_blocks')) | 
 | 470 |     reserved_blocks = min(4096, int(total_blocks * 0.02)) | 
 | 471 |     adjusted_blocks = total_blocks - reserved_blocks | 
 | 472 |     if used_blocks > adjusted_blocks: | 
 | 473 |       mount_point = prop_dict.get("mount_point") | 
 | 474 |       print("Error: Not enough room on %s (total: %d blocks, used: %d blocks, " | 
 | 475 |             "reserved: %d blocks, available: %d blocks)" % ( | 
 | 476 |                 mount_point, total_blocks, used_blocks, reserved_blocks, | 
 | 477 |                 adjusted_blocks)) | 
 | 478 |       return False | 
 | 479 |  | 
| Mohamad Ayyash | dd06352 | 2015-03-24 12:42:03 -0700 | [diff] [blame] | 480 |   if not fs_spans_partition: | 
 | 481 |     mount_point = prop_dict.get("mount_point") | 
 | 482 |     partition_size = int(prop_dict.get("partition_size")) | 
| Sami Tolvanen | 405e71d | 2016-02-09 12:28:58 -0800 | [diff] [blame] | 483 |     image_size = GetSimgSize(out_file) | 
| Mohamad Ayyash | dd06352 | 2015-03-24 12:42:03 -0700 | [diff] [blame] | 484 |     if image_size > partition_size: | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 485 |       print("Error: %s image size of %d is larger than partition size of " | 
 | 486 |             "%d" % (mount_point, image_size, partition_size)) | 
 | 487 |       return False | 
| Mohamad Ayyash | dd06352 | 2015-03-24 12:42:03 -0700 | [diff] [blame] | 488 |     if verity_supported and is_verity_partition: | 
| Sami Tolvanen | 405e71d | 2016-02-09 12:28:58 -0800 | [diff] [blame] | 489 |       ZeroPadSimg(out_file, partition_size - image_size) | 
| Mohamad Ayyash | dd06352 | 2015-03-24 12:42:03 -0700 | [diff] [blame] | 490 |  | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 491 |   # create the verified image if this is to be verified | 
| Geremy Condra | 5b5f495 | 2014-05-05 22:19:37 -0700 | [diff] [blame] | 492 |   if verity_supported and is_verity_partition: | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 493 |     if not MakeVerityEnabledImage(out_file, verity_fec_supported, prop_dict): | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 494 |       return False | 
 | 495 |  | 
| Ying Wang | 6a42a25 | 2013-02-27 13:54:02 -0800 | [diff] [blame] | 496 |   if run_fsck and prop_dict.get("skip_fsck") != "true": | 
| Geremy Condra | 6e8f53c | 2013-12-05 17:09:18 -0800 | [diff] [blame] | 497 |     success, unsparse_image = UnsparseImage(out_file, replace=False) | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 498 |     if not success: | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 499 |       return False | 
 | 500 |  | 
 | 501 |     # Run e2fsck on the inflated image file | 
 | 502 |     e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image] | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 503 |     (_, exit_code) = RunCommand(e2fsck_command) | 
| Ying Wang | 69e9b4d | 2012-11-26 18:10:23 -0800 | [diff] [blame] | 504 |  | 
 | 505 |     os.remove(unsparse_image) | 
 | 506 |  | 
 | 507 |   return exit_code == 0 | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 508 |  | 
 | 509 |  | 
 | 510 | def ImagePropFromGlobalDict(glob_dict, mount_point): | 
 | 511 |   """Build an image property dictionary from the global dictionary. | 
 | 512 |  | 
 | 513 |   Args: | 
 | 514 |     glob_dict: the global dictionary from the build system. | 
 | 515 |     mount_point: such as "system", "data" etc. | 
 | 516 |   """ | 
| Doug Zongker | 1ad7ade | 2013-12-06 11:53:27 -0800 | [diff] [blame] | 517 |   d = {} | 
| Tao Bao | 052ae35 | 2015-09-28 13:44:13 -0700 | [diff] [blame] | 518 |  | 
| Tao Bao | 822f584 | 2015-09-30 16:01:14 -0700 | [diff] [blame] | 519 |   if "build.prop" in glob_dict: | 
 | 520 |     bp = glob_dict["build.prop"] | 
 | 521 |     if "ro.build.date.utc" in bp: | 
 | 522 |       d["timestamp"] = bp["ro.build.date.utc"] | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 523 |  | 
 | 524 |   def copy_prop(src_p, dest_p): | 
 | 525 |     if src_p in glob_dict: | 
 | 526 |       d[dest_p] = str(glob_dict[src_p]) | 
 | 527 |  | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 528 |   common_props = ( | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 529 |       "extfs_sparse_flag", | 
| Todd Poynor | b2a555e | 2015-12-15 18:00:14 -0800 | [diff] [blame] | 530 |       "squashfs_sparse_flag", | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 531 |       "mkyaffs2_extra_flags", | 
| Kenny Root | f32dc71 | 2012-04-08 10:42:34 -0700 | [diff] [blame] | 532 |       "selinux_fc", | 
| Ying Wang | 6a42a25 | 2013-02-27 13:54:02 -0800 | [diff] [blame] | 533 |       "skip_fsck", | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 534 |       "verity", | 
| Geremy Condra | fd6f751 | 2013-06-16 17:26:08 -0700 | [diff] [blame] | 535 |       "verity_key", | 
| Sami Tolvanen | f99b531 | 2015-05-20 07:30:57 +0100 | [diff] [blame] | 536 |       "verity_signer_cmd", | 
 | 537 |       "verity_fec" | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 538 |       ) | 
 | 539 |   for p in common_props: | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 540 |     copy_prop(p, p) | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 541 |  | 
 | 542 |   d["mount_point"] = mount_point | 
 | 543 |   if mount_point == "system": | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 544 |     copy_prop("fs_type", "fs_type") | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 545 |     # Copy the generic sysetem fs type first, override with specific one if | 
 | 546 |     # available. | 
| Mohamad Ayyash | b97746e | 2015-03-03 12:30:37 -0800 | [diff] [blame] | 547 |     copy_prop("system_fs_type", "fs_type") | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 548 |     copy_prop("system_size", "partition_size") | 
| Ying Wang | f3b8635 | 2014-11-18 18:03:13 -0800 | [diff] [blame] | 549 |     copy_prop("system_journal_size", "journal_size") | 
| Daniel Rosenberg | f4eabc3 | 2014-07-10 15:42:38 -0700 | [diff] [blame] | 550 |     copy_prop("system_verity_block_device", "verity_block_device") | 
| Tao Bao | f3282b4 | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 551 |     copy_prop("system_root_image", "system_root_image") | 
 | 552 |     copy_prop("ramdisk_dir", "ramdisk_dir") | 
| Tao Bao | 84e7568 | 2015-07-19 02:38:53 -0700 | [diff] [blame] | 553 |     copy_prop("ramdisk_fs_config", "ramdisk_fs_config") | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 554 |     copy_prop("has_ext4_reserved_blocks", "has_ext4_reserved_blocks") | 
| Simon Wilson | f86e7ee | 2015-06-17 12:35:15 -0700 | [diff] [blame] | 555 |     copy_prop("system_squashfs_compressor", "squashfs_compressor") | 
 | 556 |     copy_prop("system_squashfs_compressor_opt", "squashfs_compressor_opt") | 
| Mohamad Ayyash | 1b6d348 | 2016-06-15 15:53:07 -0700 | [diff] [blame] | 557 |     copy_prop("system_squashfs_disable_4k_align", "squashfs_disable_4k_align") | 
| Mohamad Ayyash | f876555 | 2016-03-02 21:07:23 -0800 | [diff] [blame] | 558 |     copy_prop("system_base_fs_file", "base_fs_file") | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 559 |   elif mount_point == "data": | 
| JP Abgrall | 5bfed5a | 2014-06-16 14:17:40 -0700 | [diff] [blame] | 560 |     # Copy the generic fs type first, override with specific one if available. | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 561 |     copy_prop("fs_type", "fs_type") | 
| JP Abgrall | 5bfed5a | 2014-06-16 14:17:40 -0700 | [diff] [blame] | 562 |     copy_prop("userdata_fs_type", "fs_type") | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 563 |     copy_prop("userdata_size", "partition_size") | 
 | 564 |   elif mount_point == "cache": | 
 | 565 |     copy_prop("cache_fs_type", "fs_type") | 
 | 566 |     copy_prop("cache_size", "partition_size") | 
| Ying Wang | a0febe5 | 2013-03-20 11:02:05 -0700 | [diff] [blame] | 567 |   elif mount_point == "vendor": | 
 | 568 |     copy_prop("vendor_fs_type", "fs_type") | 
 | 569 |     copy_prop("vendor_size", "partition_size") | 
| Ying Wang | f3b8635 | 2014-11-18 18:03:13 -0800 | [diff] [blame] | 570 |     copy_prop("vendor_journal_size", "journal_size") | 
| Daniel Rosenberg | f4eabc3 | 2014-07-10 15:42:38 -0700 | [diff] [blame] | 571 |     copy_prop("vendor_verity_block_device", "verity_block_device") | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 572 |     copy_prop("has_ext4_reserved_blocks", "has_ext4_reserved_blocks") | 
| Patrick Tjin | e11aa50 | 2016-02-09 15:40:38 -0800 | [diff] [blame] | 573 |     copy_prop("vendor_squashfs_compressor", "squashfs_compressor") | 
 | 574 |     copy_prop("vendor_squashfs_compressor_opt", "squashfs_compressor_opt") | 
| Mohamad Ayyash | 1b6d348 | 2016-06-15 15:53:07 -0700 | [diff] [blame] | 575 |     copy_prop("vendor_squashfs_disable_4k_align", "squashfs_disable_4k_align") | 
| Mohamad Ayyash | f876555 | 2016-03-02 21:07:23 -0800 | [diff] [blame] | 576 |     copy_prop("vendor_base_fs_file", "base_fs_file") | 
| Ying Wang | b888843 | 2014-03-11 17:13:27 -0700 | [diff] [blame] | 577 |   elif mount_point == "oem": | 
 | 578 |     copy_prop("fs_type", "fs_type") | 
 | 579 |     copy_prop("oem_size", "partition_size") | 
| Ying Wang | f3b8635 | 2014-11-18 18:03:13 -0800 | [diff] [blame] | 580 |     copy_prop("oem_journal_size", "journal_size") | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 581 |     copy_prop("has_ext4_reserved_blocks", "has_ext4_reserved_blocks") | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 582 |  | 
 | 583 |   return d | 
 | 584 |  | 
 | 585 |  | 
 | 586 | def LoadGlobalDict(filename): | 
 | 587 |   """Load "name=value" pairs from filename""" | 
 | 588 |   d = {} | 
 | 589 |   f = open(filename) | 
 | 590 |   for line in f: | 
 | 591 |     line = line.strip() | 
 | 592 |     if not line or line.startswith("#"): | 
 | 593 |       continue | 
 | 594 |     k, v = line.split("=", 1) | 
 | 595 |     d[k] = v | 
 | 596 |   f.close() | 
 | 597 |   return d | 
 | 598 |  | 
 | 599 |  | 
 | 600 | def main(argv): | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 601 |   if len(argv) != 4: | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 602 |     print __doc__ | 
 | 603 |     sys.exit(1) | 
 | 604 |  | 
 | 605 |   in_dir = argv[0] | 
 | 606 |   glob_dict_file = argv[1] | 
 | 607 |   out_file = argv[2] | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 608 |   target_out = argv[3] | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 609 |  | 
 | 610 |   glob_dict = LoadGlobalDict(glob_dict_file) | 
| Ying Wang | ae61f50 | 2015-03-12 18:30:39 -0700 | [diff] [blame] | 611 |   if "mount_point" in glob_dict: | 
| Tao Bao | c7a6f1e | 2015-06-23 11:16:05 -0700 | [diff] [blame] | 612 |     # The caller knows the mount point and provides a dictionay needed by | 
 | 613 |     # BuildImage(). | 
| Ying Wang | ae61f50 | 2015-03-12 18:30:39 -0700 | [diff] [blame] | 614 |     image_properties = glob_dict | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 615 |   else: | 
| Ying Wang | ae61f50 | 2015-03-12 18:30:39 -0700 | [diff] [blame] | 616 |     image_filename = os.path.basename(out_file) | 
 | 617 |     mount_point = "" | 
 | 618 |     if image_filename == "system.img": | 
 | 619 |       mount_point = "system" | 
 | 620 |     elif image_filename == "userdata.img": | 
 | 621 |       mount_point = "data" | 
 | 622 |     elif image_filename == "cache.img": | 
 | 623 |       mount_point = "cache" | 
 | 624 |     elif image_filename == "vendor.img": | 
 | 625 |       mount_point = "vendor" | 
 | 626 |     elif image_filename == "oem.img": | 
 | 627 |       mount_point = "oem" | 
 | 628 |     else: | 
 | 629 |       print >> sys.stderr, "error: unknown image file name ", image_filename | 
 | 630 |       exit(1) | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 631 |  | 
| Ying Wang | ae61f50 | 2015-03-12 18:30:39 -0700 | [diff] [blame] | 632 |     image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) | 
 | 633 |  | 
| Thierry Strudel | 74a81e6 | 2015-07-09 09:54:55 -0700 | [diff] [blame] | 634 |   if not BuildImage(in_dir, image_properties, out_file, target_out): | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 635 |     print >> sys.stderr, "error: failed to build %s from %s" % (out_file, | 
 | 636 |                                                                 in_dir) | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 637 |     exit(1) | 
 | 638 |  | 
 | 639 |  | 
 | 640 | if __name__ == '__main__': | 
 | 641 |   main(sys.argv[1:]) |