RESTRICT AUTOMERGE Uses a per-partition fingerprint for building images and avb_salt.
This causes the output image files of a merged build to be identical
to the image files of the input partial builds, for each images in
PARTITIONS_WITH_CARE_MAP.
Test: python -m unittest test_common
Test: `m dist`; `unzip out/dist/target_files.zip IMAGES/\*`;
`zip -d out/dist/target_files.zip IMAGES/\*`
`add_img_to_target_files -a out/dist/target_files.zip`.
Verify that the rebuilt images are identical to the deleted ones.
Test: Build a merged target (using merge_target_files.py). Verify that
the partial target-files.zip IMAGES are identical to the merged
target-files.zip IMAGES for PARTITIONS_WITH_CARE_MAP images.
Bug: 150405807
Change-Id: I5fdf5783c1aff9c14cf5408090389b1f65b69ca6
(cherry picked from commit d5fe862628
)
This commit is contained in:
@@ -319,7 +319,7 @@ class BuildInfo(object):
|
||||
OEM-specific properties, some of them will be calculated from two info dicts.
|
||||
|
||||
Users can query properties similarly as using a dict() (e.g. info['fstab']),
|
||||
or to query build properties via GetBuildProp() or GetVendorBuildProp().
|
||||
or to query build properties via GetBuildProp() or GetPartitionBuildProp().
|
||||
|
||||
Attributes:
|
||||
info_dict: The build-time info dict.
|
||||
@@ -362,16 +362,31 @@ class BuildInfo(object):
|
||||
if self._oem_props:
|
||||
assert oem_dicts, "OEM source required for this build"
|
||||
|
||||
def check_fingerprint(fingerprint):
|
||||
if (" " in fingerprint or any(ord(ch) > 127 for ch in fingerprint)):
|
||||
raise ValueError(
|
||||
'Invalid build fingerprint: "{}". See the requirement in Android CDD '
|
||||
"3.2.2. Build Parameters.".format(fingerprint))
|
||||
|
||||
|
||||
self._partition_fingerprints = {}
|
||||
for partition in PARTITIONS_WITH_CARE_MAP:
|
||||
try:
|
||||
fingerprint = self.CalculatePartitionFingerprint(partition)
|
||||
check_fingerprint(fingerprint)
|
||||
self._partition_fingerprints[partition] = fingerprint
|
||||
except ExternalError:
|
||||
continue
|
||||
if "system" in self._partition_fingerprints:
|
||||
# system_other is not included in PARTITIONS_WITH_CARE_MAP, but does
|
||||
# need a fingerprint when creating the image.
|
||||
self._partition_fingerprints[
|
||||
"system_other"] = self._partition_fingerprints["system"]
|
||||
|
||||
# These two should be computed only after setting self._oem_props.
|
||||
self._device = self.GetOemProperty("ro.product.device")
|
||||
self._fingerprint = self.CalculateFingerprint()
|
||||
|
||||
# Sanity check the build fingerprint.
|
||||
if (' ' in self._fingerprint or
|
||||
any(ord(ch) > 127 for ch in self._fingerprint)):
|
||||
raise ValueError(
|
||||
'Invalid build fingerprint: "{}". See the requirement in Android CDD '
|
||||
'3.2.2. Build Parameters.'.format(self._fingerprint))
|
||||
check_fingerprint(self._fingerprint)
|
||||
|
||||
@property
|
||||
def is_ab(self):
|
||||
@@ -385,28 +400,6 @@ class BuildInfo(object):
|
||||
def fingerprint(self):
|
||||
return self._fingerprint
|
||||
|
||||
@property
|
||||
def vendor_fingerprint(self):
|
||||
return self._fingerprint_of("vendor")
|
||||
|
||||
@property
|
||||
def product_fingerprint(self):
|
||||
return self._fingerprint_of("product")
|
||||
|
||||
@property
|
||||
def odm_fingerprint(self):
|
||||
return self._fingerprint_of("odm")
|
||||
|
||||
def _fingerprint_of(self, partition):
|
||||
if partition + ".build.prop" not in self.info_dict:
|
||||
return None
|
||||
build_prop = self.info_dict[partition + ".build.prop"]
|
||||
if "ro." + partition + ".build.fingerprint" in build_prop:
|
||||
return build_prop["ro." + partition + ".build.fingerprint"]
|
||||
if "ro." + partition + ".build.thumbprint" in build_prop:
|
||||
return build_prop["ro." + partition + ".build.thumbprint"]
|
||||
return None
|
||||
|
||||
@property
|
||||
def oem_props(self):
|
||||
return self._oem_props
|
||||
@@ -423,8 +416,22 @@ class BuildInfo(object):
|
||||
def items(self):
|
||||
return self.info_dict.items()
|
||||
|
||||
def GetPartitionBuildProp(self, prop, partition):
|
||||
"""Returns the inquired build property for the provided partition."""
|
||||
# If provided a partition for this property, only look within that
|
||||
# partition's build.prop.
|
||||
if prop in BuildInfo._RO_PRODUCT_RESOLVE_PROPS:
|
||||
prop = prop.replace("ro.product", "ro.product.{}".format(partition))
|
||||
else:
|
||||
prop = prop.replace("ro.", "ro.{}.".format(partition))
|
||||
try:
|
||||
return self.info_dict.get("{}.build.prop".format(partition), {})[prop]
|
||||
except KeyError:
|
||||
raise ExternalError("couldn't find %s in %s.build.prop" %
|
||||
(prop, partition))
|
||||
|
||||
def GetBuildProp(self, prop):
|
||||
"""Returns the inquired build property."""
|
||||
"""Returns the inquired build property from the standard build.prop file."""
|
||||
if prop in BuildInfo._RO_PRODUCT_RESOLVE_PROPS:
|
||||
return self._ResolveRoProductBuildProp(prop)
|
||||
|
||||
@@ -462,19 +469,28 @@ class BuildInfo(object):
|
||||
|
||||
raise ExternalError("couldn't resolve {}".format(prop))
|
||||
|
||||
def GetVendorBuildProp(self, prop):
|
||||
"""Returns the inquired vendor build property."""
|
||||
try:
|
||||
return self.info_dict.get("vendor.build.prop", {})[prop]
|
||||
except KeyError:
|
||||
raise ExternalError(
|
||||
"couldn't find %s in vendor.build.prop" % (prop,))
|
||||
|
||||
def GetOemProperty(self, key):
|
||||
if self.oem_props is not None and key in self.oem_props:
|
||||
return self.oem_dicts[0][key]
|
||||
return self.GetBuildProp(key)
|
||||
|
||||
def GetPartitionFingerprint(self, partition):
|
||||
return self._partition_fingerprints.get(partition, None)
|
||||
|
||||
def CalculatePartitionFingerprint(self, partition):
|
||||
try:
|
||||
return self.GetPartitionBuildProp("ro.build.fingerprint", partition)
|
||||
except ExternalError:
|
||||
return "{}/{}/{}:{}/{}/{}:{}/{}".format(
|
||||
self.GetPartitionBuildProp("ro.product.brand", partition),
|
||||
self.GetPartitionBuildProp("ro.product.name", partition),
|
||||
self.GetPartitionBuildProp("ro.product.device", partition),
|
||||
self.GetPartitionBuildProp("ro.build.version.release", partition),
|
||||
self.GetPartitionBuildProp("ro.build.id", partition),
|
||||
self.GetPartitionBuildProp("ro.build.version.incremental", partition),
|
||||
self.GetPartitionBuildProp("ro.build.type", partition),
|
||||
self.GetPartitionBuildProp("ro.build.tags", partition))
|
||||
|
||||
def CalculateFingerprint(self):
|
||||
if self.oem_props is None:
|
||||
try:
|
||||
@@ -644,7 +660,10 @@ def LoadInfoDict(input_file, repacking=False):
|
||||
# hash / hashtree footers.
|
||||
if d.get("avb_enable") == "true":
|
||||
build_info = BuildInfo(d)
|
||||
d["avb_salt"] = sha256(build_info.fingerprint).hexdigest()
|
||||
for partition in PARTITIONS_WITH_CARE_MAP:
|
||||
fingerprint = build_info.GetPartitionFingerprint(partition)
|
||||
if fingerprint:
|
||||
d["avb_{}_salt".format(partition)] = sha256(fingerprint).hexdigest()
|
||||
|
||||
return d
|
||||
|
||||
|
Reference in New Issue
Block a user