Lazy unmount postinstall if it fails to unmount.

If postinstall forks a new child that's not killed when killing the main
postinstall process or if postinstall makes any other running process to
hold a file descriptor open in the mounted filesystem, the filesystem is
busy an we can't unmount /postinstall. Since the postinstall mountpoint is
fix in Android, we need to force a lazy unmount in order for the process
to succeed in a future run.

This case can only occur when canceling an update during postinstall (for
example if the update was retried from the server) and would otherwise
clear itself after a few unmount retries if the process using the fd
stops using it.

Bug: 31021934
Test: Added native tests to excersice this case.

(cherry picked from commit 5ba93ad42fad1efc40ae2e7abcda9c8793363508)

Change-Id: I3464377b43e2ee79cd7318dbc9d3a62706c6ea6c
diff --git a/common/utils.cc b/common/utils.cc
index 166cfb4..1338268 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -705,14 +705,24 @@
 }
 
 bool UnmountFilesystem(const string& mountpoint) {
-  for (int num_retries = 0; ; ++num_retries) {
+  int num_retries = 1;
+  for (;; ++num_retries) {
     if (umount(mountpoint.c_str()) == 0)
+      return true;
+    if (errno != EBUSY || num_retries >= kUnmountMaxNumOfRetries)
       break;
-
-    TEST_AND_RETURN_FALSE_ERRNO(errno == EBUSY &&
-                                num_retries < kUnmountMaxNumOfRetries);
     usleep(kUnmountRetryIntervalInMicroseconds);
   }
+  if (errno == EINVAL) {
+    LOG(INFO) << "Not a mountpoint: " << mountpoint;
+    return false;
+  }
+  PLOG(WARNING) << "Error unmounting " << mountpoint << " after " << num_retries
+                << " attempts. Lazy unmounting instead, error was";
+  if (umount2(mountpoint.c_str(), MNT_DETACH) != 0) {
+    PLOG(ERROR) << "Lazy unmount failed";
+    return false;
+  }
   return true;
 }