Add a wrapper class PartitionBuildProp
The build prop for a partition used to be a simple key:value dictionary. But we need more fields to hold the alternative build props overriden by the 'import' statement. Therefore, add a new class as a wrapper for these props first. Bug: 152167826 Test: unittests pass Change-Id: I2fe7e93a2f4de8e55f5f8051b000b96b5efdc85a
This commit is contained in:
@@ -423,6 +423,14 @@ class BuildInfo(object):
|
||||
def items(self):
|
||||
return self.info_dict.items()
|
||||
|
||||
def _GetRawBuildProp(self, prop, partition):
|
||||
prop_file = '{}.build.prop'.format(
|
||||
partition) if partition else 'build.prop'
|
||||
partition_props = self.info_dict.get(prop_file)
|
||||
if not partition_props:
|
||||
return None
|
||||
return partition_props.GetProp(prop)
|
||||
|
||||
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
|
||||
@@ -431,31 +439,33 @@ class BuildInfo(object):
|
||||
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))
|
||||
|
||||
prop_val = self._GetRawBuildProp(prop, partition)
|
||||
if prop_val is not None:
|
||||
return prop_val
|
||||
raise ExternalError("couldn't find %s in %s.build.prop" %
|
||||
(prop, partition))
|
||||
|
||||
def GetBuildProp(self, prop):
|
||||
"""Returns the inquired build property from the standard build.prop file."""
|
||||
if prop in BuildInfo._RO_PRODUCT_RESOLVE_PROPS:
|
||||
return self._ResolveRoProductBuildProp(prop)
|
||||
|
||||
try:
|
||||
return self.info_dict.get("build.prop", {})[prop]
|
||||
except KeyError:
|
||||
raise ExternalError("couldn't find %s in build.prop" % (prop,))
|
||||
prop_val = self._GetRawBuildProp(prop, None)
|
||||
if prop_val is not None:
|
||||
return prop_val
|
||||
|
||||
raise ExternalError("couldn't find %s in build.prop" % (prop,))
|
||||
|
||||
def _ResolveRoProductBuildProp(self, prop):
|
||||
"""Resolves the inquired ro.product.* build property"""
|
||||
prop_val = self.info_dict.get("build.prop", {}).get(prop)
|
||||
prop_val = self._GetRawBuildProp(prop, None)
|
||||
if prop_val:
|
||||
return prop_val
|
||||
|
||||
default_source_order = self._GetRoProductPropsDefaultSourceOrder()
|
||||
source_order_val = self.info_dict.get("build.prop", {}).get(
|
||||
"ro.product.property_source_order")
|
||||
source_order_val = self._GetRawBuildProp(
|
||||
"ro.product.property_source_order", None)
|
||||
if source_order_val:
|
||||
source_order = source_order_val.split(",")
|
||||
else:
|
||||
@@ -466,11 +476,10 @@ class BuildInfo(object):
|
||||
raise ExternalError(
|
||||
"Invalid ro.product.property_source_order '{}'".format(source_order))
|
||||
|
||||
for source in source_order:
|
||||
for source_partition in source_order:
|
||||
source_prop = prop.replace(
|
||||
"ro.product", "ro.product.{}".format(source), 1)
|
||||
prop_val = self.info_dict.get(
|
||||
"{}.build.prop".format(source), {}).get(source_prop)
|
||||
"ro.product", "ro.product.{}".format(source_partition), 1)
|
||||
prop_val = self._GetRawBuildProp(source_prop, source_partition)
|
||||
if prop_val:
|
||||
return prop_val
|
||||
|
||||
@@ -479,11 +488,9 @@ class BuildInfo(object):
|
||||
def _GetRoProductPropsDefaultSourceOrder(self):
|
||||
# NOTE: refer to CDDs and android.os.Build.VERSION for the definition and
|
||||
# values of these properties for each Android release.
|
||||
android_codename = self.info_dict.get("build.prop", {}).get(
|
||||
"ro.build.version.codename")
|
||||
android_codename = self._GetRawBuildProp("ro.build.version.codename", None)
|
||||
if android_codename == "REL":
|
||||
android_version = self.info_dict.get("build.prop", {}).get(
|
||||
"ro.build.version.release")
|
||||
android_version = self._GetRawBuildProp("ro.build.version.release", None)
|
||||
if android_version == "10":
|
||||
return BuildInfo._RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER_ANDROID_10
|
||||
# NOTE: float() conversion of android_version will have rounding error.
|
||||
@@ -566,6 +573,20 @@ class BuildInfo(object):
|
||||
script.AssertOemProperty(prop, values, oem_no_mount)
|
||||
|
||||
|
||||
def ReadFromInputFile(input_file, fn):
|
||||
"""Reads the contents of fn from input zipfile or directory."""
|
||||
if isinstance(input_file, zipfile.ZipFile):
|
||||
return input_file.read(fn).decode()
|
||||
else:
|
||||
path = os.path.join(input_file, *fn.split("/"))
|
||||
try:
|
||||
with open(path) as f:
|
||||
return f.read()
|
||||
except IOError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
raise KeyError(fn)
|
||||
|
||||
|
||||
def LoadInfoDict(input_file, repacking=False):
|
||||
"""Loads the key/value pairs from the given input target_files.
|
||||
|
||||
@@ -603,16 +624,7 @@ def LoadInfoDict(input_file, repacking=False):
|
||||
"input_file must be a path str when doing repacking"
|
||||
|
||||
def read_helper(fn):
|
||||
if isinstance(input_file, zipfile.ZipFile):
|
||||
return input_file.read(fn).decode()
|
||||
else:
|
||||
path = os.path.join(input_file, *fn.split("/"))
|
||||
try:
|
||||
with open(path) as f:
|
||||
return f.read()
|
||||
except IOError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
raise KeyError(fn)
|
||||
return ReadFromInputFile(input_file, fn)
|
||||
|
||||
try:
|
||||
d = LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("\n"))
|
||||
@@ -675,13 +687,8 @@ def LoadInfoDict(input_file, repacking=False):
|
||||
# system and vendor.
|
||||
for partition in PARTITIONS_WITH_CARE_MAP:
|
||||
partition_prop = "{}.build.prop".format(partition)
|
||||
d[partition_prop] = LoadBuildProp(
|
||||
read_helper, "{}/build.prop".format(partition.upper()))
|
||||
# Some partition might use /<partition>/etc/build.prop as the new path.
|
||||
# TODO: try new path first when majority of them switch to the new path.
|
||||
if not d[partition_prop]:
|
||||
d[partition_prop] = LoadBuildProp(
|
||||
read_helper, "{}/etc/build.prop".format(partition.upper()))
|
||||
d[partition_prop] = PartitionBuildProps.FromInputFile(
|
||||
input_file, partition)
|
||||
d["build.prop"] = d["system.build.prop"]
|
||||
|
||||
# Set up the salt (based on fingerprint) that will be used when adding AVB
|
||||
@@ -696,15 +703,6 @@ def LoadInfoDict(input_file, repacking=False):
|
||||
return d
|
||||
|
||||
|
||||
def LoadBuildProp(read_helper, prop_file):
|
||||
try:
|
||||
data = read_helper(prop_file)
|
||||
except KeyError:
|
||||
logger.warning("Failed to read %s", prop_file)
|
||||
data = ""
|
||||
return LoadDictionaryFromLines(data.split("\n"))
|
||||
|
||||
|
||||
def LoadListFromFile(file_path):
|
||||
with open(file_path) as f:
|
||||
return f.read().splitlines()
|
||||
@@ -727,6 +725,61 @@ def LoadDictionaryFromLines(lines):
|
||||
return d
|
||||
|
||||
|
||||
class PartitionBuildProps(object):
|
||||
"""The class holds the build prop of a particular partition.
|
||||
|
||||
This class loads the build.prop and holds the build properties for a given
|
||||
partition. It also partially recognizes the 'import' statement in the
|
||||
build.prop; and calculates alternative values of some specific build
|
||||
properties during runtime.
|
||||
|
||||
Attributes:
|
||||
input_file: a zipped target-file or an unzipped target-file directory.
|
||||
partition: name of the partition.
|
||||
props_allow_override: a list of build properties to search for the
|
||||
alternative values during runtime.
|
||||
build_props: a dictionary of build properties for the given partition.
|
||||
prop_overrides: a dict of list. And each list holds the overridden values
|
||||
for props_allow_override.
|
||||
"""
|
||||
|
||||
def __init__(self, input_file, name):
|
||||
self.input_file = input_file
|
||||
self.partition = name
|
||||
self.props_allow_override = [props.format(name) for props in [
|
||||
'ro.product.{}.name', 'ro.product.{}.device']]
|
||||
self.build_props = {}
|
||||
self.prop_overrides = {}
|
||||
|
||||
@staticmethod
|
||||
def FromDictionary(name, build_props):
|
||||
"""Constructs an instance from a build prop dictionary."""
|
||||
|
||||
props = PartitionBuildProps("unknown", name)
|
||||
props.build_props = build_props.copy()
|
||||
return props
|
||||
|
||||
@staticmethod
|
||||
def FromInputFile(input_file, name):
|
||||
"""Loads the build.prop file and builds the attributes."""
|
||||
|
||||
data = ''
|
||||
for prop_file in ['{}/etc/build.prop'.format(name.upper()),
|
||||
'{}/build.prop'.format(name.upper())]:
|
||||
try:
|
||||
data = ReadFromInputFile(input_file, prop_file)
|
||||
break
|
||||
except KeyError:
|
||||
logger.warning('Failed to read %s', prop_file)
|
||||
|
||||
props = PartitionBuildProps(input_file, name)
|
||||
props.build_props = LoadDictionaryFromLines(data.split('\n'))
|
||||
return props
|
||||
|
||||
def GetProp(self, prop):
|
||||
return self.build_props.get(prop)
|
||||
|
||||
|
||||
def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path,
|
||||
system_root_image=False):
|
||||
class Partition(object):
|
||||
|
Reference in New Issue
Block a user