Generates the care_map with fingerprint

Reads the fingerprint of a partition from the build props and embeds it
into the care_map. Later, the update_verifier will compare the
fingerprint before it performs the verification.

Bug: 114778109
Test: generate care_map for sailfish and new pixel
Change-Id: I06afa01bf6dd3de4456a08ee7960954facc775fb
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index b566e1d..a0f7459 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -72,9 +72,6 @@
 OPTIONS.replace_verity_private_key = False
 OPTIONS.is_signing = False
 
-# Partitions that should have their care_map added to META/care_map.pb
-PARTITIONS_WITH_CARE_MAP = ('system', 'vendor', 'product', 'product_services',
-                            'odm')
 # Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
 # images. (b/24377993, b/80600931)
 FIXED_FILE_TIMESTAMP = int((
@@ -111,7 +108,7 @@
     (which, care_map_ranges): care_map_ranges is the raw string of the care_map
     RangeSet.
   """
-  assert which in PARTITIONS_WITH_CARE_MAP
+  assert which in common.PARTITIONS_WITH_CARE_MAP
 
   simg = sparse_img.SparseImage(imgname)
   care_map_ranges = simg.care_map
@@ -557,7 +554,7 @@
 
 
 def AddCareMapForAbOta(output_zip, ab_partitions, image_paths):
-  """Generates and adds care_map.pb for system and vendor partitions.
+  """Generates and adds care_map.pb for a/b partition that has care_map.
 
   Args:
     output_zip: The output zip file (needs to be already open), or None to
@@ -568,7 +565,7 @@
   care_map_list = []
   for partition in ab_partitions:
     partition = partition.strip()
-    if partition not in PARTITIONS_WITH_CARE_MAP:
+    if partition not in common.PARTITIONS_WITH_CARE_MAP:
       continue
 
     verity_block_device = "{}_verity_block_device".format(partition)
@@ -579,6 +576,21 @@
       assert os.path.exists(image_path)
       care_map_list += GetCareMap(partition, image_path)
 
+      # adds fingerprint field to the care_map
+      build_props = OPTIONS.info_dict.get(partition + ".build.prop", {})
+      prop_name_list = ["ro.{}.build.fingerprint".format(partition),
+                        "ro.{}.build.thumbprint".format(partition)]
+
+      present_props = [x for x in prop_name_list if x in build_props]
+      if not present_props:
+        print("Warning: fingerprint is not present for partition {}".
+              format(partition))
+        property_id, fingerprint = "unknown", "unknown"
+      else:
+        property_id = present_props[0]
+        fingerprint = build_props[property_id]
+      care_map_list += [property_id, fingerprint]
+
   if not care_map_list:
     return
 
@@ -589,14 +601,14 @@
   with open(temp_care_map_text, 'w') as text_file:
     text_file.write('\n'.join(care_map_list))
 
-  temp_care_map = common.MakeTempFile(prefix="caremap-", suffix=".txt")
-  care_map_gen_cmd = (["care_map_generator", temp_care_map_text, temp_care_map])
+  temp_care_map = common.MakeTempFile(prefix="caremap-", suffix=".pb")
+  care_map_gen_cmd = ["care_map_generator", temp_care_map_text, temp_care_map]
   p = common.Run(care_map_gen_cmd, stdout=subprocess.PIPE,
                  stderr=subprocess.STDOUT)
   output, _ = p.communicate()
-  assert p.returncode == 0, "Failed to generate the care_map.pb message."
   if OPTIONS.verbose:
     print(output.rstrip())
+  assert p.returncode == 0, "Failed to generate the care_map proto message."
 
   care_map_path = "META/care_map.pb"
   if output_zip and care_map_path not in output_zip.namelist():
@@ -863,8 +875,8 @@
     # ready under IMAGES/ or RADIO/.
     CheckAbOtaImages(output_zip, ab_partitions)
 
-    # Generate care_map.pb for system and vendor partitions (if present),
-    # then write this file to target_files package.
+    # Generate care_map.pb for ab_partitions, then write this file to
+    # target_files package.
     AddCareMapForAbOta(output_zip, ab_partitions, partitions)
 
   # Radio images that need to be packed into IMAGES/, and product-img.zip.
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index ee2c6f4..23dadf1 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -82,6 +82,11 @@
                   'product_services', 'dtbo', 'odm')
 
 
+# Partitions that should have their care_map added to META/care_map.pb
+PARTITIONS_WITH_CARE_MAP = ('system', 'vendor', 'product', 'product_services',
+                            'odm')
+
+
 class ErrorCode(object):
   """Define error_codes for failures that happen during the actual
   update package installation.
@@ -290,8 +295,12 @@
   else:
     d["fstab"] = None
 
-  d["build.prop"] = LoadBuildProp(read_helper, 'SYSTEM/build.prop')
-  d["vendor.build.prop"] = LoadBuildProp(read_helper, 'VENDOR/build.prop')
+  # Tries to load the build props for all partitions with care_map, including
+  # system and vendor.
+  for partition in PARTITIONS_WITH_CARE_MAP:
+    d["{}.build.prop".format(partition)] = LoadBuildProp(
+        read_helper, "{}/build.prop".format(partition.upper()))
+  d["build.prop"] = d["system.build.prop"]
 
   # Set up the salt (based on fingerprint or thumbprint) that will be used when
   # adding AVB footer.
diff --git a/tools/releasetools/test_add_img_to_target_files.py b/tools/releasetools/test_add_img_to_target_files.py
index c60b496..82e4683 100644
--- a/tools/releasetools/test_add_img_to_target_files.py
+++ b/tools/releasetools/test_add_img_to_target_files.py
@@ -46,7 +46,7 @@
     # Calls an external binary to convert the proto message.
     cmd = ["care_map_generator", "--parse_proto", file_name, text_file]
     p = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    output, _ = p.communicate()
+    p.communicate()
     self.assertEqual(0, p.returncode)
 
     with open(text_file, 'r') as verify_fp:
@@ -142,8 +142,15 @@
   def _test_AddCareMapForAbOta():
     """Helper function to set up the test for test_AddCareMapForAbOta()."""
     OPTIONS.info_dict = {
-        'system_verity_block_device' : '/dev/block/system',
-        'vendor_verity_block_device' : '/dev/block/vendor',
+        'system_verity_block_device': '/dev/block/system',
+        'vendor_verity_block_device': '/dev/block/vendor',
+        'system.build.prop': {
+            'ro.system.build.fingerprint':
+                'google/sailfish/12345:user/dev-keys',
+        },
+        'vendor.build.prop': {
+            'ro.vendor.build.fingerprint': 'google/sailfish/678:user/dev-keys',
+        }
     }
 
     # Prepare the META/ folder.
@@ -170,8 +177,12 @@
     AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
 
     care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
-    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), 'vendor',
-                RangeSet("0-9").to_string_raw()]
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.fingerprint",
+                "google/sailfish/12345:user/dev-keys",
+                'vendor', RangeSet("0-9").to_string_raw(),
+                "ro.vendor.build.fingerprint",
+                "google/sailfish/678:user/dev-keys"]
 
     self._verifyCareMap(expected, care_map_file)
 
@@ -183,8 +194,12 @@
         None, ['boot', 'system', 'vendor', 'vbmeta'], image_paths)
 
     care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
-    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), 'vendor',
-                RangeSet("0-9").to_string_raw()]
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.fingerprint",
+                "google/sailfish/12345:user/dev-keys",
+                'vendor', RangeSet("0-9").to_string_raw(),
+                "ro.vendor.build.fingerprint",
+                "google/sailfish/678:user/dev-keys"]
 
     self._verifyCareMap(expected, care_map_file)
 
@@ -194,13 +209,67 @@
     OPTIONS.info_dict = {
         'avb_system_hashtree_enable' : 'true',
         'avb_vendor_hashtree_enable' : 'true',
+        'system.build.prop': {
+            'ro.system.build.fingerprint':
+                'google/sailfish/12345:user/dev-keys',
+        },
+        'vendor.build.prop': {
+            'ro.vendor.build.fingerprint': 'google/sailfish/678:user/dev-keys',
+        }
     }
 
     AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
 
     care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
-    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), 'vendor',
-                RangeSet("0-9").to_string_raw()]
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.fingerprint",
+                "google/sailfish/12345:user/dev-keys",
+                'vendor', RangeSet("0-9").to_string_raw(),
+                "ro.vendor.build.fingerprint",
+                "google/sailfish/678:user/dev-keys"]
+
+    self._verifyCareMap(expected, care_map_file)
+
+  def test_AddCareMapForAbOta_noFingerprint(self):
+    """Tests the case for partitions without fingerprint."""
+    image_paths = self._test_AddCareMapForAbOta()
+    OPTIONS.info_dict = {
+        'system_verity_block_device': '/dev/block/system',
+        'vendor_verity_block_device': '/dev/block/vendor',
+    }
+
+    AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
+
+    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), "unknown",
+                "unknown", 'vendor', RangeSet("0-9").to_string_raw(), "unknown",
+                "unknown"]
+
+    self._verifyCareMap(expected, care_map_file)
+
+  def test_AddCareMapForAbOta_withThumbprint(self):
+    """Tests the case for partitions with thumbprint."""
+    image_paths = self._test_AddCareMapForAbOta()
+    OPTIONS.info_dict = {
+        'system_verity_block_device': '/dev/block/system',
+        'vendor_verity_block_device': '/dev/block/vendor',
+        'system.build.prop': {
+            'ro.system.build.thumbprint': 'google/sailfish/123:user/dev-keys',
+        },
+        'vendor.build.prop' : {
+            'ro.vendor.build.thumbprint': 'google/sailfish/456:user/dev-keys',
+        }
+    }
+
+    AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
+
+    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.thumbprint",
+                "google/sailfish/123:user/dev-keys",
+                'vendor', RangeSet("0-9").to_string_raw(),
+                "ro.vendor.build.thumbprint",
+                "google/sailfish/456:user/dev-keys"]
 
     self._verifyCareMap(expected, care_map_file)
 
@@ -234,8 +303,12 @@
       self.assertTrue(care_map_name in verify_zip.namelist())
       verify_zip.extract(care_map_name, path=temp_dir)
 
-    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), 'vendor',
-                RangeSet("0-9").to_string_raw()]
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.fingerprint",
+                "google/sailfish/12345:user/dev-keys",
+                'vendor', RangeSet("0-9").to_string_raw(),
+                "ro.vendor.build.fingerprint",
+                "google/sailfish/678:user/dev-keys"]
     self._verifyCareMap(expected, os.path.join(temp_dir, care_map_name))
 
   def test_AddCareMapForAbOta_zipOutput_careMapEntryExists(self):
@@ -253,8 +326,12 @@
 
     # The one under OPTIONS.input_tmp must have been replaced.
     care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
-    expected = ['system', RangeSet("0-5 10-15").to_string_raw(), 'vendor',
-                RangeSet("0-9").to_string_raw()]
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.fingerprint",
+                "google/sailfish/12345:user/dev-keys",
+                'vendor', RangeSet("0-9").to_string_raw(),
+                "ro.vendor.build.fingerprint",
+                "google/sailfish/678:user/dev-keys"]
 
     self._verifyCareMap(expected, care_map_file)