Run fsck to resolve possible data corruption

Trigger fsck on mount of /data if the value of ro.preventative_fsck is
not equal to the contents of /metadata/vold/preventative_fsck, then set
the file to the property to prevent future runs

See b/305658663 for context

Bug: 305658663
Test: Make sure fsck run after first boot and not after second
Ignore-AOSP-First: Critical UDC only bug
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6c625e5d2e33bdaed7b9933b237502968c4b16e1)
Merged-In: I856c812d22363cc1d1e8aa88706d4d3b89044f52
Change-Id: I856c812d22363cc1d1e8aa88706d4d3b89044f52
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 742cdfa..8b9bce1 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -700,6 +700,29 @@
 }
 
 //
+// Mechanism to allow fsck to be triggered by setting ro.preventative_fsck
+// Introduced to address b/305658663
+// If the property value is not equal to the flag file contents, trigger
+// fsck and store the property value in the flag file
+// If we want to trigger again, simply change the property value
+//
+static bool check_if_preventative_fsck_needed(const FstabEntry& entry) {
+    const char* flag_file = "/metadata/vold/preventative_fsck";
+    if (entry.mount_point != "/data") return false;
+
+    // Don't error check - both default to empty string, which is OK
+    std::string prop = android::base::GetProperty("ro.preventative_fsck", "");
+    std::string flag;
+    android::base::ReadFileToString(flag_file, &flag);
+    if (prop == flag) return false;
+    // fsck is run immediately, so assume it runs or there is some deeper problem
+    if (!android::base::WriteStringToFile(prop, flag_file))
+        PERROR << "Failed to write file " << flag_file;
+    LINFO << "Run preventative fsck on /data";
+    return true;
+}
+
+//
 // Prepare the filesystem on the given block device to be mounted.
 //
 // If the "check" option was given in the fstab record, or it seems that the
@@ -749,7 +772,7 @@
         }
     }
 
-    if (entry.fs_mgr_flags.check ||
+    if (check_if_preventative_fsck_needed(entry) || entry.fs_mgr_flags.check ||
         (fs_stat & (FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED))) {
         check_fs(blk_device, entry.fs_type, mount_point, &fs_stat);
     }