xref: /aosp_15_r20/build/make/tools/releasetools/verity_utils.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python
2*9e94795aSAndroid Build Coastguard Worker#
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2018 The Android Open Source Project
4*9e94795aSAndroid Build Coastguard Worker#
5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*9e94795aSAndroid Build Coastguard Worker#
11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Worker"""
18*9e94795aSAndroid Build Coastguard WorkerSigns a given image using avbtool
19*9e94795aSAndroid Build Coastguard Worker
20*9e94795aSAndroid Build Coastguard WorkerUsage:  verity_utils properties_file output_image
21*9e94795aSAndroid Build Coastguard Worker"""
22*9e94795aSAndroid Build Coastguard Worker
23*9e94795aSAndroid Build Coastguard Workerfrom __future__ import print_function
24*9e94795aSAndroid Build Coastguard Worker
25*9e94795aSAndroid Build Coastguard Workerimport logging
26*9e94795aSAndroid Build Coastguard Workerimport os.path
27*9e94795aSAndroid Build Coastguard Workerimport shlex
28*9e94795aSAndroid Build Coastguard Workerimport struct
29*9e94795aSAndroid Build Coastguard Workerimport sys
30*9e94795aSAndroid Build Coastguard Worker
31*9e94795aSAndroid Build Coastguard Workerimport common
32*9e94795aSAndroid Build Coastguard Workerimport sparse_img
33*9e94795aSAndroid Build Coastguard Workerfrom rangelib import RangeSet
34*9e94795aSAndroid Build Coastguard Workerfrom hashlib import sha256
35*9e94795aSAndroid Build Coastguard Worker
36*9e94795aSAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
37*9e94795aSAndroid Build Coastguard Worker
38*9e94795aSAndroid Build Coastguard WorkerOPTIONS = common.OPTIONS
39*9e94795aSAndroid Build Coastguard WorkerBLOCK_SIZE = common.BLOCK_SIZE
40*9e94795aSAndroid Build Coastguard WorkerFIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7"
41*9e94795aSAndroid Build Coastguard Worker
42*9e94795aSAndroid Build Coastguard Worker# From external/avb/avbtool.py
43*9e94795aSAndroid Build Coastguard WorkerMAX_VBMETA_SIZE = 64 * 1024
44*9e94795aSAndroid Build Coastguard WorkerMAX_FOOTER_SIZE = 4096
45*9e94795aSAndroid Build Coastguard Worker
46*9e94795aSAndroid Build Coastguard Worker
47*9e94795aSAndroid Build Coastguard Workerclass BuildVerityImageError(Exception):
48*9e94795aSAndroid Build Coastguard Worker  """An Exception raised during verity image building."""
49*9e94795aSAndroid Build Coastguard Worker
50*9e94795aSAndroid Build Coastguard Worker  def __init__(self, message):
51*9e94795aSAndroid Build Coastguard Worker    Exception.__init__(self, message)
52*9e94795aSAndroid Build Coastguard Worker
53*9e94795aSAndroid Build Coastguard Worker
54*9e94795aSAndroid Build Coastguard Workerdef CreateVerityImageBuilder(prop_dict):
55*9e94795aSAndroid Build Coastguard Worker  """Returns a verity image builder based on the given build properties.
56*9e94795aSAndroid Build Coastguard Worker
57*9e94795aSAndroid Build Coastguard Worker  Args:
58*9e94795aSAndroid Build Coastguard Worker    prop_dict: A dict that contains the build properties. In particular, it will
59*9e94795aSAndroid Build Coastguard Worker        look for verity-related property values.
60*9e94795aSAndroid Build Coastguard Worker
61*9e94795aSAndroid Build Coastguard Worker  Returns:
62*9e94795aSAndroid Build Coastguard Worker    A VerityImageBuilder instance for Verified Boot 1.0 or Verified Boot 2.0; or
63*9e94795aSAndroid Build Coastguard Worker        None if the given build doesn't support Verified Boot.
64*9e94795aSAndroid Build Coastguard Worker  """
65*9e94795aSAndroid Build Coastguard Worker  partition_size = prop_dict.get("partition_size")
66*9e94795aSAndroid Build Coastguard Worker  # partition_size could be None at this point, if using dynamic partitions.
67*9e94795aSAndroid Build Coastguard Worker  if partition_size:
68*9e94795aSAndroid Build Coastguard Worker    partition_size = int(partition_size)
69*9e94795aSAndroid Build Coastguard Worker  # Set up the salt (based on fingerprint) that will be used when adding AVB
70*9e94795aSAndroid Build Coastguard Worker  # hash / hashtree footers.
71*9e94795aSAndroid Build Coastguard Worker  salt = prop_dict.get("avb_salt")
72*9e94795aSAndroid Build Coastguard Worker  if salt is None:
73*9e94795aSAndroid Build Coastguard Worker    salt = sha256(prop_dict.get("fingerprint", "").encode()).hexdigest()
74*9e94795aSAndroid Build Coastguard Worker
75*9e94795aSAndroid Build Coastguard Worker  # Verified Boot 2.0
76*9e94795aSAndroid Build Coastguard Worker  if (prop_dict.get("avb_hash_enable") == "true" or
77*9e94795aSAndroid Build Coastguard Worker      prop_dict.get("avb_hashtree_enable") == "true"):
78*9e94795aSAndroid Build Coastguard Worker    # key_path and algorithm are only available when chain partition is used.
79*9e94795aSAndroid Build Coastguard Worker    key_path = prop_dict.get("avb_key_path")
80*9e94795aSAndroid Build Coastguard Worker    algorithm = prop_dict.get("avb_algorithm")
81*9e94795aSAndroid Build Coastguard Worker
82*9e94795aSAndroid Build Coastguard Worker    # Image uses hash footer.
83*9e94795aSAndroid Build Coastguard Worker    if prop_dict.get("avb_hash_enable") == "true":
84*9e94795aSAndroid Build Coastguard Worker      return VerifiedBootVersion2VerityImageBuilder(
85*9e94795aSAndroid Build Coastguard Worker          prop_dict["partition_name"],
86*9e94795aSAndroid Build Coastguard Worker          partition_size,
87*9e94795aSAndroid Build Coastguard Worker          VerifiedBootVersion2VerityImageBuilder.AVB_HASH_FOOTER,
88*9e94795aSAndroid Build Coastguard Worker          prop_dict["avb_avbtool"],
89*9e94795aSAndroid Build Coastguard Worker          key_path,
90*9e94795aSAndroid Build Coastguard Worker          algorithm,
91*9e94795aSAndroid Build Coastguard Worker          salt,
92*9e94795aSAndroid Build Coastguard Worker          prop_dict["avb_add_hash_footer_args"])
93*9e94795aSAndroid Build Coastguard Worker
94*9e94795aSAndroid Build Coastguard Worker    # Image uses hashtree footer.
95*9e94795aSAndroid Build Coastguard Worker    return VerifiedBootVersion2VerityImageBuilder(
96*9e94795aSAndroid Build Coastguard Worker        prop_dict["partition_name"],
97*9e94795aSAndroid Build Coastguard Worker        partition_size,
98*9e94795aSAndroid Build Coastguard Worker        VerifiedBootVersion2VerityImageBuilder.AVB_HASHTREE_FOOTER,
99*9e94795aSAndroid Build Coastguard Worker        prop_dict["avb_avbtool"],
100*9e94795aSAndroid Build Coastguard Worker        key_path,
101*9e94795aSAndroid Build Coastguard Worker        algorithm,
102*9e94795aSAndroid Build Coastguard Worker        salt,
103*9e94795aSAndroid Build Coastguard Worker        prop_dict["avb_add_hashtree_footer_args"])
104*9e94795aSAndroid Build Coastguard Worker
105*9e94795aSAndroid Build Coastguard Worker  return None
106*9e94795aSAndroid Build Coastguard Worker
107*9e94795aSAndroid Build Coastguard Worker
108*9e94795aSAndroid Build Coastguard Workerclass VerityImageBuilder(object):
109*9e94795aSAndroid Build Coastguard Worker  """A builder that generates an image with verity metadata for Verified Boot.
110*9e94795aSAndroid Build Coastguard Worker
111*9e94795aSAndroid Build Coastguard Worker  A VerityImageBuilder instance handles the works for building an image with
112*9e94795aSAndroid Build Coastguard Worker  verity metadata for supporting Android Verified Boot. This class defines the
113*9e94795aSAndroid Build Coastguard Worker  common interface between Verified Boot 1.0 and Verified Boot 2.0. A matching
114*9e94795aSAndroid Build Coastguard Worker  builder will be returned based on the given build properties.
115*9e94795aSAndroid Build Coastguard Worker
116*9e94795aSAndroid Build Coastguard Worker  More info on the verity image generation can be found at the following link.
117*9e94795aSAndroid Build Coastguard Worker  https://source.android.com/security/verifiedboot/dm-verity#implementation
118*9e94795aSAndroid Build Coastguard Worker  """
119*9e94795aSAndroid Build Coastguard Worker
120*9e94795aSAndroid Build Coastguard Worker  def CalculateMaxImageSize(self, partition_size):
121*9e94795aSAndroid Build Coastguard Worker    """Calculates the filesystem image size for the given partition size."""
122*9e94795aSAndroid Build Coastguard Worker    raise NotImplementedError
123*9e94795aSAndroid Build Coastguard Worker
124*9e94795aSAndroid Build Coastguard Worker  def CalculateDynamicPartitionSize(self, image_size):
125*9e94795aSAndroid Build Coastguard Worker    """Calculates and sets the partition size for a dynamic partition."""
126*9e94795aSAndroid Build Coastguard Worker    raise NotImplementedError
127*9e94795aSAndroid Build Coastguard Worker
128*9e94795aSAndroid Build Coastguard Worker  def PadSparseImage(self, out_file):
129*9e94795aSAndroid Build Coastguard Worker    """Adds padding to the generated sparse image."""
130*9e94795aSAndroid Build Coastguard Worker    raise NotImplementedError
131*9e94795aSAndroid Build Coastguard Worker
132*9e94795aSAndroid Build Coastguard Worker  def Build(self, out_file):
133*9e94795aSAndroid Build Coastguard Worker    """Builds the verity image and writes it to the given file."""
134*9e94795aSAndroid Build Coastguard Worker    raise NotImplementedError
135*9e94795aSAndroid Build Coastguard Worker
136*9e94795aSAndroid Build Coastguard Worker
137*9e94795aSAndroid Build Coastguard Workerclass VerifiedBootVersion2VerityImageBuilder(VerityImageBuilder):
138*9e94795aSAndroid Build Coastguard Worker  """A VerityImageBuilder for Verified Boot 2.0."""
139*9e94795aSAndroid Build Coastguard Worker
140*9e94795aSAndroid Build Coastguard Worker  AVB_HASH_FOOTER = 1
141*9e94795aSAndroid Build Coastguard Worker  AVB_HASHTREE_FOOTER = 2
142*9e94795aSAndroid Build Coastguard Worker
143*9e94795aSAndroid Build Coastguard Worker  def __init__(self, partition_name, partition_size, footer_type, avbtool,
144*9e94795aSAndroid Build Coastguard Worker               key_path, algorithm, salt, signing_args):
145*9e94795aSAndroid Build Coastguard Worker    self.version = 2
146*9e94795aSAndroid Build Coastguard Worker    self.partition_name = partition_name
147*9e94795aSAndroid Build Coastguard Worker    self.partition_size = partition_size
148*9e94795aSAndroid Build Coastguard Worker    self.footer_type = footer_type
149*9e94795aSAndroid Build Coastguard Worker    self.avbtool = avbtool
150*9e94795aSAndroid Build Coastguard Worker    self.algorithm = algorithm
151*9e94795aSAndroid Build Coastguard Worker    self.key_path = common.ResolveAVBSigningPathArgs(key_path)
152*9e94795aSAndroid Build Coastguard Worker
153*9e94795aSAndroid Build Coastguard Worker    self.salt = salt
154*9e94795aSAndroid Build Coastguard Worker    self.signing_args = signing_args
155*9e94795aSAndroid Build Coastguard Worker    self.image_size = None
156*9e94795aSAndroid Build Coastguard Worker
157*9e94795aSAndroid Build Coastguard Worker  def CalculateMinPartitionSize(self, image_size, size_calculator=None):
158*9e94795aSAndroid Build Coastguard Worker    """Calculates min partition size for a given image size.
159*9e94795aSAndroid Build Coastguard Worker
160*9e94795aSAndroid Build Coastguard Worker    This is used when determining the partition size for a dynamic partition,
161*9e94795aSAndroid Build Coastguard Worker    which should be cover the given image size (for filesystem files) as well as
162*9e94795aSAndroid Build Coastguard Worker    the verity metadata size.
163*9e94795aSAndroid Build Coastguard Worker
164*9e94795aSAndroid Build Coastguard Worker    Args:
165*9e94795aSAndroid Build Coastguard Worker      image_size: The size of the image in question.
166*9e94795aSAndroid Build Coastguard Worker      size_calculator: The function to calculate max image size
167*9e94795aSAndroid Build Coastguard Worker          for a given partition size.
168*9e94795aSAndroid Build Coastguard Worker
169*9e94795aSAndroid Build Coastguard Worker    Returns:
170*9e94795aSAndroid Build Coastguard Worker      The minimum partition size required to accommodate the image size.
171*9e94795aSAndroid Build Coastguard Worker    """
172*9e94795aSAndroid Build Coastguard Worker    if size_calculator is None:
173*9e94795aSAndroid Build Coastguard Worker      size_calculator = self.CalculateMaxImageSize
174*9e94795aSAndroid Build Coastguard Worker
175*9e94795aSAndroid Build Coastguard Worker    # Use image size as partition size to approximate final partition size.
176*9e94795aSAndroid Build Coastguard Worker    image_ratio = size_calculator(image_size) / float(image_size)
177*9e94795aSAndroid Build Coastguard Worker
178*9e94795aSAndroid Build Coastguard Worker    # Prepare a binary search for the optimal partition size.
179*9e94795aSAndroid Build Coastguard Worker    lo = int(image_size / image_ratio) // BLOCK_SIZE * BLOCK_SIZE - BLOCK_SIZE
180*9e94795aSAndroid Build Coastguard Worker
181*9e94795aSAndroid Build Coastguard Worker    # Ensure lo is small enough: max_image_size should <= image_size.
182*9e94795aSAndroid Build Coastguard Worker    delta = BLOCK_SIZE
183*9e94795aSAndroid Build Coastguard Worker    max_image_size = size_calculator(lo)
184*9e94795aSAndroid Build Coastguard Worker    while max_image_size > image_size:
185*9e94795aSAndroid Build Coastguard Worker      image_ratio = max_image_size / float(lo)
186*9e94795aSAndroid Build Coastguard Worker      lo = int(image_size / image_ratio) // BLOCK_SIZE * BLOCK_SIZE - delta
187*9e94795aSAndroid Build Coastguard Worker      delta *= 2
188*9e94795aSAndroid Build Coastguard Worker      max_image_size = size_calculator(lo)
189*9e94795aSAndroid Build Coastguard Worker
190*9e94795aSAndroid Build Coastguard Worker    hi = lo + BLOCK_SIZE
191*9e94795aSAndroid Build Coastguard Worker
192*9e94795aSAndroid Build Coastguard Worker    # Ensure hi is large enough: max_image_size should >= image_size.
193*9e94795aSAndroid Build Coastguard Worker    delta = BLOCK_SIZE
194*9e94795aSAndroid Build Coastguard Worker    max_image_size = size_calculator(hi)
195*9e94795aSAndroid Build Coastguard Worker    while max_image_size < image_size:
196*9e94795aSAndroid Build Coastguard Worker      image_ratio = max_image_size / float(hi)
197*9e94795aSAndroid Build Coastguard Worker      hi = int(image_size / image_ratio) // BLOCK_SIZE * BLOCK_SIZE + delta
198*9e94795aSAndroid Build Coastguard Worker      delta *= 2
199*9e94795aSAndroid Build Coastguard Worker      max_image_size = size_calculator(hi)
200*9e94795aSAndroid Build Coastguard Worker
201*9e94795aSAndroid Build Coastguard Worker    partition_size = hi
202*9e94795aSAndroid Build Coastguard Worker
203*9e94795aSAndroid Build Coastguard Worker    # Start to binary search.
204*9e94795aSAndroid Build Coastguard Worker    while lo < hi:
205*9e94795aSAndroid Build Coastguard Worker      mid = ((lo + hi) // (2 * BLOCK_SIZE)) * BLOCK_SIZE
206*9e94795aSAndroid Build Coastguard Worker      max_image_size = size_calculator(mid)
207*9e94795aSAndroid Build Coastguard Worker      if max_image_size >= image_size:  # if mid can accommodate image_size
208*9e94795aSAndroid Build Coastguard Worker        if mid < partition_size:  # if a smaller partition size is found
209*9e94795aSAndroid Build Coastguard Worker          partition_size = mid
210*9e94795aSAndroid Build Coastguard Worker        hi = mid
211*9e94795aSAndroid Build Coastguard Worker      else:
212*9e94795aSAndroid Build Coastguard Worker        lo = mid + BLOCK_SIZE
213*9e94795aSAndroid Build Coastguard Worker
214*9e94795aSAndroid Build Coastguard Worker    logger.info(
215*9e94795aSAndroid Build Coastguard Worker        "CalculateMinPartitionSize(%d): partition_size %d.", image_size,
216*9e94795aSAndroid Build Coastguard Worker        partition_size)
217*9e94795aSAndroid Build Coastguard Worker
218*9e94795aSAndroid Build Coastguard Worker    return partition_size
219*9e94795aSAndroid Build Coastguard Worker
220*9e94795aSAndroid Build Coastguard Worker  def CalculateDynamicPartitionSize(self, image_size):
221*9e94795aSAndroid Build Coastguard Worker    self.partition_size = self.CalculateMinPartitionSize(image_size)
222*9e94795aSAndroid Build Coastguard Worker    return self.partition_size
223*9e94795aSAndroid Build Coastguard Worker
224*9e94795aSAndroid Build Coastguard Worker  def CalculateMaxImageSize(self, partition_size=None):
225*9e94795aSAndroid Build Coastguard Worker    """Calculates max image size for a given partition size.
226*9e94795aSAndroid Build Coastguard Worker
227*9e94795aSAndroid Build Coastguard Worker    Args:
228*9e94795aSAndroid Build Coastguard Worker      partition_size: The partition size, which defaults to self.partition_size
229*9e94795aSAndroid Build Coastguard Worker          if unspecified.
230*9e94795aSAndroid Build Coastguard Worker
231*9e94795aSAndroid Build Coastguard Worker    Returns:
232*9e94795aSAndroid Build Coastguard Worker      The maximum image size.
233*9e94795aSAndroid Build Coastguard Worker
234*9e94795aSAndroid Build Coastguard Worker    Raises:
235*9e94795aSAndroid Build Coastguard Worker      BuildVerityImageError: On error or getting invalid image size.
236*9e94795aSAndroid Build Coastguard Worker    """
237*9e94795aSAndroid Build Coastguard Worker    if partition_size is None:
238*9e94795aSAndroid Build Coastguard Worker      partition_size = self.partition_size
239*9e94795aSAndroid Build Coastguard Worker    assert partition_size > 0, \
240*9e94795aSAndroid Build Coastguard Worker        "Invalid partition size: {}".format(partition_size)
241*9e94795aSAndroid Build Coastguard Worker
242*9e94795aSAndroid Build Coastguard Worker    add_footer = ("add_hash_footer" if self.footer_type == self.AVB_HASH_FOOTER
243*9e94795aSAndroid Build Coastguard Worker                  else "add_hashtree_footer")
244*9e94795aSAndroid Build Coastguard Worker    cmd = [self.avbtool, add_footer, "--partition_size",
245*9e94795aSAndroid Build Coastguard Worker           str(partition_size), "--calc_max_image_size"]
246*9e94795aSAndroid Build Coastguard Worker    cmd.extend(shlex.split(self.signing_args))
247*9e94795aSAndroid Build Coastguard Worker
248*9e94795aSAndroid Build Coastguard Worker    proc = common.Run(cmd)
249*9e94795aSAndroid Build Coastguard Worker    output, _ = proc.communicate()
250*9e94795aSAndroid Build Coastguard Worker    if proc.returncode != 0:
251*9e94795aSAndroid Build Coastguard Worker      raise BuildVerityImageError(
252*9e94795aSAndroid Build Coastguard Worker          "Failed to calculate max image size:\n{}".format(output))
253*9e94795aSAndroid Build Coastguard Worker    image_size = int(output)
254*9e94795aSAndroid Build Coastguard Worker    if image_size <= 0:
255*9e94795aSAndroid Build Coastguard Worker      raise BuildVerityImageError(
256*9e94795aSAndroid Build Coastguard Worker          "Invalid max image size: {}".format(output))
257*9e94795aSAndroid Build Coastguard Worker    self.image_size = image_size
258*9e94795aSAndroid Build Coastguard Worker    return image_size
259*9e94795aSAndroid Build Coastguard Worker
260*9e94795aSAndroid Build Coastguard Worker  def PadSparseImage(self, out_file):
261*9e94795aSAndroid Build Coastguard Worker    # No-op as the padding is taken care of by avbtool.
262*9e94795aSAndroid Build Coastguard Worker    pass
263*9e94795aSAndroid Build Coastguard Worker
264*9e94795aSAndroid Build Coastguard Worker  def Build(self, out_file):
265*9e94795aSAndroid Build Coastguard Worker    """Adds dm-verity hashtree and AVB metadata to an image.
266*9e94795aSAndroid Build Coastguard Worker
267*9e94795aSAndroid Build Coastguard Worker    Args:
268*9e94795aSAndroid Build Coastguard Worker      out_file: Path to image to modify.
269*9e94795aSAndroid Build Coastguard Worker    """
270*9e94795aSAndroid Build Coastguard Worker    add_footer = ("add_hash_footer" if self.footer_type == self.AVB_HASH_FOOTER
271*9e94795aSAndroid Build Coastguard Worker                  else "add_hashtree_footer")
272*9e94795aSAndroid Build Coastguard Worker    cmd = [self.avbtool, add_footer,
273*9e94795aSAndroid Build Coastguard Worker           "--partition_size", str(self.partition_size),
274*9e94795aSAndroid Build Coastguard Worker           "--partition_name", self.partition_name,
275*9e94795aSAndroid Build Coastguard Worker           "--image", out_file]
276*9e94795aSAndroid Build Coastguard Worker    if self.key_path and self.algorithm:
277*9e94795aSAndroid Build Coastguard Worker      cmd.extend(["--key", self.key_path, "--algorithm", self.algorithm])
278*9e94795aSAndroid Build Coastguard Worker    if self.salt:
279*9e94795aSAndroid Build Coastguard Worker      cmd.extend(["--salt", self.salt])
280*9e94795aSAndroid Build Coastguard Worker    cmd.extend(shlex.split(self.signing_args))
281*9e94795aSAndroid Build Coastguard Worker
282*9e94795aSAndroid Build Coastguard Worker    proc = common.Run(cmd)
283*9e94795aSAndroid Build Coastguard Worker    output, _ = proc.communicate()
284*9e94795aSAndroid Build Coastguard Worker    if proc.returncode != 0:
285*9e94795aSAndroid Build Coastguard Worker      raise BuildVerityImageError("Failed to add AVB footer: {}".format(output))
286*9e94795aSAndroid Build Coastguard Worker
287*9e94795aSAndroid Build Coastguard Worker
288*9e94795aSAndroid Build Coastguard Workerdef CreateCustomImageBuilder(info_dict, partition_name, partition_size,
289*9e94795aSAndroid Build Coastguard Worker                             key_path, algorithm, signing_args):
290*9e94795aSAndroid Build Coastguard Worker  builder = None
291*9e94795aSAndroid Build Coastguard Worker  if info_dict.get("avb_enable") == "true":
292*9e94795aSAndroid Build Coastguard Worker    builder = VerifiedBootVersion2VerityImageBuilder(
293*9e94795aSAndroid Build Coastguard Worker        partition_name,
294*9e94795aSAndroid Build Coastguard Worker        partition_size,
295*9e94795aSAndroid Build Coastguard Worker        VerifiedBootVersion2VerityImageBuilder.AVB_HASHTREE_FOOTER,
296*9e94795aSAndroid Build Coastguard Worker        info_dict.get("avb_avbtool"),
297*9e94795aSAndroid Build Coastguard Worker        key_path,
298*9e94795aSAndroid Build Coastguard Worker        algorithm,
299*9e94795aSAndroid Build Coastguard Worker        # Salt is None because custom images have no fingerprint property to be
300*9e94795aSAndroid Build Coastguard Worker        # used as the salt.
301*9e94795aSAndroid Build Coastguard Worker        None,
302*9e94795aSAndroid Build Coastguard Worker        signing_args)
303*9e94795aSAndroid Build Coastguard Worker
304*9e94795aSAndroid Build Coastguard Worker  return builder
305*9e94795aSAndroid Build Coastguard Worker
306*9e94795aSAndroid Build Coastguard Worker
307*9e94795aSAndroid Build Coastguard Workerdef GetDiskUsage(path):
308*9e94795aSAndroid Build Coastguard Worker  """Returns the number of bytes that "path" occupies on host.
309*9e94795aSAndroid Build Coastguard Worker
310*9e94795aSAndroid Build Coastguard Worker  Args:
311*9e94795aSAndroid Build Coastguard Worker    path: The directory or file to calculate size on.
312*9e94795aSAndroid Build Coastguard Worker
313*9e94795aSAndroid Build Coastguard Worker  Returns:
314*9e94795aSAndroid Build Coastguard Worker    The number of bytes based on a 1K block_size.
315*9e94795aSAndroid Build Coastguard Worker  """
316*9e94795aSAndroid Build Coastguard Worker  cmd = ["du", "-b", "-k", "-s", path]
317*9e94795aSAndroid Build Coastguard Worker  output = common.RunAndCheckOutput(cmd, verbose=False)
318*9e94795aSAndroid Build Coastguard Worker  return int(output.split()[0]) * 1024
319*9e94795aSAndroid Build Coastguard Worker
320*9e94795aSAndroid Build Coastguard Worker
321*9e94795aSAndroid Build Coastguard Workerdef CalculateVbmetaDigest(extracted_dir, avbtool):
322*9e94795aSAndroid Build Coastguard Worker  """Calculates the vbmeta digest of the images in the extracted target_file"""
323*9e94795aSAndroid Build Coastguard Worker
324*9e94795aSAndroid Build Coastguard Worker  images_dir = common.MakeTempDir()
325*9e94795aSAndroid Build Coastguard Worker  for name in ("PREBUILT_IMAGES", "RADIO", "IMAGES"):
326*9e94795aSAndroid Build Coastguard Worker    path = os.path.join(extracted_dir, name)
327*9e94795aSAndroid Build Coastguard Worker    if not os.path.exists(path):
328*9e94795aSAndroid Build Coastguard Worker      continue
329*9e94795aSAndroid Build Coastguard Worker
330*9e94795aSAndroid Build Coastguard Worker    # Create symlink for image files under PREBUILT_IMAGES, RADIO and IMAGES,
331*9e94795aSAndroid Build Coastguard Worker    # and put them into one directory.
332*9e94795aSAndroid Build Coastguard Worker    for filename in os.listdir(path):
333*9e94795aSAndroid Build Coastguard Worker      if not filename.endswith(".img"):
334*9e94795aSAndroid Build Coastguard Worker        continue
335*9e94795aSAndroid Build Coastguard Worker      symlink_path = os.path.join(images_dir, filename)
336*9e94795aSAndroid Build Coastguard Worker      # The files in latter directory overwrite the existing links
337*9e94795aSAndroid Build Coastguard Worker      common.RunAndCheckOutput(
338*9e94795aSAndroid Build Coastguard Worker        ['ln', '-sf', os.path.join(path, filename), symlink_path])
339*9e94795aSAndroid Build Coastguard Worker
340*9e94795aSAndroid Build Coastguard Worker  cmd = [avbtool, "calculate_vbmeta_digest", "--image",
341*9e94795aSAndroid Build Coastguard Worker         os.path.join(images_dir, 'vbmeta.img')]
342*9e94795aSAndroid Build Coastguard Worker  return common.RunAndCheckOutput(cmd)
343*9e94795aSAndroid Build Coastguard Worker
344*9e94795aSAndroid Build Coastguard Worker
345*9e94795aSAndroid Build Coastguard Workerdef main(argv):
346*9e94795aSAndroid Build Coastguard Worker  if len(argv) != 2:
347*9e94795aSAndroid Build Coastguard Worker    print(__doc__)
348*9e94795aSAndroid Build Coastguard Worker    sys.exit(1)
349*9e94795aSAndroid Build Coastguard Worker
350*9e94795aSAndroid Build Coastguard Worker  common.InitLogging()
351*9e94795aSAndroid Build Coastguard Worker
352*9e94795aSAndroid Build Coastguard Worker  dict_file = argv[0]
353*9e94795aSAndroid Build Coastguard Worker  out_file = argv[1]
354*9e94795aSAndroid Build Coastguard Worker
355*9e94795aSAndroid Build Coastguard Worker  prop_dict = {}
356*9e94795aSAndroid Build Coastguard Worker  with open(dict_file, 'r') as f:
357*9e94795aSAndroid Build Coastguard Worker    for line in f:
358*9e94795aSAndroid Build Coastguard Worker      line = line.strip()
359*9e94795aSAndroid Build Coastguard Worker      if not line or line.startswith("#"):
360*9e94795aSAndroid Build Coastguard Worker        continue
361*9e94795aSAndroid Build Coastguard Worker      k, v = line.split("=", 1)
362*9e94795aSAndroid Build Coastguard Worker      prop_dict[k] = v
363*9e94795aSAndroid Build Coastguard Worker
364*9e94795aSAndroid Build Coastguard Worker  builder = CreateVerityImageBuilder(prop_dict)
365*9e94795aSAndroid Build Coastguard Worker
366*9e94795aSAndroid Build Coastguard Worker  if "partition_size" not in prop_dict:
367*9e94795aSAndroid Build Coastguard Worker    image_size = GetDiskUsage(out_file)
368*9e94795aSAndroid Build Coastguard Worker    # make sure that the image is big enough to hold vbmeta and footer
369*9e94795aSAndroid Build Coastguard Worker    image_size = image_size + (MAX_VBMETA_SIZE + MAX_FOOTER_SIZE)
370*9e94795aSAndroid Build Coastguard Worker    size = builder.CalculateDynamicPartitionSize(image_size)
371*9e94795aSAndroid Build Coastguard Worker    prop_dict["partition_size"] = size
372*9e94795aSAndroid Build Coastguard Worker
373*9e94795aSAndroid Build Coastguard Worker  builder.Build(out_file)
374*9e94795aSAndroid Build Coastguard Worker
375*9e94795aSAndroid Build Coastguard Worker
376*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__':
377*9e94795aSAndroid Build Coastguard Worker  try:
378*9e94795aSAndroid Build Coastguard Worker    main(sys.argv[1:])
379*9e94795aSAndroid Build Coastguard Worker  finally:
380*9e94795aSAndroid Build Coastguard Worker    common.Cleanup()
381