Merge "liblog: simplify fake_log_device"
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 2dc47bb..7b686f0 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -91,6 +91,7 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
 using android::base::Basename;
+using android::base::GetBoolProperty;
 using android::base::Realpath;
 using android::base::StartsWith;
 using android::base::unique_fd;
@@ -1357,14 +1358,33 @@
     return ret;
 }
 
+static std::string GetBlockDeviceForMountPoint(const std::string& mount_point) {
+    Fstab mounts;
+    if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
+        LERROR << "Can't read /proc/mounts";
+        return "";
+    }
+    auto entry = GetEntryForMountPoint(&mounts, mount_point);
+    if (entry == nullptr) {
+        LWARNING << mount_point << " is not mounted";
+        return "";
+    }
+    return entry->blk_device;
+}
+
 // TODO(b/143970043): return different error codes based on which step failed.
 int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
-    auto entry = GetMountedEntryForUserdata(fstab);
-    if (entry == nullptr) {
+    std::string block_device = GetBlockDeviceForMountPoint("/data");
+    if (block_device.empty()) {
+        LERROR << "/data is not mounted";
+        return -1;
+    }
+    auto fstab_entry = GetMountedEntryForUserdata(fstab);
+    if (fstab_entry == nullptr) {
         LERROR << "Can't find /data in fstab";
         return -1;
     }
-    if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
+    if (!fstab_entry->fs_mgr_flags.checkpoint_blk && !fstab_entry->fs_mgr_flags.checkpoint_fs) {
         LINFO << "Userdata doesn't support checkpointing. Nothing to do";
         return 0;
     }
@@ -1373,34 +1393,43 @@
         LINFO << "Checkpointing not needed. Don't remount";
         return 0;
     }
-    if (entry->fs_mgr_flags.checkpoint_fs) {
+    bool force_umount_for_f2fs =
+            GetBoolProperty("sys.init.userdata_remount.force_umount_f2fs", false);
+    if (fstab_entry->fs_mgr_flags.checkpoint_fs && !force_umount_for_f2fs) {
         // Userdata is f2fs, simply remount it.
-        if (!checkpoint_manager.Update(&(*entry))) {
+        if (!checkpoint_manager.Update(fstab_entry)) {
             LERROR << "Failed to remount userdata in checkpointing mode";
             return -1;
         }
-        if (mount(entry->blk_device.c_str(), entry->mount_point.c_str(), "none",
-                  MS_REMOUNT | entry->flags, entry->fs_options.c_str()) != 0) {
+        if (mount(block_device.c_str(), fstab_entry->mount_point.c_str(), "none",
+                  MS_REMOUNT | fstab_entry->flags, fstab_entry->fs_options.c_str()) != 0) {
             PERROR << "Failed to remount userdata in checkpointing mode";
             return -1;
         }
     } else {
-        // STOPSHIP(b/143970043): support remounting for ext4 + metadata encryption.
-        if (should_use_metadata_encryption(*entry)) {
-            LWARNING << "Remounting into checkpointing is not supported for metadata encrypted "
-                     << "ext4 userdata. Proceed with caution";
-            return 0;
-        }
+        LINFO << "Unmounting /data before remounting into checkpointing mode";
         if (umount2("/data", UMOUNT_NOFOLLOW) != 0) {
             PERROR << "Failed to umount /data";
             return -1;
         }
         DeviceMapper& dm = DeviceMapper::Instance();
-        // TODO(b/143970043): need to delete every dm-device under the one userdata is mounted on.
-        if (!dm.DeleteDeviceIfExists("bow")) {
-            LERROR << "Failed to delete dm-bow";
-            return -1;
+        while (dm.IsDmBlockDevice(block_device)) {
+            auto next_device = dm.GetParentBlockDeviceByPath(block_device);
+            auto name = dm.GetDmDeviceNameByPath(block_device);
+            if (!name) {
+                LERROR << "Failed to get dm-name for " << block_device;
+                return -1;
+            }
+            LINFO << "Deleting " << block_device << " named " << *name;
+            if (!dm.DeleteDevice(*name, 3s)) {
+                return -1;
+            }
+            if (!next_device) {
+                LERROR << "Failed to find parent device for " << block_device;
+            }
+            block_device = *next_device;
         }
+        LINFO << "Remounting /data";
         // TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
         int result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
         return result == FS_MGR_MNTALL_FAIL ? -1 : 0;
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 3acc3cc..22de846 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -191,7 +191,7 @@
     }
 
     auto errors = std::vector<std::string>{};
-    ParsePropertyInfoFile(file_contents, property_infos, &errors);
+    ParsePropertyInfoFile(file_contents, true, property_infos, &errors);
     for (const auto& error : errors) {
         LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
     }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index adf8929..5b35ad2 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -925,7 +925,8 @@
     }
 
     auto errors = std::vector<std::string>{};
-    ParsePropertyInfoFile(file_contents, property_infos, &errors);
+    bool require_prefix_or_exact = SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__;
+    ParsePropertyInfoFile(file_contents, require_prefix_or_exact, property_infos, &errors);
     // Individual parsing errors are reported but do not cause a failed boot, which is what
     // returning false would do here.
     for (const auto& error : errors) {
diff --git a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
index 439813d..dfb1d11 100644
--- a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
+++ b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
@@ -14,8 +14,7 @@
 // limitations under the License.
 //
 
-#ifndef PROPERTY_INFO_SERIALIZER_H
-#define PROPERTY_INFO_SERIALIZER_H
+#pragma once
 
 #include <string>
 #include <vector>
@@ -41,11 +40,9 @@
                const std::string& default_context, const std::string& default_type,
                std::string* serialized_trie, std::string* error);
 
-void ParsePropertyInfoFile(const std::string& file_contents,
+void ParsePropertyInfoFile(const std::string& file_contents, bool require_prefix_or_exact,
                            std::vector<PropertyInfoEntry>* property_infos,
                            std::vector<std::string>* errors);
 
 }  // namespace properties
 }  // namespace android
-
-#endif
diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp
index 2cdc62d..771a9ce 100644
--- a/property_service/libpropertyinfoserializer/property_info_file.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_file.cpp
@@ -56,7 +56,8 @@
   return false;
 }
 
-bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
+bool ParsePropertyInfoLine(const std::string& line, bool require_prefix_or_exact,
+                           PropertyInfoEntry* out, std::string* error) {
   auto tokenizer = SpaceTokenizer(line);
 
   auto property = tokenizer.GetNext();
@@ -72,7 +73,7 @@
   }
 
   // It is not an error to not find exact_match or a type, as older files will not contain them.
-  auto exact_match = tokenizer.GetNext();
+  auto match_operation = tokenizer.GetNext();
   // We reformat type to be space deliminated regardless of the input whitespace for easier storage
   // and subsequent parsing.
   auto type_strings = std::vector<std::string>{};
@@ -82,18 +83,27 @@
     type = tokenizer.GetNext();
   }
 
+  bool exact_match = false;
+  if (match_operation == "exact") {
+    exact_match = true;
+  } else if (match_operation != "prefix" && match_operation != "" && require_prefix_or_exact) {
+    *error = "Match operation '" + match_operation +
+             "' is not valid: must be either 'prefix' or 'exact'";
+    return false;
+  }
+
   if (!type_strings.empty() && !IsTypeValid(type_strings)) {
     *error = "Type '" + Join(type_strings, " ") + "' is not valid";
     return false;
   }
 
-  *out = {property, context, Join(type_strings, " "), exact_match == "exact"};
+  *out = {property, context, Join(type_strings, " "), exact_match};
   return true;
 }
 
 }  // namespace
 
-void ParsePropertyInfoFile(const std::string& file_contents,
+void ParsePropertyInfoFile(const std::string& file_contents, bool require_prefix_or_exact,
                            std::vector<PropertyInfoEntry>* property_infos,
                            std::vector<std::string>* errors) {
   // Do not clear property_infos to allow this function to be called on multiple files, with
@@ -108,7 +118,8 @@
 
     auto property_info_entry = PropertyInfoEntry{};
     auto parse_error = std::string{};
-    if (!ParsePropertyInfoLine(trimmed_line, &property_info_entry, &parse_error)) {
+    if (!ParsePropertyInfoLine(trimmed_line, require_prefix_or_exact, &property_info_entry,
+                               &parse_error)) {
       errors->emplace_back(parse_error);
       continue;
     }
diff --git a/property_service/property_info_checker/property_info_checker.cpp b/property_service/property_info_checker/property_info_checker.cpp
index 52c4383..61b368e 100644
--- a/property_service/property_info_checker/property_info_checker.cpp
+++ b/property_service/property_info_checker/property_info_checker.cpp
@@ -153,7 +153,7 @@
     }
 
     auto errors = std::vector<std::string>{};
-    ParsePropertyInfoFile(file_contents, &property_info_entries, &errors);
+    ParsePropertyInfoFile(file_contents, true, &property_info_entries, &errors);
     if (!errors.empty()) {
       for (const auto& error : errors) {
         std::cerr << "Could not read line from '" << filename << "': " << error << std::endl;