Wait for dm device to be ready before format

It can sometimes take a moment for the dm-device to appear after
creation, causing operations on it such as formatting to fail.
Ensure the device exists before create_crypto_blk_dev returns.

Test: adb sm set-virtual-disk true and format as adoptable.
Bug: 117586466
Change-Id: Id8f571b551f50fc759e78d917e4ac3080e926722
Merged-In: Id8f571b551f50fc759e78d917e4ac3080e926722
diff --git a/Utils.cpp b/Utils.cpp
index cdca85e..04c3956 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -19,6 +19,7 @@
 #include "Process.h"
 #include "sehandle.h"
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -40,13 +41,16 @@
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+
 #include <list>
 #include <mutex>
+#include <thread>
 
 #ifndef UMOUNT_NOFOLLOW
 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
 #endif
 
+using namespace std::chrono_literals;
 using android::base::ReadFileToString;
 using android::base::StringPrintf;
 
@@ -788,5 +792,20 @@
     return OK;
 }
 
+// TODO(118708649): fix duplication with init/util.h
+status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout) {
+    android::base::Timer t;
+    while (t.duration() < timeout) {
+        struct stat sb;
+        if (stat(filename, &sb) != -1) {
+            LOG(INFO) << "wait for '" << filename << "' took " << t;
+            return 0;
+        }
+        std::this_thread::sleep_for(10ms);
+    }
+    LOG(WARNING) << "wait for '" << filename << "' timed out and took " << t;
+    return -1;
+}
+
 }  // namespace vold
 }  // namespace android
diff --git a/Utils.h b/Utils.h
index 48d605a..4d3522a 100644
--- a/Utils.h
+++ b/Utils.h
@@ -24,6 +24,7 @@
 #include <selinux/selinux.h>
 #include <utils/Errors.h>
 
+#include <chrono>
 #include <string>
 #include <vector>
 
@@ -132,6 +133,8 @@
 
 status_t UnmountTree(const std::string& prefix);
 
+status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout);
+
 }  // namespace vold
 }  // namespace android
 
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 6e449ac..5be29be 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -30,6 +30,7 @@
 #include "Keymaster.h"
 #include "Process.h"
 #include "ScryptParameters.h"
+#include "Utils.h"
 #include "VoldUtil.h"
 #include "VolumeManager.h"
 #include "secontext.h"
@@ -73,6 +74,8 @@
 #include <crypto_scrypt.h>
 }
 
+using namespace std::chrono_literals;
+
 #define UNUSED __attribute__((unused))
 
 #define DM_CRYPT_BUF_SIZE 4096
@@ -1099,6 +1102,12 @@
         goto errout;
     }
 
+    /* Ensure the dm device has been created before returning. */
+    if (android::vold::WaitForFile(crypto_blk_name, 1s) < 0) {
+        // WaitForFile generates a suitable log message
+        goto errout;
+    }
+
     /* We made it here with no errors.  Woot! */
     retval = 0;