DO NOT MERGE releasetools: allow for multiple OEM property values.

This CL changes the --oem_settings flag to allow a comma seperated list of
property files. All property values will be used when asserting properties such
as ro.product.name.

For example, if two property files are provided with ro.product.name values of
"sprout" and "sprout_a", the resulting otapackage will check that the device's
ro.product.name property matches at least one of them.

Bug: 34191373
Test: manual

(cherry-picked and adapted from AOSP commit 7f804ba71fd5fa32e6d9735ec2544075a63b9684)

Change-Id: I954673511be8f0929982235cc9cbfbd85a9ee1f4
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index d409d94..11d1bc5 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -50,9 +50,11 @@
       Remount and verify the checksums of the files written to the
       system and vendor (if used) partitions.  Incremental builds only.
 
-  -o  (--oem_settings)  <file>
-      Use the file to specify the expected OEM-specific properties
-      on the OEM partition of the intended device.
+  -o  (--oem_settings)  <main_file[,additional_files...]>
+      Comma seperated list of files used to specify the expected OEM-specific
+      properties on the OEM partition of the intended device.
+      Multiple expected values can be used by providing multiple files.
+
 
   --oem_no_mount
       For devices with OEM-specific properties but without an OEM partition,
@@ -451,20 +453,38 @@
                   whole_file=True)
 
 
-def AppendAssertions(script, info_dict, oem_dict=None):
+def AppendAssertions(script, info_dict, oem_dicts=None):
   oem_props = info_dict.get("oem_fingerprint_properties")
   if oem_props is None or len(oem_props) == 0:
     device = GetBuildProp("ro.product.device", info_dict)
     script.AssertDevice(device)
   else:
-    if oem_dict is None:
+    if not oem_dicts:
       raise common.ExternalError(
           "No OEM file provided to answer expected assertions")
     for prop in oem_props.split():
-      if oem_dict.get(prop) is None:
+      values = []
+      for oem_dict in oem_dicts:
+        if oem_dict.get(prop):
+          values.append(oem_dict[prop])
+      if not values:
         raise common.ExternalError(
             "The OEM file is missing the property %s" % prop)
-      script.AssertOemProperty(prop, oem_dict.get(prop))
+      script.AssertOemProperty(prop, values)
+
+
+def _LoadOemDicts(script, recovery_mount_options):
+  """Returns the list of loaded OEM properties dict."""
+  oem_dicts = None
+  if OPTIONS.oem_source is None:
+    raise common.ExternalError("OEM source required for this build")
+  if not OPTIONS.oem_no_mount:
+    script.Mount("/oem", recovery_mount_options)
+  oem_dicts = []
+  for oem_file in OPTIONS.oem_source:
+    oem_dicts.append(common.LoadDictionaryFromLines(
+        open(oem_file).readlines()))
+  return oem_dicts
 
 
 def _WriteRecoveryImageToBoot(script, output_zip):
@@ -577,19 +597,15 @@
 
   oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
   recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
-  oem_dict = None
-  if oem_props is not None and len(oem_props) > 0:
-    if OPTIONS.oem_source is None:
-      raise common.ExternalError("OEM source required for this build")
-    if not OPTIONS.oem_no_mount:
-      script.Mount("/oem", recovery_mount_options)
-    oem_dict = common.LoadDictionaryFromLines(
-        open(OPTIONS.oem_source).readlines())
+  oem_dicts = None
+  if oem_props:
+    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
 
   metadata = {
-      "post-build": CalculateFingerprint(oem_props, oem_dict,
+      "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
                                          OPTIONS.info_dict),
-      "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
+      "pre-device": GetOemProperty("ro.product.device", oem_props,
+                                   oem_dicts and oem_dicts[0],
                                    OPTIONS.info_dict),
       "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
   }
@@ -613,7 +629,7 @@
     ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
     script.AssertOlderBuild(ts, ts_text)
 
-  AppendAssertions(script, OPTIONS.info_dict, oem_dict)
+  AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
   device_specific.FullOTA_Assertions()
 
   # Two-step package strategy (in chronological order, which is *not*
@@ -664,7 +680,7 @@
 
   # Dump fingerprints
   script.Print("Target: %s" % CalculateFingerprint(
-      oem_props, oem_dict, OPTIONS.info_dict))
+      oem_props, oem_dicts and oem_dicts[0], OPTIONS.info_dict))
 
   device_specific.FullOTA_InstallBegin()
 
@@ -839,17 +855,13 @@
   oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
   recovery_mount_options = OPTIONS.source_info_dict.get(
       "recovery_mount_options")
-  oem_dict = None
-  if oem_props is not None and len(oem_props) > 0:
-    if OPTIONS.oem_source is None:
-      raise common.ExternalError("OEM source required for this build")
-    if not OPTIONS.oem_no_mount:
-      script.Mount("/oem", recovery_mount_options)
-    oem_dict = common.LoadDictionaryFromLines(
-        open(OPTIONS.oem_source).readlines())
+  oem_dicts = None
+  if oem_props:
+    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
 
   metadata = {
-      "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
+      "pre-device": GetOemProperty("ro.product.device", oem_props,
+                                   oem_dicts and oem_dicts[0],
                                    OPTIONS.source_info_dict),
       "ota-type": "BLOCK",
   }
@@ -885,9 +897,9 @@
       metadata=metadata,
       info_dict=OPTIONS.source_info_dict)
 
-  source_fp = CalculateFingerprint(oem_props, oem_dict,
+  source_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
                                    OPTIONS.source_info_dict)
-  target_fp = CalculateFingerprint(oem_props, oem_dict,
+  target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
                                    OPTIONS.target_info_dict)
   metadata["pre-build"] = source_fp
   metadata["post-build"] = target_fp
@@ -952,7 +964,7 @@
   else:
     vendor_diff = None
 
-  AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
+  AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
   device_specific.IncrementalOTA_Assertions()
 
   # Two-step incremental package strategy (in chronological order,
@@ -1004,9 +1016,9 @@
 
   # Dump fingerprints
   script.Print("Source: %s" % CalculateFingerprint(
-      oem_props, oem_dict, OPTIONS.source_info_dict))
+      oem_props, oem_dicts and oem_dicts[0], OPTIONS.source_info_dict))
   script.Print("Target: %s" % CalculateFingerprint(
-      oem_props, oem_dict, OPTIONS.target_info_dict))
+      oem_props, oem_dicts and oem_dicts[0], OPTIONS.target_info_dict))
 
   script.Print("Verifying current system...")
 
@@ -1155,18 +1167,16 @@
   oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
   recovery_mount_options = OPTIONS.info_dict.get(
       "recovery_mount_options")
-  oem_dict = None
-  if oem_props is not None and len(oem_props) > 0:
-    if OPTIONS.oem_source is None:
-      raise common.ExternalError("OEM source required for this build")
-    script.Mount("/oem", recovery_mount_options)
-    oem_dict = common.LoadDictionaryFromLines(
-        open(OPTIONS.oem_source).readlines())
+  oem_dicts = None
+  if oem_props:
+    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
 
-  target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.info_dict)
+  target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
+                                   OPTIONS.info_dict)
   metadata = {
       "post-build": target_fp,
-      "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
+      "pre-device": GetOemProperty("ro.product.device", oem_props,
+                                   oem_dicts and oem_dicts[0],
                                    OPTIONS.info_dict),
       "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
   }
@@ -1180,7 +1190,7 @@
       metadata=metadata,
       info_dict=OPTIONS.info_dict)
 
-  AppendAssertions(script, OPTIONS.info_dict, oem_dict)
+  AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
 
   script.Print("Verifying device images against %s..." % target_fp)
   script.AppendExtra("")
@@ -1252,19 +1262,17 @@
 
   # Metadata to comply with Android OTA package format.
   oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
-  oem_dict = None
+  oem_dicts = None
   if oem_props:
-    if OPTIONS.oem_source is None:
-      raise common.ExternalError("OEM source required for this build")
-    oem_dict = common.LoadDictionaryFromLines(
-        open(OPTIONS.oem_source).readlines())
+    oem_dicts = _LoadOemDicts(script, None)
 
   metadata = {
-      "post-build": CalculateFingerprint(oem_props, oem_dict,
+      "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
                                          OPTIONS.info_dict),
       "post-build-incremental" : GetBuildProp("ro.build.version.incremental",
                                               OPTIONS.info_dict),
-      "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
+      "pre-device": GetOemProperty("ro.product.device", oem_props,
+                                   oem_dicts and oem_dicts[0],
                                    OPTIONS.info_dict),
       "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
       "ota-required-cache": "0",
@@ -1272,7 +1280,8 @@
   }
 
   if source_file is not None:
-    metadata["pre-build"] = CalculateFingerprint(oem_props, oem_dict,
+    metadata["pre-build"] = CalculateFingerprint(oem_props,
+                                                 oem_dicts and oem_dicts[0],
                                                  OPTIONS.source_info_dict)
     metadata["pre-build-incremental"] = GetBuildProp(
         "ro.build.version.incremental", OPTIONS.source_info_dict)
@@ -1540,17 +1549,13 @@
   oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
   recovery_mount_options = OPTIONS.source_info_dict.get(
       "recovery_mount_options")
-  oem_dict = None
-  if oem_props is not None and len(oem_props) > 0:
-    if OPTIONS.oem_source is None:
-      raise common.ExternalError("OEM source required for this build")
-    if not OPTIONS.oem_no_mount:
-      script.Mount("/oem", recovery_mount_options)
-    oem_dict = common.LoadDictionaryFromLines(
-        open(OPTIONS.oem_source).readlines())
+  oem_dicts = None
+  if oem_props:
+    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
 
   metadata = {
-      "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
+      "pre-device": GetOemProperty("ro.product.device", oem_props,
+                                   oem_dicts and oem_dicts[0],
                                    OPTIONS.source_info_dict),
       "ota-type": "FILE",
   }
@@ -1594,9 +1599,9 @@
   else:
     vendor_diff = None
 
-  target_fp = CalculateFingerprint(oem_props, oem_dict,
+  target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
                                    OPTIONS.target_info_dict)
-  source_fp = CalculateFingerprint(oem_props, oem_dict,
+  source_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
                                    OPTIONS.source_info_dict)
 
   if oem_props is None:
@@ -1634,7 +1639,7 @@
   #  0.1 for unpacking verbatim files, symlinking, and doing the
   #      device-specific commands.
 
-  AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
+  AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
   device_specific.IncrementalOTA_Assertions()
 
   # Two-step incremental package strategy (in chronological order,
@@ -1972,7 +1977,7 @@
       OPTIONS.downgrade = True
       OPTIONS.wipe_user_data = True
     elif o in ("-o", "--oem_settings"):
-      OPTIONS.oem_source = a
+      OPTIONS.oem_source = a.split(',')
     elif o == "--oem_no_mount":
       OPTIONS.oem_no_mount = True
     elif o in ("-e", "--extra_script"):