xref: /aosp_15_r20/system/update_engine/scripts/update_payload/common.py (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker#
2*5a923131SAndroid Build Coastguard Worker# Copyright (C) 2013 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker#
4*5a923131SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker#
8*5a923131SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker#
10*5a923131SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker# limitations under the License.
15*5a923131SAndroid Build Coastguard Worker#
16*5a923131SAndroid Build Coastguard Worker
17*5a923131SAndroid Build Coastguard Worker"""Utilities for update payload processing."""
18*5a923131SAndroid Build Coastguard Worker
19*5a923131SAndroid Build Coastguard Workerfrom __future__ import absolute_import
20*5a923131SAndroid Build Coastguard Workerfrom __future__ import print_function
21*5a923131SAndroid Build Coastguard Worker
22*5a923131SAndroid Build Coastguard Workerimport base64
23*5a923131SAndroid Build Coastguard Worker
24*5a923131SAndroid Build Coastguard Workerimport update_metadata_pb2
25*5a923131SAndroid Build Coastguard Workerfrom update_payload.error import PayloadError
26*5a923131SAndroid Build Coastguard Worker
27*5a923131SAndroid Build Coastguard Worker
28*5a923131SAndroid Build Coastguard Worker#
29*5a923131SAndroid Build Coastguard Worker# Constants.
30*5a923131SAndroid Build Coastguard Worker#
31*5a923131SAndroid Build Coastguard WorkerSIG_ASN1_HEADER = (
32*5a923131SAndroid Build Coastguard Worker    b'\x30\x31\x30\x0d\x06\x09\x60\x86'
33*5a923131SAndroid Build Coastguard Worker    b'\x48\x01\x65\x03\x04\x02\x01\x05'
34*5a923131SAndroid Build Coastguard Worker    b'\x00\x04\x20'
35*5a923131SAndroid Build Coastguard Worker)
36*5a923131SAndroid Build Coastguard Worker
37*5a923131SAndroid Build Coastguard WorkerBRILLO_MAJOR_PAYLOAD_VERSION = 2
38*5a923131SAndroid Build Coastguard Worker
39*5a923131SAndroid Build Coastguard WorkerSOURCE_MINOR_PAYLOAD_VERSION = 2
40*5a923131SAndroid Build Coastguard WorkerOPSRCHASH_MINOR_PAYLOAD_VERSION = 3
41*5a923131SAndroid Build Coastguard WorkerBROTLI_BSDIFF_MINOR_PAYLOAD_VERSION = 4
42*5a923131SAndroid Build Coastguard WorkerPUFFDIFF_MINOR_PAYLOAD_VERSION = 5
43*5a923131SAndroid Build Coastguard Worker
44*5a923131SAndroid Build Coastguard WorkerKERNEL = 'kernel'
45*5a923131SAndroid Build Coastguard WorkerROOTFS = 'root'
46*5a923131SAndroid Build Coastguard Worker# Tuple of (name in system, name in protobuf).
47*5a923131SAndroid Build Coastguard WorkerCROS_PARTITIONS = ((KERNEL, KERNEL), (ROOTFS, 'rootfs'))
48*5a923131SAndroid Build Coastguard Worker
49*5a923131SAndroid Build Coastguard Worker
50*5a923131SAndroid Build Coastguard Worker#
51*5a923131SAndroid Build Coastguard Worker# Payload operation types.
52*5a923131SAndroid Build Coastguard Worker#
53*5a923131SAndroid Build Coastguard Workerclass OpType(object):
54*5a923131SAndroid Build Coastguard Worker  """Container for operation type constants."""
55*5a923131SAndroid Build Coastguard Worker  _CLASS = update_metadata_pb2.InstallOperation
56*5a923131SAndroid Build Coastguard Worker  REPLACE = _CLASS.REPLACE
57*5a923131SAndroid Build Coastguard Worker  REPLACE_BZ = _CLASS.REPLACE_BZ
58*5a923131SAndroid Build Coastguard Worker  SOURCE_COPY = _CLASS.SOURCE_COPY
59*5a923131SAndroid Build Coastguard Worker  SOURCE_BSDIFF = _CLASS.SOURCE_BSDIFF
60*5a923131SAndroid Build Coastguard Worker  ZERO = _CLASS.ZERO
61*5a923131SAndroid Build Coastguard Worker  DISCARD = _CLASS.DISCARD
62*5a923131SAndroid Build Coastguard Worker  REPLACE_XZ = _CLASS.REPLACE_XZ
63*5a923131SAndroid Build Coastguard Worker  PUFFDIFF = _CLASS.PUFFDIFF
64*5a923131SAndroid Build Coastguard Worker  BROTLI_BSDIFF = _CLASS.BROTLI_BSDIFF
65*5a923131SAndroid Build Coastguard Worker  ZUCCHINI = _CLASS.ZUCCHINI
66*5a923131SAndroid Build Coastguard Worker  ALL = (REPLACE, REPLACE_BZ, SOURCE_COPY, SOURCE_BSDIFF, ZERO,
67*5a923131SAndroid Build Coastguard Worker         DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF, ZUCCHINI)
68*5a923131SAndroid Build Coastguard Worker  NAMES = {
69*5a923131SAndroid Build Coastguard Worker      REPLACE: 'REPLACE',
70*5a923131SAndroid Build Coastguard Worker      REPLACE_BZ: 'REPLACE_BZ',
71*5a923131SAndroid Build Coastguard Worker      SOURCE_COPY: 'SOURCE_COPY',
72*5a923131SAndroid Build Coastguard Worker      SOURCE_BSDIFF: 'SOURCE_BSDIFF',
73*5a923131SAndroid Build Coastguard Worker      ZERO: 'ZERO',
74*5a923131SAndroid Build Coastguard Worker      DISCARD: 'DISCARD',
75*5a923131SAndroid Build Coastguard Worker      REPLACE_XZ: 'REPLACE_XZ',
76*5a923131SAndroid Build Coastguard Worker      PUFFDIFF: 'PUFFDIFF',
77*5a923131SAndroid Build Coastguard Worker      BROTLI_BSDIFF: 'BROTLI_BSDIFF',
78*5a923131SAndroid Build Coastguard Worker      ZUCCHINI: 'ZUCCHINI',
79*5a923131SAndroid Build Coastguard Worker  }
80*5a923131SAndroid Build Coastguard Worker
81*5a923131SAndroid Build Coastguard Worker  def __init__(self):
82*5a923131SAndroid Build Coastguard Worker    pass
83*5a923131SAndroid Build Coastguard Worker
84*5a923131SAndroid Build Coastguard Worker
85*5a923131SAndroid Build Coastguard Worker#
86*5a923131SAndroid Build Coastguard Worker# Checked and hashed reading of data.
87*5a923131SAndroid Build Coastguard Worker#
88*5a923131SAndroid Build Coastguard Workerdef IntPackingFmtStr(size, is_unsigned):
89*5a923131SAndroid Build Coastguard Worker  """Returns an integer format string for use by the struct module.
90*5a923131SAndroid Build Coastguard Worker
91*5a923131SAndroid Build Coastguard Worker  Args:
92*5a923131SAndroid Build Coastguard Worker    size: the integer size in bytes (2, 4 or 8)
93*5a923131SAndroid Build Coastguard Worker    is_unsigned: whether it is signed or not
94*5a923131SAndroid Build Coastguard Worker
95*5a923131SAndroid Build Coastguard Worker  Returns:
96*5a923131SAndroid Build Coastguard Worker    A format string for packing/unpacking integer values; assumes network byte
97*5a923131SAndroid Build Coastguard Worker    order (big-endian).
98*5a923131SAndroid Build Coastguard Worker
99*5a923131SAndroid Build Coastguard Worker  Raises:
100*5a923131SAndroid Build Coastguard Worker    PayloadError if something is wrong with the arguments.
101*5a923131SAndroid Build Coastguard Worker  """
102*5a923131SAndroid Build Coastguard Worker  # Determine the base conversion format.
103*5a923131SAndroid Build Coastguard Worker  if size == 2:
104*5a923131SAndroid Build Coastguard Worker    fmt = 'h'
105*5a923131SAndroid Build Coastguard Worker  elif size == 4:
106*5a923131SAndroid Build Coastguard Worker    fmt = 'i'
107*5a923131SAndroid Build Coastguard Worker  elif size == 8:
108*5a923131SAndroid Build Coastguard Worker    fmt = 'q'
109*5a923131SAndroid Build Coastguard Worker  else:
110*5a923131SAndroid Build Coastguard Worker    raise PayloadError('unsupport numeric field size (%s)' % size)
111*5a923131SAndroid Build Coastguard Worker
112*5a923131SAndroid Build Coastguard Worker  # Signed or unsigned?
113*5a923131SAndroid Build Coastguard Worker  if is_unsigned:
114*5a923131SAndroid Build Coastguard Worker    fmt = fmt.upper()
115*5a923131SAndroid Build Coastguard Worker
116*5a923131SAndroid Build Coastguard Worker  # Make it network byte order (big-endian).
117*5a923131SAndroid Build Coastguard Worker  fmt = '!' + fmt
118*5a923131SAndroid Build Coastguard Worker
119*5a923131SAndroid Build Coastguard Worker  return fmt
120*5a923131SAndroid Build Coastguard Worker
121*5a923131SAndroid Build Coastguard Worker
122*5a923131SAndroid Build Coastguard Workerdef Read(file_obj, length, offset=None, hasher=None):
123*5a923131SAndroid Build Coastguard Worker  """Reads binary data from a file.
124*5a923131SAndroid Build Coastguard Worker
125*5a923131SAndroid Build Coastguard Worker  Args:
126*5a923131SAndroid Build Coastguard Worker    file_obj: an open file object
127*5a923131SAndroid Build Coastguard Worker    length: the length of the data to read
128*5a923131SAndroid Build Coastguard Worker    offset: an offset to seek to prior to reading; this is an absolute offset
129*5a923131SAndroid Build Coastguard Worker            from either the beginning (non-negative) or end (negative) of the
130*5a923131SAndroid Build Coastguard Worker            file.  (optional)
131*5a923131SAndroid Build Coastguard Worker    hasher: a hashing object to pass the read data through (optional)
132*5a923131SAndroid Build Coastguard Worker
133*5a923131SAndroid Build Coastguard Worker  Returns:
134*5a923131SAndroid Build Coastguard Worker    A string containing the read data.
135*5a923131SAndroid Build Coastguard Worker
136*5a923131SAndroid Build Coastguard Worker  Raises:
137*5a923131SAndroid Build Coastguard Worker    PayloadError if a read error occurred or not enough data was read.
138*5a923131SAndroid Build Coastguard Worker  """
139*5a923131SAndroid Build Coastguard Worker  if offset is not None:
140*5a923131SAndroid Build Coastguard Worker    if offset >= 0:
141*5a923131SAndroid Build Coastguard Worker      file_obj.seek(offset)
142*5a923131SAndroid Build Coastguard Worker    else:
143*5a923131SAndroid Build Coastguard Worker      file_obj.seek(offset, 2)
144*5a923131SAndroid Build Coastguard Worker
145*5a923131SAndroid Build Coastguard Worker  try:
146*5a923131SAndroid Build Coastguard Worker    data = file_obj.read(length)
147*5a923131SAndroid Build Coastguard Worker  except IOError as e:
148*5a923131SAndroid Build Coastguard Worker    raise PayloadError('error reading from file (%s): %s' % (file_obj.name, e))
149*5a923131SAndroid Build Coastguard Worker
150*5a923131SAndroid Build Coastguard Worker  if len(data) != length:
151*5a923131SAndroid Build Coastguard Worker    raise PayloadError(
152*5a923131SAndroid Build Coastguard Worker        'reading from file (%s) too short (%d instead of %d bytes)' %
153*5a923131SAndroid Build Coastguard Worker        (file_obj.name, len(data), length))
154*5a923131SAndroid Build Coastguard Worker
155*5a923131SAndroid Build Coastguard Worker  if hasher:
156*5a923131SAndroid Build Coastguard Worker    hasher.update(data)
157*5a923131SAndroid Build Coastguard Worker
158*5a923131SAndroid Build Coastguard Worker  return data
159*5a923131SAndroid Build Coastguard Worker
160*5a923131SAndroid Build Coastguard Worker
161*5a923131SAndroid Build Coastguard Worker#
162*5a923131SAndroid Build Coastguard Worker# Formatting functions.
163*5a923131SAndroid Build Coastguard Worker#
164*5a923131SAndroid Build Coastguard Workerdef FormatExtent(ex, block_size=0):
165*5a923131SAndroid Build Coastguard Worker  end_block = ex.start_block + ex.num_blocks
166*5a923131SAndroid Build Coastguard Worker  if block_size:
167*5a923131SAndroid Build Coastguard Worker    return '%d->%d * %d' % (ex.start_block, end_block, block_size)
168*5a923131SAndroid Build Coastguard Worker  return '%d->%d' % (ex.start_block, end_block)
169*5a923131SAndroid Build Coastguard Worker
170*5a923131SAndroid Build Coastguard Worker
171*5a923131SAndroid Build Coastguard Workerdef FormatSha256(digest):
172*5a923131SAndroid Build Coastguard Worker  """Returns a canonical string representation of a SHA256 digest."""
173*5a923131SAndroid Build Coastguard Worker  return base64.b64encode(digest).decode('utf-8')
174*5a923131SAndroid Build Coastguard Worker
175*5a923131SAndroid Build Coastguard Worker
176*5a923131SAndroid Build Coastguard Worker#
177*5a923131SAndroid Build Coastguard Worker# Useful iterators.
178*5a923131SAndroid Build Coastguard Worker#
179*5a923131SAndroid Build Coastguard Workerdef _ObjNameIter(items, base_name, reverse=False, name_format_func=None):
180*5a923131SAndroid Build Coastguard Worker  """A generic (item, name) tuple iterators.
181*5a923131SAndroid Build Coastguard Worker
182*5a923131SAndroid Build Coastguard Worker  Args:
183*5a923131SAndroid Build Coastguard Worker    items: the sequence of objects to iterate on
184*5a923131SAndroid Build Coastguard Worker    base_name: the base name for all objects
185*5a923131SAndroid Build Coastguard Worker    reverse: whether iteration should be in reverse order
186*5a923131SAndroid Build Coastguard Worker    name_format_func: a function to apply to the name string
187*5a923131SAndroid Build Coastguard Worker
188*5a923131SAndroid Build Coastguard Worker  Yields:
189*5a923131SAndroid Build Coastguard Worker    An iterator whose i-th invocation returns (items[i], name), where name ==
190*5a923131SAndroid Build Coastguard Worker    base_name + '[i]' (with a formatting function optionally applied to it).
191*5a923131SAndroid Build Coastguard Worker  """
192*5a923131SAndroid Build Coastguard Worker  idx, inc = (len(items), -1) if reverse else (1, 1)
193*5a923131SAndroid Build Coastguard Worker  if reverse:
194*5a923131SAndroid Build Coastguard Worker    items = reversed(items)
195*5a923131SAndroid Build Coastguard Worker  for item in items:
196*5a923131SAndroid Build Coastguard Worker    item_name = '%s[%d]' % (base_name, idx)
197*5a923131SAndroid Build Coastguard Worker    if name_format_func:
198*5a923131SAndroid Build Coastguard Worker      item_name = name_format_func(item, item_name)
199*5a923131SAndroid Build Coastguard Worker    yield (item, item_name)
200*5a923131SAndroid Build Coastguard Worker    idx += inc
201*5a923131SAndroid Build Coastguard Worker
202*5a923131SAndroid Build Coastguard Worker
203*5a923131SAndroid Build Coastguard Workerdef _OperationNameFormatter(op, op_name):
204*5a923131SAndroid Build Coastguard Worker  return '%s(%s)' % (op_name, OpType.NAMES.get(op.type, '?'))
205*5a923131SAndroid Build Coastguard Worker
206*5a923131SAndroid Build Coastguard Worker
207*5a923131SAndroid Build Coastguard Workerdef OperationIter(operations, base_name, reverse=False):
208*5a923131SAndroid Build Coastguard Worker  """An (item, name) iterator for update operations."""
209*5a923131SAndroid Build Coastguard Worker  return _ObjNameIter(operations, base_name, reverse=reverse,
210*5a923131SAndroid Build Coastguard Worker                      name_format_func=_OperationNameFormatter)
211*5a923131SAndroid Build Coastguard Worker
212*5a923131SAndroid Build Coastguard Worker
213*5a923131SAndroid Build Coastguard Workerdef ExtentIter(extents, base_name, reverse=False):
214*5a923131SAndroid Build Coastguard Worker  """An (item, name) iterator for operation extents."""
215*5a923131SAndroid Build Coastguard Worker  return _ObjNameIter(extents, base_name, reverse=reverse)
216*5a923131SAndroid Build Coastguard Worker
217*5a923131SAndroid Build Coastguard Worker
218*5a923131SAndroid Build Coastguard Workerdef SignatureIter(sigs, base_name, reverse=False):
219*5a923131SAndroid Build Coastguard Worker  """An (item, name) iterator for signatures."""
220*5a923131SAndroid Build Coastguard Worker  return _ObjNameIter(sigs, base_name, reverse=reverse)
221